LCOV - code coverage report
Current view: top level - metalib_isl - isl_transitive_closure.c (source / functions) Hit Total Coverage
Test: 2018-10-31_point_maint_greina16.lcov Lines: 0 1440 0.0 %
Date: 2018-11-01 11:27:00 Functions: 0 56 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2010      INRIA Saclay
       3             :  *
       4             :  * Use of this software is governed by the MIT license
       5             :  *
       6             :  * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
       7             :  * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
       8             :  * 91893 Orsay, France 
       9             :  */
      10             : 
      11             : #include <isl_ctx_private.h>
      12             : #include <isl_map_private.h>
      13             : #include <isl/map.h>
      14             : #include <isl_seq.h>
      15             : #include <isl_space_private.h>
      16             : #include <isl_lp_private.h>
      17             : #include <isl/union_map.h>
      18             : #include <isl_mat_private.h>
      19             : #include <isl_vec_private.h>
      20             : #include <isl_options_private.h>
      21             : #include <isl_tarjan.h>
      22             : 
      23           0 : int isl_map_is_transitively_closed(__isl_keep isl_map *map)
      24             : {
      25             :         isl_map *map2;
      26             :         int closed;
      27             : 
      28           0 :         map2 = isl_map_apply_range(isl_map_copy(map), isl_map_copy(map));
      29           0 :         closed = isl_map_is_subset(map2, map);
      30           0 :         isl_map_free(map2);
      31             : 
      32           0 :         return closed;
      33             : }
      34             : 
      35           0 : int isl_union_map_is_transitively_closed(__isl_keep isl_union_map *umap)
      36             : {
      37             :         isl_union_map *umap2;
      38             :         int closed;
      39             : 
      40           0 :         umap2 = isl_union_map_apply_range(isl_union_map_copy(umap),
      41             :                                           isl_union_map_copy(umap));
      42           0 :         closed = isl_union_map_is_subset(umap2, umap);
      43           0 :         isl_union_map_free(umap2);
      44             : 
      45           0 :         return closed;
      46             : }
      47             :  
      48             : /* Given a map that represents a path with the length of the path
      49             :  * encoded as the difference between the last output coordindate
      50             :  * and the last input coordinate, set this length to either
      51             :  * exactly "length" (if "exactly" is set) or at least "length"
      52             :  * (if "exactly" is not set).
      53             :  */
      54           0 : static __isl_give isl_map *set_path_length(__isl_take isl_map *map,
      55             :         int exactly, int length)
      56             : {
      57             :         isl_space *dim;
      58             :         struct isl_basic_map *bmap;
      59             :         unsigned d;
      60             :         unsigned nparam;
      61             :         int k;
      62             :         isl_int *c;
      63             : 
      64           0 :         if (!map)
      65           0 :                 return NULL;
      66             : 
      67           0 :         dim = isl_map_get_space(map);
      68           0 :         d = isl_space_dim(dim, isl_dim_in);
      69           0 :         nparam = isl_space_dim(dim, isl_dim_param);
      70           0 :         bmap = isl_basic_map_alloc_space(dim, 0, 1, 1);
      71           0 :         if (exactly) {
      72           0 :                 k = isl_basic_map_alloc_equality(bmap);
      73           0 :                 if (k < 0)
      74           0 :                         goto error;
      75           0 :                 c = bmap->eq[k];
      76             :         } else {
      77           0 :                 k = isl_basic_map_alloc_inequality(bmap);
      78           0 :                 if (k < 0)
      79           0 :                         goto error;
      80           0 :                 c = bmap->ineq[k];
      81             :         }
      82           0 :         isl_seq_clr(c, 1 + isl_basic_map_total_dim(bmap));
      83           0 :         isl_int_set_si(c[0], -length);
      84           0 :         isl_int_set_si(c[1 + nparam + d - 1], -1);
      85           0 :         isl_int_set_si(c[1 + nparam + d + d - 1], 1);
      86             : 
      87           0 :         bmap = isl_basic_map_finalize(bmap);
      88           0 :         map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
      89             : 
      90           0 :         return map;
      91             : error:
      92           0 :         isl_basic_map_free(bmap);
      93           0 :         isl_map_free(map);
      94           0 :         return NULL;
      95             : }
      96             : 
      97             : /* Check whether the overapproximation of the power of "map" is exactly
      98             :  * the power of "map".  Let R be "map" and A_k the overapproximation.
      99             :  * The approximation is exact if
     100             :  *
     101             :  *      A_1 = R
     102             :  *      A_k = A_{k-1} \circ R                   k >= 2
     103             :  *
     104             :  * Since A_k is known to be an overapproximation, we only need to check
     105             :  *
     106             :  *      A_1 \subset R
     107             :  *      A_k \subset A_{k-1} \circ R             k >= 2
     108             :  *
     109             :  * In practice, "app" has an extra input and output coordinate
     110             :  * to encode the length of the path.  So, we first need to add
     111             :  * this coordinate to "map" and set the length of the path to
     112             :  * one.
     113             :  */
     114           0 : static int check_power_exactness(__isl_take isl_map *map,
     115             :         __isl_take isl_map *app)
     116             : {
     117             :         int exact;
     118             :         isl_map *app_1;
     119             :         isl_map *app_2;
     120             : 
     121           0 :         map = isl_map_add_dims(map, isl_dim_in, 1);
     122           0 :         map = isl_map_add_dims(map, isl_dim_out, 1);
     123           0 :         map = set_path_length(map, 1, 1);
     124             : 
     125           0 :         app_1 = set_path_length(isl_map_copy(app), 1, 1);
     126             : 
     127           0 :         exact = isl_map_is_subset(app_1, map);
     128           0 :         isl_map_free(app_1);
     129             : 
     130           0 :         if (!exact || exact < 0) {
     131           0 :                 isl_map_free(app);
     132           0 :                 isl_map_free(map);
     133           0 :                 return exact;
     134             :         }
     135             : 
     136           0 :         app_1 = set_path_length(isl_map_copy(app), 0, 1);
     137           0 :         app_2 = set_path_length(app, 0, 2);
     138           0 :         app_1 = isl_map_apply_range(map, app_1);
     139             : 
     140           0 :         exact = isl_map_is_subset(app_2, app_1);
     141             : 
     142           0 :         isl_map_free(app_1);
     143           0 :         isl_map_free(app_2);
     144             : 
     145           0 :         return exact;
     146             : }
     147             : 
     148             : /* Check whether the overapproximation of the power of "map" is exactly
     149             :  * the power of "map", possibly after projecting out the power (if "project"
     150             :  * is set).
     151             :  *
     152             :  * If "project" is set and if "steps" can only result in acyclic paths,
     153             :  * then we check
     154             :  *
     155             :  *      A = R \cup (A \circ R)
     156             :  *
     157             :  * where A is the overapproximation with the power projected out, i.e.,
     158             :  * an overapproximation of the transitive closure.
     159             :  * More specifically, since A is known to be an overapproximation, we check
     160             :  *
     161             :  *      A \subset R \cup (A \circ R)
     162             :  *
     163             :  * Otherwise, we check if the power is exact.
     164             :  *
     165             :  * Note that "app" has an extra input and output coordinate to encode
     166             :  * the length of the part.  If we are only interested in the transitive
     167             :  * closure, then we can simply project out these coordinates first.
     168             :  */
     169           0 : static int check_exactness(__isl_take isl_map *map, __isl_take isl_map *app,
     170             :         int project)
     171             : {
     172             :         isl_map *test;
     173             :         int exact;
     174             :         unsigned d;
     175             : 
     176           0 :         if (!project)
     177           0 :                 return check_power_exactness(map, app);
     178             : 
     179           0 :         d = isl_map_dim(map, isl_dim_in);
     180           0 :         app = set_path_length(app, 0, 1);
     181           0 :         app = isl_map_project_out(app, isl_dim_in, d, 1);
     182           0 :         app = isl_map_project_out(app, isl_dim_out, d, 1);
     183             : 
     184           0 :         app = isl_map_reset_space(app, isl_map_get_space(map));
     185             : 
     186           0 :         test = isl_map_apply_range(isl_map_copy(map), isl_map_copy(app));
     187           0 :         test = isl_map_union(test, isl_map_copy(map));
     188             : 
     189           0 :         exact = isl_map_is_subset(app, test);
     190             : 
     191           0 :         isl_map_free(app);
     192           0 :         isl_map_free(test);
     193             : 
     194           0 :         isl_map_free(map);
     195             : 
     196           0 :         return exact;
     197             : }
     198             : 
     199             : /*
     200             :  * The transitive closure implementation is based on the paper
     201             :  * "Computing the Transitive Closure of a Union of Affine Integer
     202             :  * Tuple Relations" by Anna Beletska, Denis Barthou, Wlodzimierz Bielecki and
     203             :  * Albert Cohen.
     204             :  */
     205             : 
     206             : /* Given a set of n offsets v_i (the rows of "steps"), construct a relation
     207             :  * of the given dimension specification (Z^{n+1} -> Z^{n+1})
     208             :  * that maps an element x to any element that can be reached
     209             :  * by taking a non-negative number of steps along any of
     210             :  * the extended offsets v'_i = [v_i 1].
     211             :  * That is, construct
     212             :  *
     213             :  * { [x] -> [y] : exists k_i >= 0, y = x + \sum_i k_i v'_i }
     214             :  *
     215             :  * For any element in this relation, the number of steps taken
     216             :  * is equal to the difference in the final coordinates.
     217             :  */
     218           0 : static __isl_give isl_map *path_along_steps(__isl_take isl_space *dim,
     219             :         __isl_keep isl_mat *steps)
     220             : {
     221             :         int i, j, k;
     222           0 :         struct isl_basic_map *path = NULL;
     223             :         unsigned d;
     224             :         unsigned n;
     225             :         unsigned nparam;
     226             : 
     227           0 :         if (!dim || !steps)
     228             :                 goto error;
     229             : 
     230           0 :         d = isl_space_dim(dim, isl_dim_in);
     231           0 :         n = steps->n_row;
     232           0 :         nparam = isl_space_dim(dim, isl_dim_param);
     233             : 
     234           0 :         path = isl_basic_map_alloc_space(isl_space_copy(dim), n, d, n);
     235             : 
     236           0 :         for (i = 0; i < n; ++i) {
     237           0 :                 k = isl_basic_map_alloc_div(path);
     238           0 :                 if (k < 0)
     239           0 :                         goto error;
     240           0 :                 isl_assert(steps->ctx, i == k, goto error);
     241           0 :                 isl_int_set_si(path->div[k][0], 0);
     242             :         }
     243             : 
     244           0 :         for (i = 0; i < d; ++i) {
     245           0 :                 k = isl_basic_map_alloc_equality(path);
     246           0 :                 if (k < 0)
     247           0 :                         goto error;
     248           0 :                 isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path));
     249           0 :                 isl_int_set_si(path->eq[k][1 + nparam + i], 1);
     250           0 :                 isl_int_set_si(path->eq[k][1 + nparam + d + i], -1);
     251           0 :                 if (i == d - 1)
     252           0 :                         for (j = 0; j < n; ++j)
     253           0 :                                 isl_int_set_si(path->eq[k][1 + nparam + 2 * d + j], 1);
     254             :                 else
     255           0 :                         for (j = 0; j < n; ++j)
     256           0 :                                 isl_int_set(path->eq[k][1 + nparam + 2 * d + j],
     257             :                                             steps->row[j][i]);
     258             :         }
     259             : 
     260           0 :         for (i = 0; i < n; ++i) {
     261           0 :                 k = isl_basic_map_alloc_inequality(path);
     262           0 :                 if (k < 0)
     263           0 :                         goto error;
     264           0 :                 isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path));
     265           0 :                 isl_int_set_si(path->ineq[k][1 + nparam + 2 * d + i], 1);
     266             :         }
     267             : 
     268           0 :         isl_space_free(dim);
     269             : 
     270           0 :         path = isl_basic_map_simplify(path);
     271           0 :         path = isl_basic_map_finalize(path);
     272           0 :         return isl_map_from_basic_map(path);
     273             : error:
     274           0 :         isl_space_free(dim);
     275           0 :         isl_basic_map_free(path);
     276           0 :         return NULL;
     277             : }
     278             : 
     279             : #define IMPURE          0
     280             : #define PURE_PARAM      1
     281             : #define PURE_VAR        2
     282             : #define MIXED           3
     283             : 
     284             : /* Check whether the parametric constant term of constraint c is never
     285             :  * positive in "bset".
     286             :  */
     287           0 : static isl_bool parametric_constant_never_positive(
     288             :         __isl_keep isl_basic_set *bset, isl_int *c, int *div_purity)
     289             : {
     290             :         unsigned d;
     291             :         unsigned n_div;
     292             :         unsigned nparam;
     293             :         int i;
     294             :         int k;
     295             :         isl_bool empty;
     296             : 
     297           0 :         n_div = isl_basic_set_dim(bset, isl_dim_div);
     298           0 :         d = isl_basic_set_dim(bset, isl_dim_set);
     299           0 :         nparam = isl_basic_set_dim(bset, isl_dim_param);
     300             : 
     301           0 :         bset = isl_basic_set_copy(bset);
     302           0 :         bset = isl_basic_set_cow(bset);
     303           0 :         bset = isl_basic_set_extend_constraints(bset, 0, 1);
     304           0 :         k = isl_basic_set_alloc_inequality(bset);
     305           0 :         if (k < 0)
     306           0 :                 goto error;
     307           0 :         isl_seq_clr(bset->ineq[k], 1 + isl_basic_set_total_dim(bset));
     308           0 :         isl_seq_cpy(bset->ineq[k], c, 1 + nparam);
     309           0 :         for (i = 0; i < n_div; ++i) {
     310           0 :                 if (div_purity[i] != PURE_PARAM)
     311           0 :                         continue;
     312           0 :                 isl_int_set(bset->ineq[k][1 + nparam + d + i],
     313             :                             c[1 + nparam + d + i]);
     314             :         }
     315           0 :         isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1);
     316           0 :         empty = isl_basic_set_is_empty(bset);
     317           0 :         isl_basic_set_free(bset);
     318             : 
     319           0 :         return empty;
     320             : error:
     321           0 :         isl_basic_set_free(bset);
     322           0 :         return isl_bool_error;
     323             : }
     324             : 
     325             : /* Return PURE_PARAM if only the coefficients of the parameters are non-zero.
     326             :  * Return PURE_VAR if only the coefficients of the set variables are non-zero.
     327             :  * Return MIXED if only the coefficients of the parameters and the set
     328             :  *      variables are non-zero and if moreover the parametric constant
     329             :  *      can never attain positive values.
     330             :  * Return IMPURE otherwise.
     331             :  */
     332           0 : static int purity(__isl_keep isl_basic_set *bset, isl_int *c, int *div_purity,
     333             :         int eq)
     334             : {
     335             :         unsigned d;
     336             :         unsigned n_div;
     337             :         unsigned nparam;
     338             :         isl_bool empty;
     339             :         int i;
     340           0 :         int p = 0, v = 0;
     341             : 
     342           0 :         n_div = isl_basic_set_dim(bset, isl_dim_div);
     343           0 :         d = isl_basic_set_dim(bset, isl_dim_set);
     344           0 :         nparam = isl_basic_set_dim(bset, isl_dim_param);
     345             : 
     346           0 :         for (i = 0; i < n_div; ++i) {
     347           0 :                 if (isl_int_is_zero(c[1 + nparam + d + i]))
     348           0 :                         continue;
     349           0 :                 switch (div_purity[i]) {
     350           0 :                 case PURE_PARAM: p = 1; break;
     351           0 :                 case PURE_VAR: v = 1; break;
     352           0 :                 default: return IMPURE;
     353             :                 }
     354             :         }
     355           0 :         if (!p && isl_seq_first_non_zero(c + 1, nparam) == -1)
     356           0 :                 return PURE_VAR;
     357           0 :         if (!v && isl_seq_first_non_zero(c + 1 + nparam, d) == -1)
     358           0 :                 return PURE_PARAM;
     359             : 
     360           0 :         empty = parametric_constant_never_positive(bset, c, div_purity);
     361           0 :         if (eq && empty >= 0 && !empty) {
     362           0 :                 isl_seq_neg(c, c, 1 + nparam + d + n_div);
     363           0 :                 empty = parametric_constant_never_positive(bset, c, div_purity);
     364             :         }
     365             : 
     366           0 :         return empty < 0 ? -1 : empty ? MIXED : IMPURE;
     367             : }
     368             : 
     369             : /* Return an array of integers indicating the type of each div in bset.
     370             :  * If the div is (recursively) defined in terms of only the parameters,
     371             :  * then the type is PURE_PARAM.
     372             :  * If the div is (recursively) defined in terms of only the set variables,
     373             :  * then the type is PURE_VAR.
     374             :  * Otherwise, the type is IMPURE.
     375             :  */
     376           0 : static __isl_give int *get_div_purity(__isl_keep isl_basic_set *bset)
     377             : {
     378             :         int i, j;
     379             :         int *div_purity;
     380             :         unsigned d;
     381             :         unsigned n_div;
     382             :         unsigned nparam;
     383             : 
     384           0 :         if (!bset)
     385           0 :                 return NULL;
     386             : 
     387           0 :         n_div = isl_basic_set_dim(bset, isl_dim_div);
     388           0 :         d = isl_basic_set_dim(bset, isl_dim_set);
     389           0 :         nparam = isl_basic_set_dim(bset, isl_dim_param);
     390             : 
     391           0 :         div_purity = isl_alloc_array(bset->ctx, int, n_div);
     392           0 :         if (n_div && !div_purity)
     393           0 :                 return NULL;
     394             : 
     395           0 :         for (i = 0; i < bset->n_div; ++i) {
     396           0 :                 int p = 0, v = 0;
     397           0 :                 if (isl_int_is_zero(bset->div[i][0])) {
     398           0 :                         div_purity[i] = IMPURE;
     399           0 :                         continue;
     400             :                 }
     401           0 :                 if (isl_seq_first_non_zero(bset->div[i] + 2, nparam) != -1)
     402           0 :                         p = 1;
     403           0 :                 if (isl_seq_first_non_zero(bset->div[i] + 2 + nparam, d) != -1)
     404           0 :                         v = 1;
     405           0 :                 for (j = 0; j < i; ++j) {
     406           0 :                         if (isl_int_is_zero(bset->div[i][2 + nparam + d + j]))
     407           0 :                                 continue;
     408           0 :                         switch (div_purity[j]) {
     409           0 :                         case PURE_PARAM: p = 1; break;
     410           0 :                         case PURE_VAR: v = 1; break;
     411           0 :                         default: p = v = 1; break;
     412             :                         }
     413             :                 }
     414           0 :                 div_purity[i] = v ? p ? IMPURE : PURE_VAR : PURE_PARAM;
     415             :         }
     416             : 
     417           0 :         return div_purity;
     418             : }
     419             : 
     420             : /* Given a path with the as yet unconstrained length at position "pos",
     421             :  * check if setting the length to zero results in only the identity
     422             :  * mapping.
     423             :  */
     424           0 : static int empty_path_is_identity(__isl_keep isl_basic_map *path, unsigned pos)
     425             : {
     426           0 :         isl_basic_map *test = NULL;
     427           0 :         isl_basic_map *id = NULL;
     428             :         int k;
     429             :         int is_id;
     430             : 
     431           0 :         test = isl_basic_map_copy(path);
     432           0 :         test = isl_basic_map_extend_constraints(test, 1, 0);
     433           0 :         k = isl_basic_map_alloc_equality(test);
     434           0 :         if (k < 0)
     435           0 :                 goto error;
     436           0 :         isl_seq_clr(test->eq[k], 1 + isl_basic_map_total_dim(test));
     437           0 :         isl_int_set_si(test->eq[k][pos], 1);
     438           0 :         test = isl_basic_map_gauss(test, NULL);
     439           0 :         id = isl_basic_map_identity(isl_basic_map_get_space(path));
     440           0 :         is_id = isl_basic_map_is_equal(test, id);
     441           0 :         isl_basic_map_free(test);
     442           0 :         isl_basic_map_free(id);
     443           0 :         return is_id;
     444             : error:
     445           0 :         isl_basic_map_free(test);
     446           0 :         return -1;
     447             : }
     448             : 
     449             : /* If any of the constraints is found to be impure then this function
     450             :  * sets *impurity to 1.
     451             :  *
     452             :  * If impurity is NULL then we are dealing with a non-parametric set
     453             :  * and so the constraints are obviously PURE_VAR.
     454             :  */
     455           0 : static __isl_give isl_basic_map *add_delta_constraints(
     456             :         __isl_take isl_basic_map *path,
     457             :         __isl_keep isl_basic_set *delta, unsigned off, unsigned nparam,
     458             :         unsigned d, int *div_purity, int eq, int *impurity)
     459             : {
     460             :         int i, k;
     461           0 :         int n = eq ? delta->n_eq : delta->n_ineq;
     462           0 :         isl_int **delta_c = eq ? delta->eq : delta->ineq;
     463             :         unsigned n_div;
     464             : 
     465           0 :         n_div = isl_basic_set_dim(delta, isl_dim_div);
     466             : 
     467           0 :         for (i = 0; i < n; ++i) {
     468             :                 isl_int *path_c;
     469           0 :                 int p = PURE_VAR;
     470           0 :                 if (impurity)
     471           0 :                         p = purity(delta, delta_c[i], div_purity, eq);
     472           0 :                 if (p < 0)
     473           0 :                         goto error;
     474           0 :                 if (p != PURE_VAR && p != PURE_PARAM && !*impurity)
     475           0 :                         *impurity = 1;
     476           0 :                 if (p == IMPURE)
     477           0 :                         continue;
     478           0 :                 if (eq && p != MIXED) {
     479           0 :                         k = isl_basic_map_alloc_equality(path);
     480           0 :                         if (k < 0)
     481           0 :                                 goto error;
     482           0 :                         path_c = path->eq[k];
     483             :                 } else {
     484           0 :                         k = isl_basic_map_alloc_inequality(path);
     485           0 :                         if (k < 0)
     486           0 :                                 goto error;
     487           0 :                         path_c = path->ineq[k];
     488             :                 }
     489           0 :                 isl_seq_clr(path_c, 1 + isl_basic_map_total_dim(path));
     490           0 :                 if (p == PURE_VAR) {
     491           0 :                         isl_seq_cpy(path_c + off,
     492           0 :                                     delta_c[i] + 1 + nparam, d);
     493           0 :                         isl_int_set(path_c[off + d], delta_c[i][0]);
     494           0 :                 } else if (p == PURE_PARAM) {
     495           0 :                         isl_seq_cpy(path_c, delta_c[i], 1 + nparam);
     496             :                 } else {
     497           0 :                         isl_seq_cpy(path_c + off,
     498           0 :                                     delta_c[i] + 1 + nparam, d);
     499           0 :                         isl_seq_cpy(path_c, delta_c[i], 1 + nparam);
     500             :                 }
     501           0 :                 isl_seq_cpy(path_c + off - n_div,
     502           0 :                             delta_c[i] + 1 + nparam + d, n_div);
     503             :         }
     504             : 
     505           0 :         return path;
     506             : error:
     507           0 :         isl_basic_map_free(path);
     508           0 :         return NULL;
     509             : }
     510             : 
     511             : /* Given a set of offsets "delta", construct a relation of the
     512             :  * given dimension specification (Z^{n+1} -> Z^{n+1}) that
     513             :  * is an overapproximation of the relations that
     514             :  * maps an element x to any element that can be reached
     515             :  * by taking a non-negative number of steps along any of
     516             :  * the elements in "delta".
     517             :  * That is, construct an approximation of
     518             :  *
     519             :  *      { [x] -> [y] : exists f \in \delta, k \in Z :
     520             :  *                                      y = x + k [f, 1] and k >= 0 }
     521             :  *
     522             :  * For any element in this relation, the number of steps taken
     523             :  * is equal to the difference in the final coordinates.
     524             :  *
     525             :  * In particular, let delta be defined as
     526             :  *
     527             :  *      \delta = [p] -> { [x] : A x + a >= 0 and B p + b >= 0 and
     528             :  *                              C x + C'p + c >= 0 and
     529             :  *                              D x + D'p + d >= 0 }
     530             :  *
     531             :  * where the constraints C x + C'p + c >= 0 are such that the parametric
     532             :  * constant term of each constraint j, "C_j x + C'_j p + c_j",
     533             :  * can never attain positive values, then the relation is constructed as
     534             :  *
     535             :  *      { [x] -> [y] : exists [f, k] \in Z^{n+1} : y = x + f and
     536             :  *                      A f + k a >= 0 and B p + b >= 0 and
     537             :  *                      C f + C'p + c >= 0 and k >= 1 }
     538             :  *      union { [x] -> [x] }
     539             :  *
     540             :  * If the zero-length paths happen to correspond exactly to the identity
     541             :  * mapping, then we return
     542             :  *
     543             :  *      { [x] -> [y] : exists [f, k] \in Z^{n+1} : y = x + f and
     544             :  *                      A f + k a >= 0 and B p + b >= 0 and
     545             :  *                      C f + C'p + c >= 0 and k >= 0 }
     546             :  *
     547             :  * instead.
     548             :  *
     549             :  * Existentially quantified variables in \delta are handled by
     550             :  * classifying them as independent of the parameters, purely
     551             :  * parameter dependent and others.  Constraints containing
     552             :  * any of the other existentially quantified variables are removed.
     553             :  * This is safe, but leads to an additional overapproximation.
     554             :  *
     555             :  * If there are any impure constraints, then we also eliminate
     556             :  * the parameters from \delta, resulting in a set
     557             :  *
     558             :  *      \delta' = { [x] : E x + e >= 0 }
     559             :  *
     560             :  * and add the constraints
     561             :  *
     562             :  *                      E f + k e >= 0
     563             :  *
     564             :  * to the constructed relation.
     565             :  */
     566           0 : static __isl_give isl_map *path_along_delta(__isl_take isl_space *dim,
     567             :         __isl_take isl_basic_set *delta)
     568             : {
     569           0 :         isl_basic_map *path = NULL;
     570             :         unsigned d;
     571             :         unsigned n_div;
     572             :         unsigned nparam;
     573             :         unsigned off;
     574             :         int i, k;
     575             :         int is_id;
     576           0 :         int *div_purity = NULL;
     577           0 :         int impurity = 0;
     578             : 
     579           0 :         if (!delta)
     580           0 :                 goto error;
     581           0 :         n_div = isl_basic_set_dim(delta, isl_dim_div);
     582           0 :         d = isl_basic_set_dim(delta, isl_dim_set);
     583           0 :         nparam = isl_basic_set_dim(delta, isl_dim_param);
     584           0 :         path = isl_basic_map_alloc_space(isl_space_copy(dim), n_div + d + 1,
     585           0 :                         d + 1 + delta->n_eq, delta->n_eq + delta->n_ineq + 1);
     586           0 :         off = 1 + nparam + 2 * (d + 1) + n_div;
     587             : 
     588           0 :         for (i = 0; i < n_div + d + 1; ++i) {
     589           0 :                 k = isl_basic_map_alloc_div(path);
     590           0 :                 if (k < 0)
     591           0 :                         goto error;
     592           0 :                 isl_int_set_si(path->div[k][0], 0);
     593             :         }
     594             : 
     595           0 :         for (i = 0; i < d + 1; ++i) {
     596           0 :                 k = isl_basic_map_alloc_equality(path);
     597           0 :                 if (k < 0)
     598           0 :                         goto error;
     599           0 :                 isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path));
     600           0 :                 isl_int_set_si(path->eq[k][1 + nparam + i], 1);
     601           0 :                 isl_int_set_si(path->eq[k][1 + nparam + d + 1 + i], -1);
     602           0 :                 isl_int_set_si(path->eq[k][off + i], 1);
     603             :         }
     604             : 
     605           0 :         div_purity = get_div_purity(delta);
     606           0 :         if (n_div && !div_purity)
     607           0 :                 goto error;
     608             : 
     609           0 :         path = add_delta_constraints(path, delta, off, nparam, d,
     610             :                                      div_purity, 1, &impurity);
     611           0 :         path = add_delta_constraints(path, delta, off, nparam, d,
     612             :                                      div_purity, 0, &impurity);
     613           0 :         if (impurity) {
     614           0 :                 isl_space *dim = isl_basic_set_get_space(delta);
     615           0 :                 delta = isl_basic_set_project_out(delta,
     616             :                                                   isl_dim_param, 0, nparam);
     617           0 :                 delta = isl_basic_set_add_dims(delta, isl_dim_param, nparam);
     618           0 :                 delta = isl_basic_set_reset_space(delta, dim);
     619           0 :                 if (!delta)
     620           0 :                         goto error;
     621           0 :                 path = isl_basic_map_extend_constraints(path, delta->n_eq,
     622           0 :                                                         delta->n_ineq + 1);
     623           0 :                 path = add_delta_constraints(path, delta, off, nparam, d,
     624             :                                              NULL, 1, NULL);
     625           0 :                 path = add_delta_constraints(path, delta, off, nparam, d,
     626             :                                              NULL, 0, NULL);
     627           0 :                 path = isl_basic_map_gauss(path, NULL);
     628             :         }
     629             : 
     630           0 :         is_id = empty_path_is_identity(path, off + d);
     631           0 :         if (is_id < 0)
     632           0 :                 goto error;
     633             : 
     634           0 :         k = isl_basic_map_alloc_inequality(path);
     635           0 :         if (k < 0)
     636           0 :                 goto error;
     637           0 :         isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path));
     638           0 :         if (!is_id)
     639           0 :                 isl_int_set_si(path->ineq[k][0], -1);
     640           0 :         isl_int_set_si(path->ineq[k][off + d], 1);
     641             :                         
     642           0 :         free(div_purity);
     643           0 :         isl_basic_set_free(delta);
     644           0 :         path = isl_basic_map_finalize(path);
     645           0 :         if (is_id) {
     646           0 :                 isl_space_free(dim);
     647           0 :                 return isl_map_from_basic_map(path);
     648             :         }
     649           0 :         return isl_basic_map_union(path, isl_basic_map_identity(dim));
     650             : error:
     651           0 :         free(div_purity);
     652           0 :         isl_space_free(dim);
     653           0 :         isl_basic_set_free(delta);
     654           0 :         isl_basic_map_free(path);
     655           0 :         return NULL;
     656             : }
     657             : 
     658             : /* Given a dimension specification Z^{n+1} -> Z^{n+1} and a parameter "param",
     659             :  * construct a map that equates the parameter to the difference
     660             :  * in the final coordinates and imposes that this difference is positive.
     661             :  * That is, construct
     662             :  *
     663             :  *      { [x,x_s] -> [y,y_s] : k = y_s - x_s > 0 }
     664             :  */
     665           0 : static __isl_give isl_map *equate_parameter_to_length(__isl_take isl_space *dim,
     666             :         unsigned param)
     667             : {
     668             :         struct isl_basic_map *bmap;
     669             :         unsigned d;
     670             :         unsigned nparam;
     671             :         int k;
     672             : 
     673           0 :         d = isl_space_dim(dim, isl_dim_in);
     674           0 :         nparam = isl_space_dim(dim, isl_dim_param);
     675           0 :         bmap = isl_basic_map_alloc_space(dim, 0, 1, 1);
     676           0 :         k = isl_basic_map_alloc_equality(bmap);
     677           0 :         if (k < 0)
     678           0 :                 goto error;
     679           0 :         isl_seq_clr(bmap->eq[k], 1 + isl_basic_map_total_dim(bmap));
     680           0 :         isl_int_set_si(bmap->eq[k][1 + param], -1);
     681           0 :         isl_int_set_si(bmap->eq[k][1 + nparam + d - 1], -1);
     682           0 :         isl_int_set_si(bmap->eq[k][1 + nparam + d + d - 1], 1);
     683             : 
     684           0 :         k = isl_basic_map_alloc_inequality(bmap);
     685           0 :         if (k < 0)
     686           0 :                 goto error;
     687           0 :         isl_seq_clr(bmap->ineq[k], 1 + isl_basic_map_total_dim(bmap));
     688           0 :         isl_int_set_si(bmap->ineq[k][1 + param], 1);
     689           0 :         isl_int_set_si(bmap->ineq[k][0], -1);
     690             : 
     691           0 :         bmap = isl_basic_map_finalize(bmap);
     692           0 :         return isl_map_from_basic_map(bmap);
     693             : error:
     694           0 :         isl_basic_map_free(bmap);
     695           0 :         return NULL;
     696             : }
     697             : 
     698             : /* Check whether "path" is acyclic, where the last coordinates of domain
     699             :  * and range of path encode the number of steps taken.
     700             :  * That is, check whether
     701             :  *
     702             :  *      { d | d = y - x and (x,y) in path }
     703             :  *
     704             :  * does not contain any element with positive last coordinate (positive length)
     705             :  * and zero remaining coordinates (cycle).
     706             :  */
     707           0 : static int is_acyclic(__isl_take isl_map *path)
     708             : {
     709             :         int i;
     710             :         int acyclic;
     711             :         unsigned dim;
     712             :         struct isl_set *delta;
     713             : 
     714           0 :         delta = isl_map_deltas(path);
     715           0 :         dim = isl_set_dim(delta, isl_dim_set);
     716           0 :         for (i = 0; i < dim; ++i) {
     717           0 :                 if (i == dim -1)
     718           0 :                         delta = isl_set_lower_bound_si(delta, isl_dim_set, i, 1);
     719             :                 else
     720           0 :                         delta = isl_set_fix_si(delta, isl_dim_set, i, 0);
     721             :         }
     722             : 
     723           0 :         acyclic = isl_set_is_empty(delta);
     724           0 :         isl_set_free(delta);
     725             : 
     726           0 :         return acyclic;
     727             : }
     728             : 
     729             : /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D
     730             :  * and a dimension specification (Z^{n+1} -> Z^{n+1}),
     731             :  * construct a map that is an overapproximation of the map
     732             :  * that takes an element from the space D \times Z to another
     733             :  * element from the same space, such that the first n coordinates of the
     734             :  * difference between them is a sum of differences between images
     735             :  * and pre-images in one of the R_i and such that the last coordinate
     736             :  * is equal to the number of steps taken.
     737             :  * That is, let
     738             :  *
     739             :  *      \Delta_i = { y - x | (x, y) in R_i }
     740             :  *
     741             :  * then the constructed map is an overapproximation of
     742             :  *
     743             :  *      { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
     744             :  *                              d = (\sum_i k_i \delta_i, \sum_i k_i) }
     745             :  *
     746             :  * The elements of the singleton \Delta_i's are collected as the
     747             :  * rows of the steps matrix.  For all these \Delta_i's together,
     748             :  * a single path is constructed.
     749             :  * For each of the other \Delta_i's, we compute an overapproximation
     750             :  * of the paths along elements of \Delta_i.
     751             :  * Since each of these paths performs an addition, composition is
     752             :  * symmetric and we can simply compose all resulting paths in any order.
     753             :  */
     754           0 : static __isl_give isl_map *construct_extended_path(__isl_take isl_space *dim,
     755             :         __isl_keep isl_map *map, int *project)
     756             : {
     757           0 :         struct isl_mat *steps = NULL;
     758           0 :         struct isl_map *path = NULL;
     759             :         unsigned d;
     760             :         int i, j, n;
     761             : 
     762           0 :         if (!map)
     763           0 :                 goto error;
     764             : 
     765           0 :         d = isl_map_dim(map, isl_dim_in);
     766             : 
     767           0 :         path = isl_map_identity(isl_space_copy(dim));
     768             : 
     769           0 :         steps = isl_mat_alloc(map->ctx, map->n, d);
     770           0 :         if (!steps)
     771           0 :                 goto error;
     772             : 
     773           0 :         n = 0;
     774           0 :         for (i = 0; i < map->n; ++i) {
     775             :                 struct isl_basic_set *delta;
     776             : 
     777           0 :                 delta = isl_basic_map_deltas(isl_basic_map_copy(map->p[i]));
     778             : 
     779           0 :                 for (j = 0; j < d; ++j) {
     780             :                         isl_bool fixed;
     781             : 
     782           0 :                         fixed = isl_basic_set_plain_dim_is_fixed(delta, j,
     783           0 :                                                             &steps->row[n][j]);
     784           0 :                         if (fixed < 0) {
     785           0 :                                 isl_basic_set_free(delta);
     786           0 :                                 goto error;
     787             :                         }
     788           0 :                         if (!fixed)
     789           0 :                                 break;
     790             :                 }
     791             : 
     792             : 
     793           0 :                 if (j < d) {
     794           0 :                         path = isl_map_apply_range(path,
     795             :                                 path_along_delta(isl_space_copy(dim), delta));
     796           0 :                         path = isl_map_coalesce(path);
     797             :                 } else {
     798           0 :                         isl_basic_set_free(delta);
     799           0 :                         ++n;
     800             :                 }
     801             :         }
     802             : 
     803           0 :         if (n > 0) {
     804           0 :                 steps->n_row = n;
     805           0 :                 path = isl_map_apply_range(path,
     806             :                                 path_along_steps(isl_space_copy(dim), steps));
     807             :         }
     808             : 
     809           0 :         if (project && *project) {
     810           0 :                 *project = is_acyclic(isl_map_copy(path));
     811           0 :                 if (*project < 0)
     812           0 :                         goto error;
     813             :         }
     814             : 
     815           0 :         isl_space_free(dim);
     816           0 :         isl_mat_free(steps);
     817           0 :         return path;
     818             : error:
     819           0 :         isl_space_free(dim);
     820           0 :         isl_mat_free(steps);
     821           0 :         isl_map_free(path);
     822           0 :         return NULL;
     823             : }
     824             : 
     825           0 : static isl_bool isl_set_overlaps(__isl_keep isl_set *set1,
     826             :         __isl_keep isl_set *set2)
     827             : {
     828             :         isl_set *i;
     829             :         isl_bool no_overlap;
     830             : 
     831           0 :         if (!set1 || !set2)
     832           0 :                 return isl_bool_error;
     833             : 
     834           0 :         if (!isl_space_tuple_is_equal(set1->dim, isl_dim_set,
     835             :                                         set2->dim, isl_dim_set))
     836           0 :                 return isl_bool_false;
     837             : 
     838           0 :         i = isl_set_intersect(isl_set_copy(set1), isl_set_copy(set2));
     839           0 :         no_overlap = isl_set_is_empty(i);
     840           0 :         isl_set_free(i);
     841             : 
     842           0 :         return isl_bool_not(no_overlap);
     843             : }
     844             : 
     845             : /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D
     846             :  * and a dimension specification (Z^{n+1} -> Z^{n+1}),
     847             :  * construct a map that is an overapproximation of the map
     848             :  * that takes an element from the dom R \times Z to an
     849             :  * element from ran R \times Z, such that the first n coordinates of the
     850             :  * difference between them is a sum of differences between images
     851             :  * and pre-images in one of the R_i and such that the last coordinate
     852             :  * is equal to the number of steps taken.
     853             :  * That is, let
     854             :  *
     855             :  *      \Delta_i = { y - x | (x, y) in R_i }
     856             :  *
     857             :  * then the constructed map is an overapproximation of
     858             :  *
     859             :  *      { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
     860             :  *                              d = (\sum_i k_i \delta_i, \sum_i k_i) and
     861             :  *                              x in dom R and x + d in ran R and
     862             :  *                              \sum_i k_i >= 1 }
     863             :  */
     864           0 : static __isl_give isl_map *construct_component(__isl_take isl_space *dim,
     865             :         __isl_keep isl_map *map, int *exact, int project)
     866             : {
     867           0 :         struct isl_set *domain = NULL;
     868           0 :         struct isl_set *range = NULL;
     869           0 :         struct isl_map *app = NULL;
     870           0 :         struct isl_map *path = NULL;
     871             :         isl_bool overlaps;
     872             : 
     873           0 :         domain = isl_map_domain(isl_map_copy(map));
     874           0 :         domain = isl_set_coalesce(domain);
     875           0 :         range = isl_map_range(isl_map_copy(map));
     876           0 :         range = isl_set_coalesce(range);
     877           0 :         overlaps = isl_set_overlaps(domain, range);
     878           0 :         if (overlaps < 0 || !overlaps) {
     879           0 :                 isl_set_free(domain);
     880           0 :                 isl_set_free(range);
     881           0 :                 isl_space_free(dim);
     882             : 
     883           0 :                 if (overlaps < 0)
     884           0 :                         map = NULL;
     885           0 :                 map = isl_map_copy(map);
     886           0 :                 map = isl_map_add_dims(map, isl_dim_in, 1);
     887           0 :                 map = isl_map_add_dims(map, isl_dim_out, 1);
     888           0 :                 map = set_path_length(map, 1, 1);
     889           0 :                 return map;
     890             :         }
     891           0 :         app = isl_map_from_domain_and_range(domain, range);
     892           0 :         app = isl_map_add_dims(app, isl_dim_in, 1);
     893           0 :         app = isl_map_add_dims(app, isl_dim_out, 1);
     894             : 
     895           0 :         path = construct_extended_path(isl_space_copy(dim), map,
     896           0 :                                         exact && *exact ? &project : NULL);
     897           0 :         app = isl_map_intersect(app, path);
     898             : 
     899           0 :         if (exact && *exact &&
     900           0 :             (*exact = check_exactness(isl_map_copy(map), isl_map_copy(app),
     901             :                                       project)) < 0)
     902           0 :                 goto error;
     903             : 
     904           0 :         isl_space_free(dim);
     905           0 :         app = set_path_length(app, 0, 1);
     906           0 :         return app;
     907             : error:
     908           0 :         isl_space_free(dim);
     909           0 :         isl_map_free(app);
     910           0 :         return NULL;
     911             : }
     912             : 
     913             : /* Call construct_component and, if "project" is set, project out
     914             :  * the final coordinates.
     915             :  */
     916           0 : static __isl_give isl_map *construct_projected_component(
     917             :         __isl_take isl_space *dim,
     918             :         __isl_keep isl_map *map, int *exact, int project)
     919             : {
     920             :         isl_map *app;
     921             :         unsigned d;
     922             : 
     923           0 :         if (!dim)
     924           0 :                 return NULL;
     925           0 :         d = isl_space_dim(dim, isl_dim_in);
     926             : 
     927           0 :         app = construct_component(dim, map, exact, project);
     928           0 :         if (project) {
     929           0 :                 app = isl_map_project_out(app, isl_dim_in, d - 1, 1);
     930           0 :                 app = isl_map_project_out(app, isl_dim_out, d - 1, 1);
     931             :         }
     932           0 :         return app;
     933             : }
     934             : 
     935             : /* Compute an extended version, i.e., with path lengths, of
     936             :  * an overapproximation of the transitive closure of "bmap"
     937             :  * with path lengths greater than or equal to zero and with
     938             :  * domain and range equal to "dom".
     939             :  */
     940           0 : static __isl_give isl_map *q_closure(__isl_take isl_space *dim,
     941             :         __isl_take isl_set *dom, __isl_keep isl_basic_map *bmap, int *exact)
     942             : {
     943           0 :         int project = 1;
     944             :         isl_map *path;
     945             :         isl_map *map;
     946             :         isl_map *app;
     947             : 
     948           0 :         dom = isl_set_add_dims(dom, isl_dim_set, 1);
     949           0 :         app = isl_map_from_domain_and_range(dom, isl_set_copy(dom));
     950           0 :         map = isl_map_from_basic_map(isl_basic_map_copy(bmap));
     951           0 :         path = construct_extended_path(dim, map, &project);
     952           0 :         app = isl_map_intersect(app, path);
     953             : 
     954           0 :         if ((*exact = check_exactness(map, isl_map_copy(app), project)) < 0)
     955           0 :                 goto error;
     956             : 
     957           0 :         return app;
     958             : error:
     959           0 :         isl_map_free(app);
     960           0 :         return NULL;
     961             : }
     962             : 
     963             : /* Check whether qc has any elements of length at least one
     964             :  * with domain and/or range outside of dom and ran.
     965             :  */
     966           0 : static int has_spurious_elements(__isl_keep isl_map *qc,
     967             :         __isl_keep isl_set *dom, __isl_keep isl_set *ran)
     968             : {
     969             :         isl_set *s;
     970             :         int subset;
     971             :         unsigned d;
     972             : 
     973           0 :         if (!qc || !dom || !ran)
     974           0 :                 return -1;
     975             : 
     976           0 :         d = isl_map_dim(qc, isl_dim_in);
     977             : 
     978           0 :         qc = isl_map_copy(qc);
     979           0 :         qc = set_path_length(qc, 0, 1);
     980           0 :         qc = isl_map_project_out(qc, isl_dim_in, d - 1, 1);
     981           0 :         qc = isl_map_project_out(qc, isl_dim_out, d - 1, 1);
     982             : 
     983           0 :         s = isl_map_domain(isl_map_copy(qc));
     984           0 :         subset = isl_set_is_subset(s, dom);
     985           0 :         isl_set_free(s);
     986           0 :         if (subset < 0)
     987           0 :                 goto error;
     988           0 :         if (!subset) {
     989           0 :                 isl_map_free(qc);
     990           0 :                 return 1;
     991             :         }
     992             : 
     993           0 :         s = isl_map_range(qc);
     994           0 :         subset = isl_set_is_subset(s, ran);
     995           0 :         isl_set_free(s);
     996             : 
     997           0 :         return subset < 0 ? -1 : !subset;
     998             : error:
     999           0 :         isl_map_free(qc);
    1000           0 :         return -1;
    1001             : }
    1002             : 
    1003             : #define LEFT    2
    1004             : #define RIGHT   1
    1005             : 
    1006             : /* For each basic map in "map", except i, check whether it combines
    1007             :  * with the transitive closure that is reflexive on C combines
    1008             :  * to the left and to the right.
    1009             :  *
    1010             :  * In particular, if
    1011             :  *
    1012             :  *      dom map_j \subseteq C
    1013             :  *
    1014             :  * then right[j] is set to 1.  Otherwise, if
    1015             :  *
    1016             :  *      ran map_i \cap dom map_j = \emptyset
    1017             :  *
    1018             :  * then right[j] is set to 0.  Otherwise, composing to the right
    1019             :  * is impossible.
    1020             :  *
    1021             :  * Similar, for composing to the left, we have if
    1022             :  *
    1023             :  *      ran map_j \subseteq C
    1024             :  *
    1025             :  * then left[j] is set to 1.  Otherwise, if
    1026             :  *
    1027             :  *      dom map_i \cap ran map_j = \emptyset
    1028             :  *
    1029             :  * then left[j] is set to 0.  Otherwise, composing to the left
    1030             :  * is impossible.
    1031             :  *
    1032             :  * The return value is or'd with LEFT if composing to the left
    1033             :  * is possible and with RIGHT if composing to the right is possible.
    1034             :  */
    1035           0 : static int composability(__isl_keep isl_set *C, int i,
    1036             :         isl_set **dom, isl_set **ran, int *left, int *right,
    1037             :         __isl_keep isl_map *map)
    1038             : {
    1039             :         int j;
    1040             :         int ok;
    1041             : 
    1042           0 :         ok = LEFT | RIGHT;
    1043           0 :         for (j = 0; j < map->n && ok; ++j) {
    1044             :                 isl_bool overlaps, subset;
    1045           0 :                 if (j == i)
    1046           0 :                         continue;
    1047             : 
    1048           0 :                 if (ok & RIGHT) {
    1049           0 :                         if (!dom[j])
    1050           0 :                                 dom[j] = isl_set_from_basic_set(
    1051             :                                         isl_basic_map_domain(
    1052           0 :                                                 isl_basic_map_copy(map->p[j])));
    1053           0 :                         if (!dom[j])
    1054           0 :                                 return -1;
    1055           0 :                         overlaps = isl_set_overlaps(ran[i], dom[j]);
    1056           0 :                         if (overlaps < 0)
    1057           0 :                                 return -1;
    1058           0 :                         if (!overlaps)
    1059           0 :                                 right[j] = 0;
    1060             :                         else {
    1061           0 :                                 subset = isl_set_is_subset(dom[j], C);
    1062           0 :                                 if (subset < 0)
    1063           0 :                                         return -1;
    1064           0 :                                 if (subset)
    1065           0 :                                         right[j] = 1;
    1066             :                                 else
    1067           0 :                                         ok &= ~RIGHT;
    1068             :                         }
    1069             :                 }
    1070             : 
    1071           0 :                 if (ok & LEFT) {
    1072           0 :                         if (!ran[j])
    1073           0 :                                 ran[j] = isl_set_from_basic_set(
    1074             :                                         isl_basic_map_range(
    1075           0 :                                                 isl_basic_map_copy(map->p[j])));
    1076           0 :                         if (!ran[j])
    1077           0 :                                 return -1;
    1078           0 :                         overlaps = isl_set_overlaps(dom[i], ran[j]);
    1079           0 :                         if (overlaps < 0)
    1080           0 :                                 return -1;
    1081           0 :                         if (!overlaps)
    1082           0 :                                 left[j] = 0;
    1083             :                         else {
    1084           0 :                                 subset = isl_set_is_subset(ran[j], C);
    1085           0 :                                 if (subset < 0)
    1086           0 :                                         return -1;
    1087           0 :                                 if (subset)
    1088           0 :                                         left[j] = 1;
    1089             :                                 else
    1090           0 :                                         ok &= ~LEFT;
    1091             :                         }
    1092             :                 }
    1093             :         }
    1094             : 
    1095           0 :         return ok;
    1096             : }
    1097             : 
    1098           0 : static __isl_give isl_map *anonymize(__isl_take isl_map *map)
    1099             : {
    1100           0 :         map = isl_map_reset(map, isl_dim_in);
    1101           0 :         map = isl_map_reset(map, isl_dim_out);
    1102           0 :         return map;
    1103             : }
    1104             : 
    1105             : /* Return a map that is a union of the basic maps in "map", except i,
    1106             :  * composed to left and right with qc based on the entries of "left"
    1107             :  * and "right".
    1108             :  */
    1109           0 : static __isl_give isl_map *compose(__isl_keep isl_map *map, int i,
    1110             :         __isl_take isl_map *qc, int *left, int *right)
    1111             : {
    1112             :         int j;
    1113             :         isl_map *comp;
    1114             : 
    1115           0 :         comp = isl_map_empty(isl_map_get_space(map));
    1116           0 :         for (j = 0; j < map->n; ++j) {
    1117             :                 isl_map *map_j;
    1118             : 
    1119           0 :                 if (j == i)
    1120           0 :                         continue;
    1121             : 
    1122           0 :                 map_j = isl_map_from_basic_map(isl_basic_map_copy(map->p[j]));
    1123           0 :                 map_j = anonymize(map_j);
    1124           0 :                 if (left && left[j])
    1125           0 :                         map_j = isl_map_apply_range(map_j, isl_map_copy(qc));
    1126           0 :                 if (right && right[j])
    1127           0 :                         map_j = isl_map_apply_range(isl_map_copy(qc), map_j);
    1128           0 :                 comp = isl_map_union(comp, map_j);
    1129             :         }
    1130             : 
    1131           0 :         comp = isl_map_compute_divs(comp);
    1132           0 :         comp = isl_map_coalesce(comp);
    1133             : 
    1134           0 :         isl_map_free(qc);
    1135             : 
    1136           0 :         return comp;
    1137             : }
    1138             : 
    1139             : /* Compute the transitive closure of "map" incrementally by
    1140             :  * computing
    1141             :  *
    1142             :  *      map_i^+ \cup qc^+
    1143             :  *
    1144             :  * or
    1145             :  *
    1146             :  *      map_i^+ \cup ((id \cup map_i^) \circ qc^+)
    1147             :  *
    1148             :  * or
    1149             :  *
    1150             :  *      map_i^+ \cup (qc^+ \circ (id \cup map_i^))
    1151             :  *
    1152             :  * depending on whether left or right are NULL.
    1153             :  */
    1154           0 : static __isl_give isl_map *compute_incremental(
    1155             :         __isl_take isl_space *dim, __isl_keep isl_map *map,
    1156             :         int i, __isl_take isl_map *qc, int *left, int *right, int *exact)
    1157             : {
    1158             :         isl_map *map_i;
    1159             :         isl_map *tc;
    1160           0 :         isl_map *rtc = NULL;
    1161             : 
    1162           0 :         if (!map)
    1163           0 :                 goto error;
    1164           0 :         isl_assert(map->ctx, left || right, goto error);
    1165             : 
    1166           0 :         map_i = isl_map_from_basic_map(isl_basic_map_copy(map->p[i]));
    1167           0 :         tc = construct_projected_component(isl_space_copy(dim), map_i,
    1168             :                                                 exact, 1);
    1169           0 :         isl_map_free(map_i);
    1170             : 
    1171           0 :         if (*exact)
    1172           0 :                 qc = isl_map_transitive_closure(qc, exact);
    1173             : 
    1174           0 :         if (!*exact) {
    1175           0 :                 isl_space_free(dim);
    1176           0 :                 isl_map_free(tc);
    1177           0 :                 isl_map_free(qc);
    1178           0 :                 return isl_map_universe(isl_map_get_space(map));
    1179             :         }
    1180             : 
    1181           0 :         if (!left || !right)
    1182           0 :                 rtc = isl_map_union(isl_map_copy(tc),
    1183             :                                     isl_map_identity(isl_map_get_space(tc)));
    1184           0 :         if (!right)
    1185           0 :                 qc = isl_map_apply_range(rtc, qc);
    1186           0 :         if (!left)
    1187           0 :                 qc = isl_map_apply_range(qc, rtc);
    1188           0 :         qc = isl_map_union(tc, qc);
    1189             : 
    1190           0 :         isl_space_free(dim);
    1191             : 
    1192           0 :         return qc;
    1193             : error:
    1194           0 :         isl_space_free(dim);
    1195           0 :         isl_map_free(qc);
    1196           0 :         return NULL;
    1197             : }
    1198             : 
    1199             : /* Given a map "map", try to find a basic map such that
    1200             :  * map^+ can be computed as
    1201             :  *
    1202             :  * map^+ = map_i^+ \cup
    1203             :  *    \bigcup_j ((map_i^+ \cup Id_C)^+ \circ map_j \circ (map_i^+ \cup Id_C))^+
    1204             :  *
    1205             :  * with C the simple hull of the domain and range of the input map.
    1206             :  * map_i^ \cup Id_C is computed by allowing the path lengths to be zero
    1207             :  * and by intersecting domain and range with C.
    1208             :  * Of course, we need to check that this is actually equal to map_i^ \cup Id_C.
    1209             :  * Also, we only use the incremental computation if all the transitive
    1210             :  * closures are exact and if the number of basic maps in the union,
    1211             :  * after computing the integer divisions, is smaller than the number
    1212             :  * of basic maps in the input map.
    1213             :  */
    1214           0 : static int incemental_on_entire_domain(__isl_keep isl_space *dim,
    1215             :         __isl_keep isl_map *map,
    1216             :         isl_set **dom, isl_set **ran, int *left, int *right,
    1217             :         __isl_give isl_map **res)
    1218             : {
    1219             :         int i;
    1220             :         isl_set *C;
    1221             :         unsigned d;
    1222             : 
    1223           0 :         *res = NULL;
    1224             : 
    1225           0 :         C = isl_set_union(isl_map_domain(isl_map_copy(map)),
    1226             :                           isl_map_range(isl_map_copy(map)));
    1227           0 :         C = isl_set_from_basic_set(isl_set_simple_hull(C));
    1228           0 :         if (!C)
    1229           0 :                 return -1;
    1230           0 :         if (C->n != 1) {
    1231           0 :                 isl_set_free(C);
    1232           0 :                 return 0;
    1233             :         }
    1234             : 
    1235           0 :         d = isl_map_dim(map, isl_dim_in);
    1236             : 
    1237           0 :         for (i = 0; i < map->n; ++i) {
    1238             :                 isl_map *qc;
    1239             :                 int exact_i, spurious;
    1240             :                 int j;
    1241           0 :                 dom[i] = isl_set_from_basic_set(isl_basic_map_domain(
    1242           0 :                                         isl_basic_map_copy(map->p[i])));
    1243           0 :                 ran[i] = isl_set_from_basic_set(isl_basic_map_range(
    1244           0 :                                         isl_basic_map_copy(map->p[i])));
    1245           0 :                 qc = q_closure(isl_space_copy(dim), isl_set_copy(C),
    1246           0 :                                 map->p[i], &exact_i);
    1247           0 :                 if (!qc)
    1248           0 :                         goto error;
    1249           0 :                 if (!exact_i) {
    1250           0 :                         isl_map_free(qc);
    1251           0 :                         continue;
    1252             :                 }
    1253           0 :                 spurious = has_spurious_elements(qc, dom[i], ran[i]);
    1254           0 :                 if (spurious) {
    1255           0 :                         isl_map_free(qc);
    1256           0 :                         if (spurious < 0)
    1257           0 :                                 goto error;
    1258           0 :                         continue;
    1259             :                 }
    1260           0 :                 qc = isl_map_project_out(qc, isl_dim_in, d, 1);
    1261           0 :                 qc = isl_map_project_out(qc, isl_dim_out, d, 1);
    1262           0 :                 qc = isl_map_compute_divs(qc);
    1263           0 :                 for (j = 0; j < map->n; ++j)
    1264           0 :                         left[j] = right[j] = 1;
    1265           0 :                 qc = compose(map, i, qc, left, right);
    1266           0 :                 if (!qc)
    1267           0 :                         goto error;
    1268           0 :                 if (qc->n >= map->n) {
    1269           0 :                         isl_map_free(qc);
    1270           0 :                         continue;
    1271             :                 }
    1272           0 :                 *res = compute_incremental(isl_space_copy(dim), map, i, qc,
    1273             :                                 left, right, &exact_i);
    1274           0 :                 if (!*res)
    1275           0 :                         goto error;
    1276           0 :                 if (exact_i)
    1277           0 :                         break;
    1278           0 :                 isl_map_free(*res);
    1279           0 :                 *res = NULL;
    1280             :         }
    1281             : 
    1282           0 :         isl_set_free(C);
    1283             : 
    1284           0 :         return *res != NULL;
    1285             : error:
    1286           0 :         isl_set_free(C);
    1287           0 :         return -1;
    1288             : }
    1289             : 
    1290             : /* Try and compute the transitive closure of "map" as
    1291             :  *
    1292             :  * map^+ = map_i^+ \cup
    1293             :  *    \bigcup_j ((map_i^+ \cup Id_C)^+ \circ map_j \circ (map_i^+ \cup Id_C))^+
    1294             :  *
    1295             :  * with C either the simple hull of the domain and range of the entire
    1296             :  * map or the simple hull of domain and range of map_i.
    1297             :  */
    1298           0 : static __isl_give isl_map *incremental_closure(__isl_take isl_space *dim,
    1299             :         __isl_keep isl_map *map, int *exact, int project)
    1300             : {
    1301             :         int i;
    1302           0 :         isl_set **dom = NULL;
    1303           0 :         isl_set **ran = NULL;
    1304           0 :         int *left = NULL;
    1305           0 :         int *right = NULL;
    1306             :         isl_set *C;
    1307             :         unsigned d;
    1308           0 :         isl_map *res = NULL;
    1309             : 
    1310           0 :         if (!project)
    1311           0 :                 return construct_projected_component(dim, map, exact, project);
    1312             : 
    1313           0 :         if (!map)
    1314           0 :                 goto error;
    1315           0 :         if (map->n <= 1)
    1316           0 :                 return construct_projected_component(dim, map, exact, project);
    1317             : 
    1318           0 :         d = isl_map_dim(map, isl_dim_in);
    1319             : 
    1320           0 :         dom = isl_calloc_array(map->ctx, isl_set *, map->n);
    1321           0 :         ran = isl_calloc_array(map->ctx, isl_set *, map->n);
    1322           0 :         left = isl_calloc_array(map->ctx, int, map->n);
    1323           0 :         right = isl_calloc_array(map->ctx, int, map->n);
    1324           0 :         if (!ran || !dom || !left || !right)
    1325             :                 goto error;
    1326             : 
    1327           0 :         if (incemental_on_entire_domain(dim, map, dom, ran, left, right, &res) < 0)
    1328           0 :                 goto error;
    1329             : 
    1330           0 :         for (i = 0; !res && i < map->n; ++i) {
    1331             :                 isl_map *qc;
    1332             :                 int exact_i, spurious, comp;
    1333           0 :                 if (!dom[i])
    1334           0 :                         dom[i] = isl_set_from_basic_set(
    1335             :                                         isl_basic_map_domain(
    1336           0 :                                                 isl_basic_map_copy(map->p[i])));
    1337           0 :                 if (!dom[i])
    1338           0 :                         goto error;
    1339           0 :                 if (!ran[i])
    1340           0 :                         ran[i] = isl_set_from_basic_set(
    1341             :                                         isl_basic_map_range(
    1342           0 :                                                 isl_basic_map_copy(map->p[i])));
    1343           0 :                 if (!ran[i])
    1344           0 :                         goto error;
    1345           0 :                 C = isl_set_union(isl_set_copy(dom[i]),
    1346           0 :                                       isl_set_copy(ran[i]));
    1347           0 :                 C = isl_set_from_basic_set(isl_set_simple_hull(C));
    1348           0 :                 if (!C)
    1349           0 :                         goto error;
    1350           0 :                 if (C->n != 1) {
    1351           0 :                         isl_set_free(C);
    1352           0 :                         continue;
    1353             :                 }
    1354           0 :                 comp = composability(C, i, dom, ran, left, right, map);
    1355           0 :                 if (!comp || comp < 0) {
    1356           0 :                         isl_set_free(C);
    1357           0 :                         if (comp < 0)
    1358           0 :                                 goto error;
    1359           0 :                         continue;
    1360             :                 }
    1361           0 :                 qc = q_closure(isl_space_copy(dim), C, map->p[i], &exact_i);
    1362           0 :                 if (!qc)
    1363           0 :                         goto error;
    1364           0 :                 if (!exact_i) {
    1365           0 :                         isl_map_free(qc);
    1366           0 :                         continue;
    1367             :                 }
    1368           0 :                 spurious = has_spurious_elements(qc, dom[i], ran[i]);
    1369           0 :                 if (spurious) {
    1370           0 :                         isl_map_free(qc);
    1371           0 :                         if (spurious < 0)
    1372           0 :                                 goto error;
    1373           0 :                         continue;
    1374             :                 }
    1375           0 :                 qc = isl_map_project_out(qc, isl_dim_in, d, 1);
    1376           0 :                 qc = isl_map_project_out(qc, isl_dim_out, d, 1);
    1377           0 :                 qc = isl_map_compute_divs(qc);
    1378           0 :                 qc = compose(map, i, qc, (comp & LEFT) ? left : NULL,
    1379           0 :                                 (comp & RIGHT) ? right : NULL);
    1380           0 :                 if (!qc)
    1381           0 :                         goto error;
    1382           0 :                 if (qc->n >= map->n) {
    1383           0 :                         isl_map_free(qc);
    1384           0 :                         continue;
    1385             :                 }
    1386           0 :                 res = compute_incremental(isl_space_copy(dim), map, i, qc,
    1387           0 :                                 (comp & LEFT) ? left : NULL,
    1388           0 :                                 (comp & RIGHT) ? right : NULL, &exact_i);
    1389           0 :                 if (!res)
    1390           0 :                         goto error;
    1391           0 :                 if (exact_i)
    1392           0 :                         break;
    1393           0 :                 isl_map_free(res);
    1394           0 :                 res = NULL;
    1395             :         }
    1396             : 
    1397           0 :         for (i = 0; i < map->n; ++i) {
    1398           0 :                 isl_set_free(dom[i]);
    1399           0 :                 isl_set_free(ran[i]);
    1400             :         }
    1401           0 :         free(dom);
    1402           0 :         free(ran);
    1403           0 :         free(left);
    1404           0 :         free(right);
    1405             : 
    1406           0 :         if (res) {
    1407           0 :                 isl_space_free(dim);
    1408           0 :                 return res;
    1409             :         }
    1410             : 
    1411           0 :         return construct_projected_component(dim, map, exact, project);
    1412             : error:
    1413           0 :         if (dom)
    1414           0 :                 for (i = 0; i < map->n; ++i)
    1415           0 :                         isl_set_free(dom[i]);
    1416           0 :         free(dom);
    1417           0 :         if (ran)
    1418           0 :                 for (i = 0; i < map->n; ++i)
    1419           0 :                         isl_set_free(ran[i]);
    1420           0 :         free(ran);
    1421           0 :         free(left);
    1422           0 :         free(right);
    1423           0 :         isl_space_free(dim);
    1424           0 :         return NULL;
    1425             : }
    1426             : 
    1427             : /* Given an array of sets "set", add "dom" at position "pos"
    1428             :  * and search for elements at earlier positions that overlap with "dom".
    1429             :  * If any can be found, then merge all of them, together with "dom", into
    1430             :  * a single set and assign the union to the first in the array,
    1431             :  * which becomes the new group leader for all groups involved in the merge.
    1432             :  * During the search, we only consider group leaders, i.e., those with
    1433             :  * group[i] = i, as the other sets have already been combined
    1434             :  * with one of the group leaders.
    1435             :  */
    1436           0 : static int merge(isl_set **set, int *group, __isl_take isl_set *dom, int pos)
    1437             : {
    1438             :         int i;
    1439             : 
    1440           0 :         group[pos] = pos;
    1441           0 :         set[pos] = isl_set_copy(dom);
    1442             : 
    1443           0 :         for (i = pos - 1; i >= 0; --i) {
    1444             :                 isl_bool o;
    1445             : 
    1446           0 :                 if (group[i] != i)
    1447           0 :                         continue;
    1448             : 
    1449           0 :                 o = isl_set_overlaps(set[i], dom);
    1450           0 :                 if (o < 0)
    1451           0 :                         goto error;
    1452           0 :                 if (!o)
    1453           0 :                         continue;
    1454             : 
    1455           0 :                 set[i] = isl_set_union(set[i], set[group[pos]]);
    1456           0 :                 set[group[pos]] = NULL;
    1457           0 :                 if (!set[i])
    1458           0 :                         goto error;
    1459           0 :                 group[group[pos]] = i;
    1460           0 :                 group[pos] = i;
    1461             :         }
    1462             : 
    1463           0 :         isl_set_free(dom);
    1464           0 :         return 0;
    1465             : error:
    1466           0 :         isl_set_free(dom);
    1467           0 :         return -1;
    1468             : }
    1469             : 
    1470             : /* Replace each entry in the n by n grid of maps by the cross product
    1471             :  * with the relation { [i] -> [i + 1] }.
    1472             :  */
    1473           0 : static int add_length(__isl_keep isl_map *map, isl_map ***grid, int n)
    1474             : {
    1475             :         int i, j, k;
    1476             :         isl_space *dim;
    1477             :         isl_basic_map *bstep;
    1478             :         isl_map *step;
    1479             :         unsigned nparam;
    1480             : 
    1481           0 :         if (!map)
    1482           0 :                 return -1;
    1483             : 
    1484           0 :         dim = isl_map_get_space(map);
    1485           0 :         nparam = isl_space_dim(dim, isl_dim_param);
    1486           0 :         dim = isl_space_drop_dims(dim, isl_dim_in, 0, isl_space_dim(dim, isl_dim_in));
    1487           0 :         dim = isl_space_drop_dims(dim, isl_dim_out, 0, isl_space_dim(dim, isl_dim_out));
    1488           0 :         dim = isl_space_add_dims(dim, isl_dim_in, 1);
    1489           0 :         dim = isl_space_add_dims(dim, isl_dim_out, 1);
    1490           0 :         bstep = isl_basic_map_alloc_space(dim, 0, 1, 0);
    1491           0 :         k = isl_basic_map_alloc_equality(bstep);
    1492           0 :         if (k < 0) {
    1493           0 :                 isl_basic_map_free(bstep);
    1494           0 :                 return -1;
    1495             :         }
    1496           0 :         isl_seq_clr(bstep->eq[k], 1 + isl_basic_map_total_dim(bstep));
    1497           0 :         isl_int_set_si(bstep->eq[k][0], 1);
    1498           0 :         isl_int_set_si(bstep->eq[k][1 + nparam], 1);
    1499           0 :         isl_int_set_si(bstep->eq[k][1 + nparam + 1], -1);
    1500           0 :         bstep = isl_basic_map_finalize(bstep);
    1501           0 :         step = isl_map_from_basic_map(bstep);
    1502             : 
    1503           0 :         for (i = 0; i < n; ++i)
    1504           0 :                 for (j = 0; j < n; ++j)
    1505           0 :                         grid[i][j] = isl_map_product(grid[i][j],
    1506             :                                                      isl_map_copy(step));
    1507             : 
    1508           0 :         isl_map_free(step);
    1509             : 
    1510           0 :         return 0;
    1511             : }
    1512             : 
    1513             : /* The core of the Floyd-Warshall algorithm.
    1514             :  * Updates the given n x x matrix of relations in place.
    1515             :  *
    1516             :  * The algorithm iterates over all vertices.  In each step, the whole
    1517             :  * matrix is updated to include all paths that go to the current vertex,
    1518             :  * possibly stay there a while (including passing through earlier vertices)
    1519             :  * and then come back.  At the start of each iteration, the diagonal
    1520             :  * element corresponding to the current vertex is replaced by its
    1521             :  * transitive closure to account for all indirect paths that stay
    1522             :  * in the current vertex.
    1523             :  */
    1524           0 : static void floyd_warshall_iterate(isl_map ***grid, int n, int *exact)
    1525             : {
    1526             :         int r, p, q;
    1527             : 
    1528           0 :         for (r = 0; r < n; ++r) {
    1529             :                 int r_exact;
    1530           0 :                 grid[r][r] = isl_map_transitive_closure(grid[r][r],
    1531           0 :                                 (exact && *exact) ? &r_exact : NULL);
    1532           0 :                 if (exact && *exact && !r_exact)
    1533           0 :                         *exact = 0;
    1534             : 
    1535           0 :                 for (p = 0; p < n; ++p)
    1536           0 :                         for (q = 0; q < n; ++q) {
    1537             :                                 isl_map *loop;
    1538           0 :                                 if (p == r && q == r)
    1539           0 :                                         continue;
    1540           0 :                                 loop = isl_map_apply_range(
    1541           0 :                                                 isl_map_copy(grid[p][r]),
    1542           0 :                                                 isl_map_copy(grid[r][q]));
    1543           0 :                                 grid[p][q] = isl_map_union(grid[p][q], loop);
    1544           0 :                                 loop = isl_map_apply_range(
    1545           0 :                                                 isl_map_copy(grid[p][r]),
    1546             :                                         isl_map_apply_range(
    1547           0 :                                                 isl_map_copy(grid[r][r]),
    1548           0 :                                                 isl_map_copy(grid[r][q])));
    1549           0 :                                 grid[p][q] = isl_map_union(grid[p][q], loop);
    1550           0 :                                 grid[p][q] = isl_map_coalesce(grid[p][q]);
    1551             :                         }
    1552             :         }
    1553           0 : }
    1554             : 
    1555             : /* Given a partition of the domains and ranges of the basic maps in "map",
    1556             :  * apply the Floyd-Warshall algorithm with the elements in the partition
    1557             :  * as vertices.
    1558             :  *
    1559             :  * In particular, there are "n" elements in the partition and "group" is
    1560             :  * an array of length 2 * map->n with entries in [0,n-1].
    1561             :  *
    1562             :  * We first construct a matrix of relations based on the partition information,
    1563             :  * apply Floyd-Warshall on this matrix of relations and then take the
    1564             :  * union of all entries in the matrix as the final result.
    1565             :  *
    1566             :  * If we are actually computing the power instead of the transitive closure,
    1567             :  * i.e., when "project" is not set, then the result should have the
    1568             :  * path lengths encoded as the difference between an extra pair of
    1569             :  * coordinates.  We therefore apply the nested transitive closures
    1570             :  * to relations that include these lengths.  In particular, we replace
    1571             :  * the input relation by the cross product with the unit length relation
    1572             :  * { [i] -> [i + 1] }.
    1573             :  */
    1574           0 : static __isl_give isl_map *floyd_warshall_with_groups(__isl_take isl_space *dim,
    1575             :         __isl_keep isl_map *map, int *exact, int project, int *group, int n)
    1576             : {
    1577             :         int i, j, k;
    1578           0 :         isl_map ***grid = NULL;
    1579             :         isl_map *app;
    1580             : 
    1581           0 :         if (!map)
    1582           0 :                 goto error;
    1583             : 
    1584           0 :         if (n == 1) {
    1585           0 :                 free(group);
    1586           0 :                 return incremental_closure(dim, map, exact, project);
    1587             :         }
    1588             : 
    1589           0 :         grid = isl_calloc_array(map->ctx, isl_map **, n);
    1590           0 :         if (!grid)
    1591           0 :                 goto error;
    1592           0 :         for (i = 0; i < n; ++i) {
    1593           0 :                 grid[i] = isl_calloc_array(map->ctx, isl_map *, n);
    1594           0 :                 if (!grid[i])
    1595           0 :                         goto error;
    1596           0 :                 for (j = 0; j < n; ++j)
    1597           0 :                         grid[i][j] = isl_map_empty(isl_map_get_space(map));
    1598             :         }
    1599             : 
    1600           0 :         for (k = 0; k < map->n; ++k) {
    1601           0 :                 i = group[2 * k];
    1602           0 :                 j = group[2 * k + 1];
    1603           0 :                 grid[i][j] = isl_map_union(grid[i][j],
    1604             :                                 isl_map_from_basic_map(
    1605           0 :                                         isl_basic_map_copy(map->p[k])));
    1606             :         }
    1607             : 
    1608           0 :         if (!project && add_length(map, grid, n) < 0)
    1609           0 :                 goto error;
    1610             : 
    1611           0 :         floyd_warshall_iterate(grid, n, exact);
    1612             : 
    1613           0 :         app = isl_map_empty(isl_map_get_space(grid[0][0]));
    1614             : 
    1615           0 :         for (i = 0; i < n; ++i) {
    1616           0 :                 for (j = 0; j < n; ++j)
    1617           0 :                         app = isl_map_union(app, grid[i][j]);
    1618           0 :                 free(grid[i]);
    1619             :         }
    1620           0 :         free(grid);
    1621             : 
    1622           0 :         free(group);
    1623           0 :         isl_space_free(dim);
    1624             : 
    1625           0 :         return app;
    1626             : error:
    1627           0 :         if (grid)
    1628           0 :                 for (i = 0; i < n; ++i) {
    1629           0 :                         if (!grid[i])
    1630           0 :                                 continue;
    1631           0 :                         for (j = 0; j < n; ++j)
    1632           0 :                                 isl_map_free(grid[i][j]);
    1633           0 :                         free(grid[i]);
    1634             :                 }
    1635           0 :         free(grid);
    1636           0 :         free(group);
    1637           0 :         isl_space_free(dim);
    1638           0 :         return NULL;
    1639             : }
    1640             : 
    1641             : /* Partition the domains and ranges of the n basic relations in list
    1642             :  * into disjoint cells.
    1643             :  *
    1644             :  * To find the partition, we simply consider all of the domains
    1645             :  * and ranges in turn and combine those that overlap.
    1646             :  * "set" contains the partition elements and "group" indicates
    1647             :  * to which partition element a given domain or range belongs.
    1648             :  * The domain of basic map i corresponds to element 2 * i in these arrays,
    1649             :  * while the domain corresponds to element 2 * i + 1.
    1650             :  * During the construction group[k] is either equal to k,
    1651             :  * in which case set[k] contains the union of all the domains and
    1652             :  * ranges in the corresponding group, or is equal to some l < k,
    1653             :  * with l another domain or range in the same group.
    1654             :  */
    1655           0 : static int *setup_groups(isl_ctx *ctx, __isl_keep isl_basic_map **list, int n,
    1656             :         isl_set ***set, int *n_group)
    1657             : {
    1658             :         int i;
    1659           0 :         int *group = NULL;
    1660             :         int g;
    1661             : 
    1662           0 :         *set = isl_calloc_array(ctx, isl_set *, 2 * n);
    1663           0 :         group = isl_alloc_array(ctx, int, 2 * n);
    1664             : 
    1665           0 :         if (!*set || !group)
    1666             :                 goto error;
    1667             : 
    1668           0 :         for (i = 0; i < n; ++i) {
    1669             :                 isl_set *dom;
    1670           0 :                 dom = isl_set_from_basic_set(isl_basic_map_domain(
    1671           0 :                                 isl_basic_map_copy(list[i])));
    1672           0 :                 if (merge(*set, group, dom, 2 * i) < 0)
    1673           0 :                         goto error;
    1674           0 :                 dom = isl_set_from_basic_set(isl_basic_map_range(
    1675           0 :                                 isl_basic_map_copy(list[i])));
    1676           0 :                 if (merge(*set, group, dom, 2 * i + 1) < 0)
    1677           0 :                         goto error;
    1678             :         }
    1679             : 
    1680           0 :         g = 0;
    1681           0 :         for (i = 0; i < 2 * n; ++i)
    1682           0 :                 if (group[i] == i) {
    1683           0 :                         if (g != i) {
    1684           0 :                                 (*set)[g] = (*set)[i];
    1685           0 :                                 (*set)[i] = NULL;
    1686             :                         }
    1687           0 :                         group[i] = g++;
    1688             :                 } else
    1689           0 :                         group[i] = group[group[i]];
    1690             : 
    1691           0 :         *n_group = g;
    1692             : 
    1693           0 :         return group;
    1694             : error:
    1695           0 :         if (*set) {
    1696           0 :                 for (i = 0; i < 2 * n; ++i)
    1697           0 :                         isl_set_free((*set)[i]);
    1698           0 :                 free(*set);
    1699           0 :                 *set = NULL;
    1700             :         }
    1701           0 :         free(group);
    1702           0 :         return NULL;
    1703             : }
    1704             : 
    1705             : /* Check if the domains and ranges of the basic maps in "map" can
    1706             :  * be partitioned, and if so, apply Floyd-Warshall on the elements
    1707             :  * of the partition.  Note that we also apply this algorithm
    1708             :  * if we want to compute the power, i.e., when "project" is not set.
    1709             :  * However, the results are unlikely to be exact since the recursive
    1710             :  * calls inside the Floyd-Warshall algorithm typically result in
    1711             :  * non-linear path lengths quite quickly.
    1712             :  */
    1713           0 : static __isl_give isl_map *floyd_warshall(__isl_take isl_space *dim,
    1714             :         __isl_keep isl_map *map, int *exact, int project)
    1715             : {
    1716             :         int i;
    1717           0 :         isl_set **set = NULL;
    1718           0 :         int *group = NULL;
    1719             :         int n;
    1720             : 
    1721           0 :         if (!map)
    1722           0 :                 goto error;
    1723           0 :         if (map->n <= 1)
    1724           0 :                 return incremental_closure(dim, map, exact, project);
    1725             : 
    1726           0 :         group = setup_groups(map->ctx, map->p, map->n, &set, &n);
    1727           0 :         if (!group)
    1728           0 :                 goto error;
    1729             : 
    1730           0 :         for (i = 0; i < 2 * map->n; ++i)
    1731           0 :                 isl_set_free(set[i]);
    1732             : 
    1733           0 :         free(set);
    1734             : 
    1735           0 :         return floyd_warshall_with_groups(dim, map, exact, project, group, n);
    1736             : error:
    1737           0 :         isl_space_free(dim);
    1738           0 :         return NULL;
    1739             : }
    1740             : 
    1741             : /* Structure for representing the nodes of the graph of which
    1742             :  * strongly connected components are being computed.
    1743             :  *
    1744             :  * list contains the actual nodes
    1745             :  * check_closed is set if we may have used the fact that
    1746             :  * a pair of basic maps can be interchanged
    1747             :  */
    1748             : struct isl_tc_follows_data {
    1749             :         isl_basic_map **list;
    1750             :         int check_closed;
    1751             : };
    1752             : 
    1753             : /* Check whether in the computation of the transitive closure
    1754             :  * "list[i]" (R_1) should follow (or be part of the same component as)
    1755             :  * "list[j]" (R_2).
    1756             :  *
    1757             :  * That is check whether
    1758             :  *
    1759             :  *      R_1 \circ R_2
    1760             :  *
    1761             :  * is a subset of
    1762             :  *
    1763             :  *      R_2 \circ R_1
    1764             :  *
    1765             :  * If so, then there is no reason for R_1 to immediately follow R_2
    1766             :  * in any path.
    1767             :  *
    1768             :  * *check_closed is set if the subset relation holds while
    1769             :  * R_1 \circ R_2 is not empty.
    1770             :  */
    1771           0 : static isl_bool basic_map_follows(int i, int j, void *user)
    1772             : {
    1773           0 :         struct isl_tc_follows_data *data = user;
    1774           0 :         struct isl_map *map12 = NULL;
    1775           0 :         struct isl_map *map21 = NULL;
    1776             :         isl_bool subset;
    1777             : 
    1778           0 :         if (!isl_space_tuple_is_equal(data->list[i]->dim, isl_dim_in,
    1779           0 :                                     data->list[j]->dim, isl_dim_out))
    1780           0 :                 return isl_bool_false;
    1781             : 
    1782           0 :         map21 = isl_map_from_basic_map(
    1783             :                         isl_basic_map_apply_range(
    1784           0 :                                 isl_basic_map_copy(data->list[j]),
    1785           0 :                                 isl_basic_map_copy(data->list[i])));
    1786           0 :         subset = isl_map_is_empty(map21);
    1787           0 :         if (subset < 0)
    1788           0 :                 goto error;
    1789           0 :         if (subset) {
    1790           0 :                 isl_map_free(map21);
    1791           0 :                 return isl_bool_false;
    1792             :         }
    1793             : 
    1794           0 :         if (!isl_space_tuple_is_equal(data->list[i]->dim, isl_dim_in,
    1795           0 :                                     data->list[i]->dim, isl_dim_out) ||
    1796           0 :             !isl_space_tuple_is_equal(data->list[j]->dim, isl_dim_in,
    1797           0 :                                     data->list[j]->dim, isl_dim_out)) {
    1798           0 :                 isl_map_free(map21);
    1799           0 :                 return isl_bool_true;
    1800             :         }
    1801             : 
    1802           0 :         map12 = isl_map_from_basic_map(
    1803             :                         isl_basic_map_apply_range(
    1804           0 :                                 isl_basic_map_copy(data->list[i]),
    1805           0 :                                 isl_basic_map_copy(data->list[j])));
    1806             : 
    1807           0 :         subset = isl_map_is_subset(map21, map12);
    1808             : 
    1809           0 :         isl_map_free(map12);
    1810           0 :         isl_map_free(map21);
    1811             : 
    1812           0 :         if (subset)
    1813           0 :                 data->check_closed = 1;
    1814             : 
    1815           0 :         return subset < 0 ? isl_bool_error : !subset;
    1816             : error:
    1817           0 :         isl_map_free(map21);
    1818           0 :         return isl_bool_error;
    1819             : }
    1820             : 
    1821             : /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D
    1822             :  * and a dimension specification (Z^{n+1} -> Z^{n+1}),
    1823             :  * construct a map that is an overapproximation of the map
    1824             :  * that takes an element from the dom R \times Z to an
    1825             :  * element from ran R \times Z, such that the first n coordinates of the
    1826             :  * difference between them is a sum of differences between images
    1827             :  * and pre-images in one of the R_i and such that the last coordinate
    1828             :  * is equal to the number of steps taken.
    1829             :  * If "project" is set, then these final coordinates are not included,
    1830             :  * i.e., a relation of type Z^n -> Z^n is returned.
    1831             :  * That is, let
    1832             :  *
    1833             :  *      \Delta_i = { y - x | (x, y) in R_i }
    1834             :  *
    1835             :  * then the constructed map is an overapproximation of
    1836             :  *
    1837             :  *      { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
    1838             :  *                              d = (\sum_i k_i \delta_i, \sum_i k_i) and
    1839             :  *                              x in dom R and x + d in ran R }
    1840             :  *
    1841             :  * or
    1842             :  *
    1843             :  *      { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
    1844             :  *                              d = (\sum_i k_i \delta_i) and
    1845             :  *                              x in dom R and x + d in ran R }
    1846             :  *
    1847             :  * if "project" is set.
    1848             :  *
    1849             :  * We first split the map into strongly connected components, perform
    1850             :  * the above on each component and then join the results in the correct
    1851             :  * order, at each join also taking in the union of both arguments
    1852             :  * to allow for paths that do not go through one of the two arguments.
    1853             :  */
    1854           0 : static __isl_give isl_map *construct_power_components(__isl_take isl_space *dim,
    1855             :         __isl_keep isl_map *map, int *exact, int project)
    1856             : {
    1857             :         int i, n, c;
    1858           0 :         struct isl_map *path = NULL;
    1859             :         struct isl_tc_follows_data data;
    1860           0 :         struct isl_tarjan_graph *g = NULL;
    1861             :         int *orig_exact;
    1862             :         int local_exact;
    1863             : 
    1864           0 :         if (!map)
    1865           0 :                 goto error;
    1866           0 :         if (map->n <= 1)
    1867           0 :                 return floyd_warshall(dim, map, exact, project);
    1868             : 
    1869           0 :         data.list = map->p;
    1870           0 :         data.check_closed = 0;
    1871           0 :         g = isl_tarjan_graph_init(map->ctx, map->n, &basic_map_follows, &data);
    1872           0 :         if (!g)
    1873           0 :                 goto error;
    1874             : 
    1875           0 :         orig_exact = exact;
    1876           0 :         if (data.check_closed && !exact)
    1877           0 :                 exact = &local_exact;
    1878             : 
    1879           0 :         c = 0;
    1880           0 :         i = 0;
    1881           0 :         n = map->n;
    1882           0 :         if (project)
    1883           0 :                 path = isl_map_empty(isl_map_get_space(map));
    1884             :         else
    1885           0 :                 path = isl_map_empty(isl_space_copy(dim));
    1886           0 :         path = anonymize(path);
    1887           0 :         while (n) {
    1888             :                 struct isl_map *comp;
    1889             :                 isl_map *path_comp, *path_comb;
    1890           0 :                 comp = isl_map_alloc_space(isl_map_get_space(map), n, 0);
    1891           0 :                 while (g->order[i] != -1) {
    1892           0 :                         comp = isl_map_add_basic_map(comp,
    1893           0 :                                     isl_basic_map_copy(map->p[g->order[i]]));
    1894           0 :                         --n;
    1895           0 :                         ++i;
    1896             :                 }
    1897           0 :                 path_comp = floyd_warshall(isl_space_copy(dim),
    1898             :                                                 comp, exact, project);
    1899           0 :                 path_comp = anonymize(path_comp);
    1900           0 :                 path_comb = isl_map_apply_range(isl_map_copy(path),
    1901             :                                                 isl_map_copy(path_comp));
    1902           0 :                 path = isl_map_union(path, path_comp);
    1903           0 :                 path = isl_map_union(path, path_comb);
    1904           0 :                 isl_map_free(comp);
    1905           0 :                 ++i;
    1906           0 :                 ++c;
    1907             :         }
    1908             : 
    1909           0 :         if (c > 1 && data.check_closed && !*exact) {
    1910             :                 int closed;
    1911             : 
    1912           0 :                 closed = isl_map_is_transitively_closed(path);
    1913           0 :                 if (closed < 0)
    1914           0 :                         goto error;
    1915           0 :                 if (!closed) {
    1916           0 :                         isl_tarjan_graph_free(g);
    1917           0 :                         isl_map_free(path);
    1918           0 :                         return floyd_warshall(dim, map, orig_exact, project);
    1919             :                 }
    1920             :         }
    1921             : 
    1922           0 :         isl_tarjan_graph_free(g);
    1923           0 :         isl_space_free(dim);
    1924             : 
    1925           0 :         return path;
    1926             : error:
    1927           0 :         isl_tarjan_graph_free(g);
    1928           0 :         isl_space_free(dim);
    1929           0 :         isl_map_free(path);
    1930           0 :         return NULL;
    1931             : }
    1932             : 
    1933             : /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D,
    1934             :  * construct a map that is an overapproximation of the map
    1935             :  * that takes an element from the space D to another
    1936             :  * element from the same space, such that the difference between
    1937             :  * them is a strictly positive sum of differences between images
    1938             :  * and pre-images in one of the R_i.
    1939             :  * The number of differences in the sum is equated to parameter "param".
    1940             :  * That is, let
    1941             :  *
    1942             :  *      \Delta_i = { y - x | (x, y) in R_i }
    1943             :  *
    1944             :  * then the constructed map is an overapproximation of
    1945             :  *
    1946             :  *      { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
    1947             :  *                              d = \sum_i k_i \delta_i and k = \sum_i k_i > 0 }
    1948             :  * or
    1949             :  *
    1950             :  *      { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
    1951             :  *                              d = \sum_i k_i \delta_i and \sum_i k_i > 0 }
    1952             :  *
    1953             :  * if "project" is set.
    1954             :  *
    1955             :  * If "project" is not set, then
    1956             :  * we construct an extended mapping with an extra coordinate
    1957             :  * that indicates the number of steps taken.  In particular,
    1958             :  * the difference in the last coordinate is equal to the number
    1959             :  * of steps taken to move from a domain element to the corresponding
    1960             :  * image element(s).
    1961             :  */
    1962           0 : static __isl_give isl_map *construct_power(__isl_keep isl_map *map,
    1963             :         int *exact, int project)
    1964             : {
    1965           0 :         struct isl_map *app = NULL;
    1966           0 :         isl_space *dim = NULL;
    1967             : 
    1968           0 :         if (!map)
    1969           0 :                 return NULL;
    1970             : 
    1971           0 :         dim = isl_map_get_space(map);
    1972             : 
    1973           0 :         dim = isl_space_add_dims(dim, isl_dim_in, 1);
    1974           0 :         dim = isl_space_add_dims(dim, isl_dim_out, 1);
    1975             : 
    1976           0 :         app = construct_power_components(isl_space_copy(dim), map,
    1977             :                                         exact, project);
    1978             : 
    1979           0 :         isl_space_free(dim);
    1980             : 
    1981           0 :         return app;
    1982             : }
    1983             : 
    1984             : /* Compute the positive powers of "map", or an overapproximation.
    1985             :  * If the result is exact, then *exact is set to 1.
    1986             :  *
    1987             :  * If project is set, then we are actually interested in the transitive
    1988             :  * closure, so we can use a more relaxed exactness check.
    1989             :  * The lengths of the paths are also projected out instead of being
    1990             :  * encoded as the difference between an extra pair of final coordinates.
    1991             :  */
    1992           0 : static __isl_give isl_map *map_power(__isl_take isl_map *map,
    1993             :         int *exact, int project)
    1994             : {
    1995           0 :         struct isl_map *app = NULL;
    1996             : 
    1997           0 :         if (exact)
    1998           0 :                 *exact = 1;
    1999             : 
    2000           0 :         if (!map)
    2001           0 :                 return NULL;
    2002             : 
    2003           0 :         isl_assert(map->ctx,
    2004             :                 isl_map_dim(map, isl_dim_in) == isl_map_dim(map, isl_dim_out),
    2005             :                 goto error);
    2006             : 
    2007           0 :         app = construct_power(map, exact, project);
    2008             : 
    2009           0 :         isl_map_free(map);
    2010           0 :         return app;
    2011             : error:
    2012           0 :         isl_map_free(map);
    2013           0 :         isl_map_free(app);
    2014           0 :         return NULL;
    2015             : }
    2016             : 
    2017             : /* Compute the positive powers of "map", or an overapproximation.
    2018             :  * The result maps the exponent to a nested copy of the corresponding power.
    2019             :  * If the result is exact, then *exact is set to 1.
    2020             :  * map_power constructs an extended relation with the path lengths
    2021             :  * encoded as the difference between the final coordinates.
    2022             :  * In the final step, this difference is equated to an extra parameter
    2023             :  * and made positive.  The extra coordinates are subsequently projected out
    2024             :  * and the parameter is turned into the domain of the result.
    2025             :  */
    2026           0 : __isl_give isl_map *isl_map_power(__isl_take isl_map *map, int *exact)
    2027             : {
    2028             :         isl_space *target_dim;
    2029             :         isl_space *dim;
    2030             :         isl_map *diff;
    2031             :         unsigned d;
    2032             :         unsigned param;
    2033             : 
    2034           0 :         if (!map)
    2035           0 :                 return NULL;
    2036             : 
    2037           0 :         d = isl_map_dim(map, isl_dim_in);
    2038           0 :         param = isl_map_dim(map, isl_dim_param);
    2039             : 
    2040           0 :         map = isl_map_compute_divs(map);
    2041           0 :         map = isl_map_coalesce(map);
    2042             : 
    2043           0 :         if (isl_map_plain_is_empty(map)) {
    2044           0 :                 map = isl_map_from_range(isl_map_wrap(map));
    2045           0 :                 map = isl_map_add_dims(map, isl_dim_in, 1);
    2046           0 :                 map = isl_map_set_dim_name(map, isl_dim_in, 0, "k");
    2047           0 :                 return map;
    2048             :         }
    2049             : 
    2050           0 :         target_dim = isl_map_get_space(map);
    2051           0 :         target_dim = isl_space_from_range(isl_space_wrap(target_dim));
    2052           0 :         target_dim = isl_space_add_dims(target_dim, isl_dim_in, 1);
    2053           0 :         target_dim = isl_space_set_dim_name(target_dim, isl_dim_in, 0, "k");
    2054             : 
    2055           0 :         map = map_power(map, exact, 0);
    2056             : 
    2057           0 :         map = isl_map_add_dims(map, isl_dim_param, 1);
    2058           0 :         dim = isl_map_get_space(map);
    2059           0 :         diff = equate_parameter_to_length(dim, param);
    2060           0 :         map = isl_map_intersect(map, diff);
    2061           0 :         map = isl_map_project_out(map, isl_dim_in, d, 1);
    2062           0 :         map = isl_map_project_out(map, isl_dim_out, d, 1);
    2063           0 :         map = isl_map_from_range(isl_map_wrap(map));
    2064           0 :         map = isl_map_move_dims(map, isl_dim_in, 0, isl_dim_param, param, 1);
    2065             : 
    2066           0 :         map = isl_map_reset_space(map, target_dim);
    2067             : 
    2068           0 :         return map;
    2069             : }
    2070             : 
    2071             : /* Compute a relation that maps each element in the range of the input
    2072             :  * relation to the lengths of all paths composed of edges in the input
    2073             :  * relation that end up in the given range element.
    2074             :  * The result may be an overapproximation, in which case *exact is set to 0.
    2075             :  * The resulting relation is very similar to the power relation.
    2076             :  * The difference are that the domain has been projected out, the
    2077             :  * range has become the domain and the exponent is the range instead
    2078             :  * of a parameter.
    2079             :  */
    2080           0 : __isl_give isl_map *isl_map_reaching_path_lengths(__isl_take isl_map *map,
    2081             :         int *exact)
    2082             : {
    2083             :         isl_space *dim;
    2084             :         isl_map *diff;
    2085             :         unsigned d;
    2086             :         unsigned param;
    2087             : 
    2088           0 :         if (!map)
    2089           0 :                 return NULL;
    2090             : 
    2091           0 :         d = isl_map_dim(map, isl_dim_in);
    2092           0 :         param = isl_map_dim(map, isl_dim_param);
    2093             : 
    2094           0 :         map = isl_map_compute_divs(map);
    2095           0 :         map = isl_map_coalesce(map);
    2096             : 
    2097           0 :         if (isl_map_plain_is_empty(map)) {
    2098           0 :                 if (exact)
    2099           0 :                         *exact = 1;
    2100           0 :                 map = isl_map_project_out(map, isl_dim_out, 0, d);
    2101           0 :                 map = isl_map_add_dims(map, isl_dim_out, 1);
    2102           0 :                 return map;
    2103             :         }
    2104             : 
    2105           0 :         map = map_power(map, exact, 0);
    2106             : 
    2107           0 :         map = isl_map_add_dims(map, isl_dim_param, 1);
    2108           0 :         dim = isl_map_get_space(map);
    2109           0 :         diff = equate_parameter_to_length(dim, param);
    2110           0 :         map = isl_map_intersect(map, diff);
    2111           0 :         map = isl_map_project_out(map, isl_dim_in, 0, d + 1);
    2112           0 :         map = isl_map_project_out(map, isl_dim_out, d, 1);
    2113           0 :         map = isl_map_reverse(map);
    2114           0 :         map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_param, param, 1);
    2115             : 
    2116           0 :         return map;
    2117             : }
    2118             : 
    2119             : /* Given a map, compute the smallest superset of this map that is of the form
    2120             :  *
    2121             :  *      { i -> j : L <= j - i <= U and exists a_p: j_p - i_p = M_p a_p }
    2122             :  *
    2123             :  * (where p ranges over the (non-parametric) dimensions),
    2124             :  * compute the transitive closure of this map, i.e.,
    2125             :  *
    2126             :  *      { i -> j : exists k > 0:
    2127             :  *              k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p }
    2128             :  *
    2129             :  * and intersect domain and range of this transitive closure with
    2130             :  * the given domain and range.
    2131             :  *
    2132             :  * If with_id is set, then try to include as much of the identity mapping
    2133             :  * as possible, by computing
    2134             :  *
    2135             :  *      { i -> j : exists k >= 0:
    2136             :  *              k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p }
    2137             :  *
    2138             :  * instead (i.e., allow k = 0).
    2139             :  *
    2140             :  * In practice, we compute the difference set
    2141             :  *
    2142             :  *      delta  = { j - i | i -> j in map },
    2143             :  *
    2144             :  * look for stride constraint on the individual dimensions and compute
    2145             :  * (constant) lower and upper bounds for each individual dimension,
    2146             :  * adding a constraint for each bound not equal to infinity.
    2147             :  */
    2148           0 : static __isl_give isl_map *box_closure_on_domain(__isl_take isl_map *map,
    2149             :         __isl_take isl_set *dom, __isl_take isl_set *ran, int with_id)
    2150             : {
    2151             :         int i;
    2152             :         int k;
    2153             :         unsigned d;
    2154             :         unsigned nparam;
    2155             :         unsigned total;
    2156             :         isl_space *dim;
    2157             :         isl_set *delta;
    2158           0 :         isl_map *app = NULL;
    2159           0 :         isl_basic_set *aff = NULL;
    2160           0 :         isl_basic_map *bmap = NULL;
    2161           0 :         isl_vec *obj = NULL;
    2162             :         isl_int opt;
    2163             : 
    2164           0 :         isl_int_init(opt);
    2165             : 
    2166           0 :         delta = isl_map_deltas(isl_map_copy(map));
    2167             : 
    2168           0 :         aff = isl_set_affine_hull(isl_set_copy(delta));
    2169           0 :         if (!aff)
    2170           0 :                 goto error;
    2171           0 :         dim = isl_map_get_space(map);
    2172           0 :         d = isl_space_dim(dim, isl_dim_in);
    2173           0 :         nparam = isl_space_dim(dim, isl_dim_param);
    2174           0 :         total = isl_space_dim(dim, isl_dim_all);
    2175           0 :         bmap = isl_basic_map_alloc_space(dim,
    2176           0 :                                         aff->n_div + 1, aff->n_div, 2 * d + 1);
    2177           0 :         for (i = 0; i < aff->n_div + 1; ++i) {
    2178           0 :                 k = isl_basic_map_alloc_div(bmap);
    2179           0 :                 if (k < 0)
    2180           0 :                         goto error;
    2181           0 :                 isl_int_set_si(bmap->div[k][0], 0);
    2182             :         }
    2183           0 :         for (i = 0; i < aff->n_eq; ++i) {
    2184           0 :                 if (!isl_basic_set_eq_is_stride(aff, i))
    2185           0 :                         continue;
    2186           0 :                 k = isl_basic_map_alloc_equality(bmap);
    2187           0 :                 if (k < 0)
    2188           0 :                         goto error;
    2189           0 :                 isl_seq_clr(bmap->eq[k], 1 + nparam);
    2190           0 :                 isl_seq_cpy(bmap->eq[k] + 1 + nparam + d,
    2191           0 :                                 aff->eq[i] + 1 + nparam, d);
    2192           0 :                 isl_seq_neg(bmap->eq[k] + 1 + nparam,
    2193           0 :                                 aff->eq[i] + 1 + nparam, d);
    2194           0 :                 isl_seq_cpy(bmap->eq[k] + 1 + nparam + 2 * d,
    2195           0 :                                 aff->eq[i] + 1 + nparam + d, aff->n_div);
    2196           0 :                 isl_int_set_si(bmap->eq[k][1 + total + aff->n_div], 0);
    2197             :         }
    2198           0 :         obj = isl_vec_alloc(map->ctx, 1 + nparam + d);
    2199           0 :         if (!obj)
    2200           0 :                 goto error;
    2201           0 :         isl_seq_clr(obj->el, 1 + nparam + d);
    2202           0 :         for (i = 0; i < d; ++ i) {
    2203             :                 enum isl_lp_result res;
    2204             : 
    2205           0 :                 isl_int_set_si(obj->el[1 + nparam + i], 1);
    2206             : 
    2207           0 :                 res = isl_set_solve_lp(delta, 0, obj->el, map->ctx->one, &opt,
    2208             :                                         NULL, NULL);
    2209           0 :                 if (res == isl_lp_error)
    2210           0 :                         goto error;
    2211           0 :                 if (res == isl_lp_ok) {
    2212           0 :                         k = isl_basic_map_alloc_inequality(bmap);
    2213           0 :                         if (k < 0)
    2214           0 :                                 goto error;
    2215           0 :                         isl_seq_clr(bmap->ineq[k],
    2216           0 :                                         1 + nparam + 2 * d + bmap->n_div);
    2217           0 :                         isl_int_set_si(bmap->ineq[k][1 + nparam + i], -1);
    2218           0 :                         isl_int_set_si(bmap->ineq[k][1 + nparam + d + i], 1);
    2219           0 :                         isl_int_neg(bmap->ineq[k][1 + nparam + 2 * d + aff->n_div], opt);
    2220             :                 }
    2221             : 
    2222           0 :                 res = isl_set_solve_lp(delta, 1, obj->el, map->ctx->one, &opt,
    2223             :                                         NULL, NULL);
    2224           0 :                 if (res == isl_lp_error)
    2225           0 :                         goto error;
    2226           0 :                 if (res == isl_lp_ok) {
    2227           0 :                         k = isl_basic_map_alloc_inequality(bmap);
    2228           0 :                         if (k < 0)
    2229           0 :                                 goto error;
    2230           0 :                         isl_seq_clr(bmap->ineq[k],
    2231           0 :                                         1 + nparam + 2 * d + bmap->n_div);
    2232           0 :                         isl_int_set_si(bmap->ineq[k][1 + nparam + i], 1);
    2233           0 :                         isl_int_set_si(bmap->ineq[k][1 + nparam + d + i], -1);
    2234           0 :                         isl_int_set(bmap->ineq[k][1 + nparam + 2 * d + aff->n_div], opt);
    2235             :                 }
    2236             : 
    2237           0 :                 isl_int_set_si(obj->el[1 + nparam + i], 0);
    2238             :         }
    2239           0 :         k = isl_basic_map_alloc_inequality(bmap);
    2240           0 :         if (k < 0)
    2241           0 :                 goto error;
    2242           0 :         isl_seq_clr(bmap->ineq[k],
    2243           0 :                         1 + nparam + 2 * d + bmap->n_div);
    2244           0 :         if (!with_id)
    2245           0 :                 isl_int_set_si(bmap->ineq[k][0], -1);
    2246           0 :         isl_int_set_si(bmap->ineq[k][1 + nparam + 2 * d + aff->n_div], 1);
    2247             : 
    2248           0 :         app = isl_map_from_domain_and_range(dom, ran);
    2249             : 
    2250           0 :         isl_vec_free(obj);
    2251           0 :         isl_basic_set_free(aff);
    2252           0 :         isl_map_free(map);
    2253           0 :         bmap = isl_basic_map_finalize(bmap);
    2254           0 :         isl_set_free(delta);
    2255           0 :         isl_int_clear(opt);
    2256             : 
    2257           0 :         map = isl_map_from_basic_map(bmap);
    2258           0 :         map = isl_map_intersect(map, app);
    2259             : 
    2260           0 :         return map;
    2261             : error:
    2262           0 :         isl_vec_free(obj);
    2263           0 :         isl_basic_map_free(bmap);
    2264           0 :         isl_basic_set_free(aff);
    2265           0 :         isl_set_free(dom);
    2266           0 :         isl_set_free(ran);
    2267           0 :         isl_map_free(map);
    2268           0 :         isl_set_free(delta);
    2269           0 :         isl_int_clear(opt);
    2270           0 :         return NULL;
    2271             : }
    2272             : 
    2273             : /* Given a map, compute the smallest superset of this map that is of the form
    2274             :  *
    2275             :  *      { i -> j : L <= j - i <= U and exists a_p: j_p - i_p = M_p a_p }
    2276             :  *
    2277             :  * (where p ranges over the (non-parametric) dimensions),
    2278             :  * compute the transitive closure of this map, i.e.,
    2279             :  *
    2280             :  *      { i -> j : exists k > 0:
    2281             :  *              k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p }
    2282             :  *
    2283             :  * and intersect domain and range of this transitive closure with
    2284             :  * domain and range of the original map.
    2285             :  */
    2286           0 : static __isl_give isl_map *box_closure(__isl_take isl_map *map)
    2287             : {
    2288             :         isl_set *domain;
    2289             :         isl_set *range;
    2290             : 
    2291           0 :         domain = isl_map_domain(isl_map_copy(map));
    2292           0 :         domain = isl_set_coalesce(domain);
    2293           0 :         range = isl_map_range(isl_map_copy(map));
    2294           0 :         range = isl_set_coalesce(range);
    2295             : 
    2296           0 :         return box_closure_on_domain(map, domain, range, 0);
    2297             : }
    2298             : 
    2299             : /* Given a map, compute the smallest superset of this map that is of the form
    2300             :  *
    2301             :  *      { i -> j : L <= j - i <= U and exists a_p: j_p - i_p = M_p a_p }
    2302             :  *
    2303             :  * (where p ranges over the (non-parametric) dimensions),
    2304             :  * compute the transitive and partially reflexive closure of this map, i.e.,
    2305             :  *
    2306             :  *      { i -> j : exists k >= 0:
    2307             :  *              k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p }
    2308             :  *
    2309             :  * and intersect domain and range of this transitive closure with
    2310             :  * the given domain.
    2311             :  */
    2312           0 : static __isl_give isl_map *box_closure_with_identity(__isl_take isl_map *map,
    2313             :         __isl_take isl_set *dom)
    2314             : {
    2315           0 :         return box_closure_on_domain(map, dom, isl_set_copy(dom), 1);
    2316             : }
    2317             : 
    2318             : /* Check whether app is the transitive closure of map.
    2319             :  * In particular, check that app is acyclic and, if so,
    2320             :  * check that
    2321             :  *
    2322             :  *      app \subset (map \cup (map \circ app))
    2323             :  */
    2324           0 : static int check_exactness_omega(__isl_keep isl_map *map,
    2325             :         __isl_keep isl_map *app)
    2326             : {
    2327             :         isl_set *delta;
    2328             :         int i;
    2329             :         int is_empty, is_exact;
    2330             :         unsigned d;
    2331             :         isl_map *test;
    2332             : 
    2333           0 :         delta = isl_map_deltas(isl_map_copy(app));
    2334           0 :         d = isl_set_dim(delta, isl_dim_set);
    2335           0 :         for (i = 0; i < d; ++i)
    2336           0 :                 delta = isl_set_fix_si(delta, isl_dim_set, i, 0);
    2337           0 :         is_empty = isl_set_is_empty(delta);
    2338           0 :         isl_set_free(delta);
    2339           0 :         if (is_empty < 0)
    2340           0 :                 return -1;
    2341           0 :         if (!is_empty)
    2342           0 :                 return 0;
    2343             : 
    2344           0 :         test = isl_map_apply_range(isl_map_copy(app), isl_map_copy(map));
    2345           0 :         test = isl_map_union(test, isl_map_copy(map));
    2346           0 :         is_exact = isl_map_is_subset(app, test);
    2347           0 :         isl_map_free(test);
    2348             : 
    2349           0 :         return is_exact;
    2350             : }
    2351             : 
    2352             : /* Check if basic map M_i can be combined with all the other
    2353             :  * basic maps such that
    2354             :  *
    2355             :  *      (\cup_j M_j)^+
    2356             :  *
    2357             :  * can be computed as
    2358             :  *
    2359             :  *      M_i \cup (\cup_{j \ne i} M_i^* \circ M_j \circ M_i^*)^+
    2360             :  *
    2361             :  * In particular, check if we can compute a compact representation
    2362             :  * of
    2363             :  *
    2364             :  *              M_i^* \circ M_j \circ M_i^*
    2365             :  *
    2366             :  * for each j != i.
    2367             :  * Let M_i^? be an extension of M_i^+ that allows paths
    2368             :  * of length zero, i.e., the result of box_closure(., 1).
    2369             :  * The criterion, as proposed by Kelly et al., is that
    2370             :  * id = M_i^? - M_i^+ can be represented as a basic map
    2371             :  * and that
    2372             :  *
    2373             :  *      id \circ M_j \circ id = M_j
    2374             :  *
    2375             :  * for each j != i.
    2376             :  *
    2377             :  * If this function returns 1, then tc and qc are set to
    2378             :  * M_i^+ and M_i^?, respectively.
    2379             :  */
    2380           0 : static int can_be_split_off(__isl_keep isl_map *map, int i,
    2381             :         __isl_give isl_map **tc, __isl_give isl_map **qc)
    2382             : {
    2383           0 :         isl_map *map_i, *id = NULL;
    2384           0 :         int j = -1;
    2385             :         isl_set *C;
    2386             : 
    2387           0 :         *tc = NULL;
    2388           0 :         *qc = NULL;
    2389             : 
    2390           0 :         C = isl_set_union(isl_map_domain(isl_map_copy(map)),
    2391             :                           isl_map_range(isl_map_copy(map)));
    2392           0 :         C = isl_set_from_basic_set(isl_set_simple_hull(C));
    2393           0 :         if (!C)
    2394           0 :                 goto error;
    2395             : 
    2396           0 :         map_i = isl_map_from_basic_map(isl_basic_map_copy(map->p[i]));
    2397           0 :         *tc = box_closure(isl_map_copy(map_i));
    2398           0 :         *qc = box_closure_with_identity(map_i, C);
    2399           0 :         id = isl_map_subtract(isl_map_copy(*qc), isl_map_copy(*tc));
    2400             : 
    2401           0 :         if (!id || !*qc)
    2402             :                 goto error;
    2403           0 :         if (id->n != 1 || (*qc)->n != 1)
    2404             :                 goto done;
    2405             : 
    2406           0 :         for (j = 0; j < map->n; ++j) {
    2407             :                 isl_map *map_j, *test;
    2408             :                 int is_ok;
    2409             : 
    2410           0 :                 if (i == j)
    2411           0 :                         continue;
    2412           0 :                 map_j = isl_map_from_basic_map(
    2413           0 :                                         isl_basic_map_copy(map->p[j]));
    2414           0 :                 test = isl_map_apply_range(isl_map_copy(id),
    2415             :                                                 isl_map_copy(map_j));
    2416           0 :                 test = isl_map_apply_range(test, isl_map_copy(id));
    2417           0 :                 is_ok = isl_map_is_equal(test, map_j);
    2418           0 :                 isl_map_free(map_j);
    2419           0 :                 isl_map_free(test);
    2420           0 :                 if (is_ok < 0)
    2421           0 :                         goto error;
    2422           0 :                 if (!is_ok)
    2423           0 :                         break;
    2424             :         }
    2425             : 
    2426             : done:
    2427           0 :         isl_map_free(id);
    2428           0 :         if (j == map->n)
    2429           0 :                 return 1;
    2430             : 
    2431           0 :         isl_map_free(*qc);
    2432           0 :         isl_map_free(*tc);
    2433           0 :         *qc = NULL;
    2434           0 :         *tc = NULL;
    2435             : 
    2436           0 :         return 0;
    2437             : error:
    2438           0 :         isl_map_free(id);
    2439           0 :         isl_map_free(*qc);
    2440           0 :         isl_map_free(*tc);
    2441           0 :         *qc = NULL;
    2442           0 :         *tc = NULL;
    2443           0 :         return -1;
    2444             : }
    2445             : 
    2446           0 : static __isl_give isl_map *box_closure_with_check(__isl_take isl_map *map,
    2447             :         int *exact)
    2448             : {
    2449             :         isl_map *app;
    2450             : 
    2451           0 :         app = box_closure(isl_map_copy(map));
    2452           0 :         if (exact)
    2453           0 :                 *exact = check_exactness_omega(map, app);
    2454             : 
    2455           0 :         isl_map_free(map);
    2456           0 :         return app;
    2457             : }
    2458             : 
    2459             : /* Compute an overapproximation of the transitive closure of "map"
    2460             :  * using a variation of the algorithm from
    2461             :  * "Transitive Closure of Infinite Graphs and its Applications"
    2462             :  * by Kelly et al.
    2463             :  *
    2464             :  * We first check whether we can can split of any basic map M_i and
    2465             :  * compute
    2466             :  *
    2467             :  *      (\cup_j M_j)^+
    2468             :  *
    2469             :  * as
    2470             :  *
    2471             :  *      M_i \cup (\cup_{j \ne i} M_i^* \circ M_j \circ M_i^*)^+
    2472             :  *
    2473             :  * using a recursive call on the remaining map.
    2474             :  *
    2475             :  * If not, we simply call box_closure on the whole map.
    2476             :  */
    2477           0 : static __isl_give isl_map *transitive_closure_omega(__isl_take isl_map *map,
    2478             :         int *exact)
    2479             : {
    2480             :         int i, j;
    2481             :         int exact_i;
    2482             :         isl_map *app;
    2483             : 
    2484           0 :         if (!map)
    2485           0 :                 return NULL;
    2486           0 :         if (map->n == 1)
    2487           0 :                 return box_closure_with_check(map, exact);
    2488             : 
    2489           0 :         for (i = 0; i < map->n; ++i) {
    2490             :                 int ok;
    2491             :                 isl_map *qc, *tc;
    2492           0 :                 ok = can_be_split_off(map, i, &tc, &qc);
    2493           0 :                 if (ok < 0)
    2494           0 :                         goto error;
    2495           0 :                 if (!ok)
    2496           0 :                         continue;
    2497             : 
    2498           0 :                 app = isl_map_alloc_space(isl_map_get_space(map), map->n - 1, 0);
    2499             : 
    2500           0 :                 for (j = 0; j < map->n; ++j) {
    2501           0 :                         if (j == i)
    2502           0 :                                 continue;
    2503           0 :                         app = isl_map_add_basic_map(app,
    2504           0 :                                                 isl_basic_map_copy(map->p[j]));
    2505             :                 }
    2506             : 
    2507           0 :                 app = isl_map_apply_range(isl_map_copy(qc), app);
    2508           0 :                 app = isl_map_apply_range(app, qc);
    2509             : 
    2510           0 :                 app = isl_map_union(tc, transitive_closure_omega(app, NULL));
    2511           0 :                 exact_i = check_exactness_omega(map, app);
    2512           0 :                 if (exact_i == 1) {
    2513           0 :                         if (exact)
    2514           0 :                                 *exact = exact_i;
    2515           0 :                         isl_map_free(map);
    2516           0 :                         return app;
    2517             :                 }
    2518           0 :                 isl_map_free(app);
    2519           0 :                 if (exact_i < 0)
    2520           0 :                         goto error;
    2521             :         }
    2522             : 
    2523           0 :         return box_closure_with_check(map, exact);
    2524             : error:
    2525           0 :         isl_map_free(map);
    2526           0 :         return NULL;
    2527             : }
    2528             : 
    2529             : /* Compute the transitive closure  of "map", or an overapproximation.
    2530             :  * If the result is exact, then *exact is set to 1.
    2531             :  * Simply use map_power to compute the powers of map, but tell
    2532             :  * it to project out the lengths of the paths instead of equating
    2533             :  * the length to a parameter.
    2534             :  */
    2535           0 : __isl_give isl_map *isl_map_transitive_closure(__isl_take isl_map *map,
    2536             :         int *exact)
    2537             : {
    2538             :         isl_space *target_dim;
    2539             :         int closed;
    2540             : 
    2541           0 :         if (!map)
    2542           0 :                 goto error;
    2543             : 
    2544           0 :         if (map->ctx->opt->closure == ISL_CLOSURE_BOX)
    2545           0 :                 return transitive_closure_omega(map, exact);
    2546             : 
    2547           0 :         map = isl_map_compute_divs(map);
    2548           0 :         map = isl_map_coalesce(map);
    2549           0 :         closed = isl_map_is_transitively_closed(map);
    2550           0 :         if (closed < 0)
    2551           0 :                 goto error;
    2552           0 :         if (closed) {
    2553           0 :                 if (exact)
    2554           0 :                         *exact = 1;
    2555           0 :                 return map;
    2556             :         }
    2557             : 
    2558           0 :         target_dim = isl_map_get_space(map);
    2559           0 :         map = map_power(map, exact, 1);
    2560           0 :         map = isl_map_reset_space(map, target_dim);
    2561             : 
    2562           0 :         return map;
    2563             : error:
    2564           0 :         isl_map_free(map);
    2565           0 :         return NULL;
    2566             : }
    2567             : 
    2568           0 : static isl_stat inc_count(__isl_take isl_map *map, void *user)
    2569             : {
    2570           0 :         int *n = user;
    2571             : 
    2572           0 :         *n += map->n;
    2573             : 
    2574           0 :         isl_map_free(map);
    2575             : 
    2576           0 :         return isl_stat_ok;
    2577             : }
    2578             : 
    2579           0 : static isl_stat collect_basic_map(__isl_take isl_map *map, void *user)
    2580             : {
    2581             :         int i;
    2582           0 :         isl_basic_map ***next = user;
    2583             : 
    2584           0 :         for (i = 0; i < map->n; ++i) {
    2585           0 :                 **next = isl_basic_map_copy(map->p[i]);
    2586           0 :                 if (!**next)
    2587           0 :                         goto error;
    2588           0 :                 (*next)++;
    2589             :         }
    2590             : 
    2591           0 :         isl_map_free(map);
    2592           0 :         return isl_stat_ok;
    2593             : error:
    2594           0 :         isl_map_free(map);
    2595           0 :         return isl_stat_error;
    2596             : }
    2597             : 
    2598             : /* Perform Floyd-Warshall on the given list of basic relations.
    2599             :  * The basic relations may live in different dimensions,
    2600             :  * but basic relations that get assigned to the diagonal of the
    2601             :  * grid have domains and ranges of the same dimension and so
    2602             :  * the standard algorithm can be used because the nested transitive
    2603             :  * closures are only applied to diagonal elements and because all
    2604             :  * compositions are peformed on relations with compatible domains and ranges.
    2605             :  */
    2606           0 : static __isl_give isl_union_map *union_floyd_warshall_on_list(isl_ctx *ctx,
    2607             :         __isl_keep isl_basic_map **list, int n, int *exact)
    2608             : {
    2609             :         int i, j, k;
    2610             :         int n_group;
    2611           0 :         int *group = NULL;
    2612           0 :         isl_set **set = NULL;
    2613           0 :         isl_map ***grid = NULL;
    2614             :         isl_union_map *app;
    2615             : 
    2616           0 :         group = setup_groups(ctx, list, n, &set, &n_group);
    2617           0 :         if (!group)
    2618           0 :                 goto error;
    2619             : 
    2620           0 :         grid = isl_calloc_array(ctx, isl_map **, n_group);
    2621           0 :         if (!grid)
    2622           0 :                 goto error;
    2623           0 :         for (i = 0; i < n_group; ++i) {
    2624           0 :                 grid[i] = isl_calloc_array(ctx, isl_map *, n_group);
    2625           0 :                 if (!grid[i])
    2626           0 :                         goto error;
    2627           0 :                 for (j = 0; j < n_group; ++j) {
    2628             :                         isl_space *dim1, *dim2, *dim;
    2629           0 :                         dim1 = isl_space_reverse(isl_set_get_space(set[i]));
    2630           0 :                         dim2 = isl_set_get_space(set[j]);
    2631           0 :                         dim = isl_space_join(dim1, dim2);
    2632           0 :                         grid[i][j] = isl_map_empty(dim);
    2633             :                 }
    2634             :         }
    2635             : 
    2636           0 :         for (k = 0; k < n; ++k) {
    2637           0 :                 i = group[2 * k];
    2638           0 :                 j = group[2 * k + 1];
    2639           0 :                 grid[i][j] = isl_map_union(grid[i][j],
    2640             :                                 isl_map_from_basic_map(
    2641           0 :                                         isl_basic_map_copy(list[k])));
    2642             :         }
    2643             :         
    2644           0 :         floyd_warshall_iterate(grid, n_group, exact);
    2645             : 
    2646           0 :         app = isl_union_map_empty(isl_map_get_space(grid[0][0]));
    2647             : 
    2648           0 :         for (i = 0; i < n_group; ++i) {
    2649           0 :                 for (j = 0; j < n_group; ++j)
    2650           0 :                         app = isl_union_map_add_map(app, grid[i][j]);
    2651           0 :                 free(grid[i]);
    2652             :         }
    2653           0 :         free(grid);
    2654             : 
    2655           0 :         for (i = 0; i < 2 * n; ++i)
    2656           0 :                 isl_set_free(set[i]);
    2657           0 :         free(set);
    2658             : 
    2659           0 :         free(group);
    2660           0 :         return app;
    2661             : error:
    2662           0 :         if (grid)
    2663           0 :                 for (i = 0; i < n_group; ++i) {
    2664           0 :                         if (!grid[i])
    2665           0 :                                 continue;
    2666           0 :                         for (j = 0; j < n_group; ++j)
    2667           0 :                                 isl_map_free(grid[i][j]);
    2668           0 :                         free(grid[i]);
    2669             :                 }
    2670           0 :         free(grid);
    2671           0 :         if (set) {
    2672           0 :                 for (i = 0; i < 2 * n; ++i)
    2673           0 :                         isl_set_free(set[i]);
    2674           0 :                 free(set);
    2675             :         }
    2676           0 :         free(group);
    2677           0 :         return NULL;
    2678             : }
    2679             : 
    2680             : /* Perform Floyd-Warshall on the given union relation.
    2681             :  * The implementation is very similar to that for non-unions.
    2682             :  * The main difference is that it is applied unconditionally.
    2683             :  * We first extract a list of basic maps from the union map
    2684             :  * and then perform the algorithm on this list.
    2685             :  */
    2686           0 : static __isl_give isl_union_map *union_floyd_warshall(
    2687             :         __isl_take isl_union_map *umap, int *exact)
    2688             : {
    2689             :         int i, n;
    2690             :         isl_ctx *ctx;
    2691           0 :         isl_basic_map **list = NULL;
    2692             :         isl_basic_map **next;
    2693             :         isl_union_map *res;
    2694             : 
    2695           0 :         n = 0;
    2696           0 :         if (isl_union_map_foreach_map(umap, inc_count, &n) < 0)
    2697           0 :                 goto error;
    2698             : 
    2699           0 :         ctx = isl_union_map_get_ctx(umap);
    2700           0 :         list = isl_calloc_array(ctx, isl_basic_map *, n);
    2701           0 :         if (!list)
    2702           0 :                 goto error;
    2703             : 
    2704           0 :         next = list;
    2705           0 :         if (isl_union_map_foreach_map(umap, collect_basic_map, &next) < 0)
    2706           0 :                 goto error;
    2707             : 
    2708           0 :         res = union_floyd_warshall_on_list(ctx, list, n, exact);
    2709             : 
    2710           0 :         if (list) {
    2711           0 :                 for (i = 0; i < n; ++i)
    2712           0 :                         isl_basic_map_free(list[i]);
    2713           0 :                 free(list);
    2714             :         }
    2715             : 
    2716           0 :         isl_union_map_free(umap);
    2717           0 :         return res;
    2718             : error:
    2719           0 :         if (list) {
    2720           0 :                 for (i = 0; i < n; ++i)
    2721           0 :                         isl_basic_map_free(list[i]);
    2722           0 :                 free(list);
    2723             :         }
    2724           0 :         isl_union_map_free(umap);
    2725           0 :         return NULL;
    2726             : }
    2727             : 
    2728             : /* Decompose the give union relation into strongly connected components.
    2729             :  * The implementation is essentially the same as that of
    2730             :  * construct_power_components with the major difference that all
    2731             :  * operations are performed on union maps.
    2732             :  */
    2733           0 : static __isl_give isl_union_map *union_components(
    2734             :         __isl_take isl_union_map *umap, int *exact)
    2735             : {
    2736             :         int i;
    2737             :         int n;
    2738             :         isl_ctx *ctx;
    2739           0 :         isl_basic_map **list = NULL;
    2740             :         isl_basic_map **next;
    2741           0 :         isl_union_map *path = NULL;
    2742             :         struct isl_tc_follows_data data;
    2743           0 :         struct isl_tarjan_graph *g = NULL;
    2744             :         int c, l;
    2745           0 :         int recheck = 0;
    2746             : 
    2747           0 :         n = 0;
    2748           0 :         if (isl_union_map_foreach_map(umap, inc_count, &n) < 0)
    2749           0 :                 goto error;
    2750             : 
    2751           0 :         if (n == 0)
    2752           0 :                 return umap;
    2753           0 :         if (n <= 1)
    2754           0 :                 return union_floyd_warshall(umap, exact);
    2755             : 
    2756           0 :         ctx = isl_union_map_get_ctx(umap);
    2757           0 :         list = isl_calloc_array(ctx, isl_basic_map *, n);
    2758           0 :         if (!list)
    2759           0 :                 goto error;
    2760             : 
    2761           0 :         next = list;
    2762           0 :         if (isl_union_map_foreach_map(umap, collect_basic_map, &next) < 0)
    2763           0 :                 goto error;
    2764             : 
    2765           0 :         data.list = list;
    2766           0 :         data.check_closed = 0;
    2767           0 :         g = isl_tarjan_graph_init(ctx, n, &basic_map_follows, &data);
    2768           0 :         if (!g)
    2769           0 :                 goto error;
    2770             : 
    2771           0 :         c = 0;
    2772           0 :         i = 0;
    2773           0 :         l = n;
    2774           0 :         path = isl_union_map_empty(isl_union_map_get_space(umap));
    2775           0 :         while (l) {
    2776             :                 isl_union_map *comp;
    2777             :                 isl_union_map *path_comp, *path_comb;
    2778           0 :                 comp = isl_union_map_empty(isl_union_map_get_space(umap));
    2779           0 :                 while (g->order[i] != -1) {
    2780           0 :                         comp = isl_union_map_add_map(comp,
    2781             :                                     isl_map_from_basic_map(
    2782           0 :                                         isl_basic_map_copy(list[g->order[i]])));
    2783           0 :                         --l;
    2784           0 :                         ++i;
    2785             :                 }
    2786           0 :                 path_comp = union_floyd_warshall(comp, exact);
    2787           0 :                 path_comb = isl_union_map_apply_range(isl_union_map_copy(path),
    2788             :                                                 isl_union_map_copy(path_comp));
    2789           0 :                 path = isl_union_map_union(path, path_comp);
    2790           0 :                 path = isl_union_map_union(path, path_comb);
    2791           0 :                 ++i;
    2792           0 :                 ++c;
    2793             :         }
    2794             : 
    2795           0 :         if (c > 1 && data.check_closed && !*exact) {
    2796             :                 int closed;
    2797             : 
    2798           0 :                 closed = isl_union_map_is_transitively_closed(path);
    2799           0 :                 if (closed < 0)
    2800           0 :                         goto error;
    2801           0 :                 recheck = !closed;
    2802             :         }
    2803             : 
    2804           0 :         isl_tarjan_graph_free(g);
    2805             : 
    2806           0 :         for (i = 0; i < n; ++i)
    2807           0 :                 isl_basic_map_free(list[i]);
    2808           0 :         free(list);
    2809             : 
    2810           0 :         if (recheck) {
    2811           0 :                 isl_union_map_free(path);
    2812           0 :                 return union_floyd_warshall(umap, exact);
    2813             :         }
    2814             : 
    2815           0 :         isl_union_map_free(umap);
    2816             : 
    2817           0 :         return path;
    2818             : error:
    2819           0 :         isl_tarjan_graph_free(g);
    2820           0 :         if (list) {
    2821           0 :                 for (i = 0; i < n; ++i)
    2822           0 :                         isl_basic_map_free(list[i]);
    2823           0 :                 free(list);
    2824             :         }
    2825           0 :         isl_union_map_free(umap);
    2826           0 :         isl_union_map_free(path);
    2827           0 :         return NULL;
    2828             : }
    2829             : 
    2830             : /* Compute the transitive closure  of "umap", or an overapproximation.
    2831             :  * If the result is exact, then *exact is set to 1.
    2832             :  */
    2833           0 : __isl_give isl_union_map *isl_union_map_transitive_closure(
    2834             :         __isl_take isl_union_map *umap, int *exact)
    2835             : {
    2836             :         int closed;
    2837             : 
    2838           0 :         if (!umap)
    2839           0 :                 return NULL;
    2840             : 
    2841           0 :         if (exact)
    2842           0 :                 *exact = 1;
    2843             : 
    2844           0 :         umap = isl_union_map_compute_divs(umap);
    2845           0 :         umap = isl_union_map_coalesce(umap);
    2846           0 :         closed = isl_union_map_is_transitively_closed(umap);
    2847           0 :         if (closed < 0)
    2848           0 :                 goto error;
    2849           0 :         if (closed)
    2850           0 :                 return umap;
    2851           0 :         umap = union_components(umap, exact);
    2852           0 :         return umap;
    2853             : error:
    2854           0 :         isl_union_map_free(umap);
    2855           0 :         return NULL;
    2856             : }
    2857             : 
    2858             : struct isl_union_power {
    2859             :         isl_union_map *pow;
    2860             :         int *exact;
    2861             : };
    2862             : 
    2863           0 : static isl_stat power(__isl_take isl_map *map, void *user)
    2864             : {
    2865           0 :         struct isl_union_power *up = user;
    2866             : 
    2867           0 :         map = isl_map_power(map, up->exact);
    2868           0 :         up->pow = isl_union_map_from_map(map);
    2869             : 
    2870           0 :         return isl_stat_error;
    2871             : }
    2872             : 
    2873             : /* Construct a map [x] -> [x+1], with parameters prescribed by "dim".
    2874             :  */
    2875           0 : static __isl_give isl_union_map *increment(__isl_take isl_space *dim)
    2876             : {
    2877             :         int k;
    2878             :         isl_basic_map *bmap;
    2879             : 
    2880           0 :         dim = isl_space_add_dims(dim, isl_dim_in, 1);
    2881           0 :         dim = isl_space_add_dims(dim, isl_dim_out, 1);
    2882           0 :         bmap = isl_basic_map_alloc_space(dim, 0, 1, 0);
    2883           0 :         k = isl_basic_map_alloc_equality(bmap);
    2884           0 :         if (k < 0)
    2885           0 :                 goto error;
    2886           0 :         isl_seq_clr(bmap->eq[k], 1 + isl_basic_map_total_dim(bmap));
    2887           0 :         isl_int_set_si(bmap->eq[k][0], 1);
    2888           0 :         isl_int_set_si(bmap->eq[k][isl_basic_map_offset(bmap, isl_dim_in)], 1);
    2889           0 :         isl_int_set_si(bmap->eq[k][isl_basic_map_offset(bmap, isl_dim_out)], -1);
    2890           0 :         return isl_union_map_from_map(isl_map_from_basic_map(bmap));
    2891             : error:
    2892           0 :         isl_basic_map_free(bmap);
    2893           0 :         return NULL;
    2894             : }
    2895             : 
    2896             : /* Construct a map [[x]->[y]] -> [y-x], with parameters prescribed by "dim".
    2897             :  */
    2898           0 : static __isl_give isl_union_map *deltas_map(__isl_take isl_space *dim)
    2899             : {
    2900             :         isl_basic_map *bmap;
    2901             : 
    2902           0 :         dim = isl_space_add_dims(dim, isl_dim_in, 1);
    2903           0 :         dim = isl_space_add_dims(dim, isl_dim_out, 1);
    2904           0 :         bmap = isl_basic_map_universe(dim);
    2905           0 :         bmap = isl_basic_map_deltas_map(bmap);
    2906             : 
    2907           0 :         return isl_union_map_from_map(isl_map_from_basic_map(bmap));
    2908             : }
    2909             : 
    2910             : /* Compute the positive powers of "map", or an overapproximation.
    2911             :  * The result maps the exponent to a nested copy of the corresponding power.
    2912             :  * If the result is exact, then *exact is set to 1.
    2913             :  */
    2914           0 : __isl_give isl_union_map *isl_union_map_power(__isl_take isl_union_map *umap,
    2915             :         int *exact)
    2916             : {
    2917             :         int n;
    2918             :         isl_union_map *inc;
    2919             :         isl_union_map *dm;
    2920             : 
    2921           0 :         if (!umap)
    2922           0 :                 return NULL;
    2923           0 :         n = isl_union_map_n_map(umap);
    2924           0 :         if (n == 0)
    2925           0 :                 return umap;
    2926           0 :         if (n == 1) {
    2927           0 :                 struct isl_union_power up = { NULL, exact };
    2928           0 :                 isl_union_map_foreach_map(umap, &power, &up);
    2929           0 :                 isl_union_map_free(umap);
    2930           0 :                 return up.pow;
    2931             :         }
    2932           0 :         inc = increment(isl_union_map_get_space(umap));
    2933           0 :         umap = isl_union_map_product(inc, umap);
    2934           0 :         umap = isl_union_map_transitive_closure(umap, exact);
    2935           0 :         umap = isl_union_map_zip(umap);
    2936           0 :         dm = deltas_map(isl_union_map_get_space(umap));
    2937           0 :         umap = isl_union_map_apply_domain(umap, dm);
    2938             :         
    2939           0 :         return umap;
    2940             : }
    2941             : 
    2942             : #undef TYPE
    2943             : #define TYPE isl_map
    2944             : #include "isl_power_templ.c"
    2945             : 
    2946             : #undef TYPE
    2947             : #define TYPE isl_union_map
    2948             : #include "isl_power_templ.c"

Generated by: LCOV version 1.12