LCOV - code coverage report
Current view: top level - metalib_isl - isl_map_subtract.c (source / functions) Hit Total Coverage
Test: 2018-10-31_point_maint_greina16.lcov Lines: 319 483 66.0 %
Date: 2018-11-01 11:27:00 Functions: 23 31 74.2 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2008-2009 Katholieke Universiteit Leuven
       3             :  *
       4             :  * Use of this software is governed by the MIT license
       5             :  *
       6             :  * Written by Sven Verdoolaege, K.U.Leuven, Departement
       7             :  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
       8             :  */
       9             : 
      10             : #include <isl_map_private.h>
      11             : #include <isl_seq.h>
      12             : #include <isl/set.h>
      13             : #include <isl/map.h>
      14             : #include "isl_tab.h"
      15             : #include <isl_point_private.h>
      16             : #include <isl_vec_private.h>
      17             : 
      18             : #include <set_to_map.c>
      19             : #include <set_from_map.c>
      20             : 
      21             : /* Expand the constraint "c" into "v".  The initial "dim" dimensions
      22             :  * are the same, but "v" may have more divs than "c" and the divs of "c"
      23             :  * may appear in different positions in "v".
      24             :  * The number of divs in "c" is given by "n_div" and the mapping
      25             :  * of divs in "c" to divs in "v" is given by "div_map".
      26             :  *
      27             :  * Although it shouldn't happen in practice, it is theoretically
      28             :  * possible that two or more divs in "c" are mapped to the same div in "v".
      29             :  * These divs are then necessarily the same, so we simply add their
      30             :  * coefficients.
      31             :  */
      32  3824916907 : static void expand_constraint(isl_vec *v, unsigned dim,
      33             :         isl_int *c, int *div_map, unsigned n_div)
      34             : {
      35             :         int i;
      36             : 
      37  3824916907 :         isl_seq_cpy(v->el, c, 1 + dim);
      38  3824916907 :         isl_seq_clr(v->el + 1 + dim, v->size - (1 + dim));
      39             : 
      40  3824916907 :         for (i = 0; i < n_div; ++i) {
      41           0 :                 int pos = 1 + dim + div_map[i];
      42           0 :                 isl_int_add(v->el[pos], v->el[pos], c[1 + dim + i]);
      43             :         }
      44  3824916907 : }
      45             : 
      46             : /* Add all constraints of bmap to tab.  The equalities of bmap
      47             :  * are added as a pair of inequalities.
      48             :  */
      49   797159303 : static isl_stat tab_add_constraints(struct isl_tab *tab,
      50             :         __isl_keep isl_basic_map *bmap, int *div_map)
      51             : {
      52             :         int i;
      53             :         unsigned dim;
      54             :         unsigned tab_total;
      55             :         unsigned bmap_total;
      56             :         isl_vec *v;
      57             : 
      58   797159303 :         if (!tab || !bmap)
      59           0 :                 return isl_stat_error;
      60             : 
      61   797159303 :         tab_total = isl_basic_map_total_dim(tab->bmap);
      62   797159303 :         bmap_total = isl_basic_map_total_dim(bmap);
      63   797159303 :         dim = isl_space_dim(tab->bmap->dim, isl_dim_all);
      64             : 
      65   797159303 :         if (isl_tab_extend_cons(tab, 2 * bmap->n_eq + bmap->n_ineq) < 0)
      66           0 :                 return isl_stat_error;
      67             : 
      68   797159303 :         v = isl_vec_alloc(bmap->ctx, 1 + tab_total);
      69   797159303 :         if (!v)
      70           0 :                 return isl_stat_error;
      71             : 
      72  1133850690 :         for (i = 0; i < bmap->n_eq; ++i) {
      73   435551308 :                 expand_constraint(v, dim, bmap->eq[i], div_map, bmap->n_div);
      74   435551308 :                 if (isl_tab_add_ineq(tab, v->el) < 0)
      75           0 :                         goto error;
      76   435551308 :                 isl_seq_neg(bmap->eq[i], bmap->eq[i], 1 + bmap_total);
      77   435551308 :                 expand_constraint(v, dim, bmap->eq[i], div_map, bmap->n_div);
      78   435551308 :                 if (isl_tab_add_ineq(tab, v->el) < 0)
      79           0 :                         goto error;
      80   435551308 :                 isl_seq_neg(bmap->eq[i], bmap->eq[i], 1 + bmap_total);
      81   435551308 :                 if (tab->empty)
      82    98859921 :                         break;
      83             :         }
      84             : 
      85  2883341150 :         for (i = 0; i < bmap->n_ineq; ++i) {
      86  2832365489 :                 expand_constraint(v, dim, bmap->ineq[i], div_map, bmap->n_div);
      87  2832365489 :                 if (isl_tab_add_ineq(tab, v->el) < 0)
      88           0 :                         goto error;
      89  2832365489 :                 if (tab->empty)
      90   746183642 :                         break;
      91             :         }
      92             : 
      93   797159303 :         isl_vec_free(v);
      94   797159303 :         return isl_stat_ok;
      95             : error:
      96           0 :         isl_vec_free(v);
      97           0 :         return isl_stat_error;
      98             : }
      99             : 
     100             : /* Add a specific constraint of bmap (or its opposite) to tab.
     101             :  * The position of the constraint is specified by "c", where
     102             :  * the equalities of bmap are counted twice, once for the inequality
     103             :  * that is equal to the equality, and once for its negation.
     104             :  *
     105             :  * Each of these constraints has been added to "tab" before by
     106             :  * tab_add_constraints (and later removed again), so there should
     107             :  * already be a row available for the constraint.
     108             :  */
     109   121448802 : static isl_stat tab_add_constraint(struct isl_tab *tab,
     110             :         __isl_keep isl_basic_map *bmap, int *div_map, int c, int oppose)
     111             : {
     112             :         unsigned dim;
     113             :         unsigned tab_total;
     114             :         unsigned bmap_total;
     115             :         isl_vec *v;
     116             :         isl_stat r;
     117             : 
     118   121448802 :         if (!tab || !bmap)
     119           0 :                 return isl_stat_error;
     120             : 
     121   121448802 :         tab_total = isl_basic_map_total_dim(tab->bmap);
     122   121448802 :         bmap_total = isl_basic_map_total_dim(bmap);
     123   121448802 :         dim = isl_space_dim(tab->bmap->dim, isl_dim_all);
     124             : 
     125   121448802 :         v = isl_vec_alloc(bmap->ctx, 1 + tab_total);
     126   121448802 :         if (!v)
     127           0 :                 return isl_stat_error;
     128             : 
     129   121448802 :         if (c < 2 * bmap->n_eq) {
     130    15568828 :                 if ((c % 2) != oppose)
     131     7735024 :                         isl_seq_neg(bmap->eq[c/2], bmap->eq[c/2],
     132             :                                         1 + bmap_total);
     133    15568828 :                 if (oppose)
     134     7908814 :                         isl_int_sub_ui(bmap->eq[c/2][0], bmap->eq[c/2][0], 1);
     135    15568828 :                 expand_constraint(v, dim, bmap->eq[c/2], div_map, bmap->n_div);
     136    15568828 :                 r = isl_tab_add_ineq(tab, v->el);
     137    15568828 :                 if (oppose)
     138     7908814 :                         isl_int_add_ui(bmap->eq[c/2][0], bmap->eq[c/2][0], 1);
     139    15568828 :                 if ((c % 2) != oppose)
     140     7735024 :                         isl_seq_neg(bmap->eq[c/2], bmap->eq[c/2],
     141             :                                         1 + bmap_total);
     142             :         } else {
     143   105879974 :                 c -= 2 * bmap->n_eq;
     144   105879974 :                 if (oppose) {
     145    67892477 :                         isl_seq_neg(bmap->ineq[c], bmap->ineq[c],
     146             :                                         1 + bmap_total);
     147    67892477 :                         isl_int_sub_ui(bmap->ineq[c][0], bmap->ineq[c][0], 1);
     148             :                 }
     149   105879974 :                 expand_constraint(v, dim, bmap->ineq[c], div_map, bmap->n_div);
     150   105879974 :                 r = isl_tab_add_ineq(tab, v->el);
     151   105879974 :                 if (oppose) {
     152    67892477 :                         isl_int_add_ui(bmap->ineq[c][0], bmap->ineq[c][0], 1);
     153    67892477 :                         isl_seq_neg(bmap->ineq[c], bmap->ineq[c],
     154             :                                         1 + bmap_total);
     155             :                 }
     156             :         }
     157             : 
     158   121448802 :         isl_vec_free(v);
     159   121448802 :         return r;
     160             : }
     161             : 
     162   797159303 : static isl_stat tab_add_divs(struct isl_tab *tab,
     163             :         __isl_keep isl_basic_map *bmap, int **div_map)
     164             : {
     165             :         int i, j;
     166             :         struct isl_vec *vec;
     167             :         unsigned total;
     168             :         unsigned dim;
     169             : 
     170   797159303 :         if (!bmap)
     171           0 :                 return isl_stat_error;
     172   797159303 :         if (!bmap->n_div)
     173   797159303 :                 return isl_stat_ok;
     174             : 
     175           0 :         if (!*div_map)
     176           0 :                 *div_map = isl_alloc_array(bmap->ctx, int, bmap->n_div);
     177           0 :         if (!*div_map)
     178           0 :                 return isl_stat_error;
     179             : 
     180           0 :         total = isl_basic_map_total_dim(tab->bmap);
     181           0 :         dim = total - tab->bmap->n_div;
     182           0 :         vec = isl_vec_alloc(bmap->ctx, 2 + total + bmap->n_div);
     183           0 :         if (!vec)
     184           0 :                 return isl_stat_error;
     185             : 
     186           0 :         for (i = 0; i < bmap->n_div; ++i) {
     187           0 :                 isl_seq_cpy(vec->el, bmap->div[i], 2 + dim);
     188           0 :                 isl_seq_clr(vec->el + 2 + dim, tab->bmap->n_div);
     189           0 :                 for (j = 0; j < i; ++j)
     190           0 :                         isl_int_add(vec->el[2 + dim + (*div_map)[j]],
     191             :                                     vec->el[2 + dim + (*div_map)[j]],
     192             :                                         bmap->div[i][2 + dim + j]);
     193           0 :                 for (j = 0; j < tab->bmap->n_div; ++j)
     194           0 :                         if (isl_seq_eq(tab->bmap->div[j],
     195           0 :                                         vec->el, 2 + dim + tab->bmap->n_div))
     196           0 :                                 break;
     197           0 :                 (*div_map)[i] = j;
     198           0 :                 if (j == tab->bmap->n_div) {
     199           0 :                         vec->size = 2 + dim + tab->bmap->n_div;
     200           0 :                         if (isl_tab_add_div(tab, vec) < 0)
     201           0 :                                 goto error;
     202             :                 }
     203             :         }
     204             : 
     205           0 :         isl_vec_free(vec);
     206             : 
     207           0 :         return isl_stat_ok;
     208             : error:
     209           0 :         isl_vec_free(vec);
     210             : 
     211           0 :         return isl_stat_error;
     212             : }
     213             : 
     214             : /* Freeze all constraints of tableau tab.
     215             :  */
     216   797159303 : static int tab_freeze_constraints(struct isl_tab *tab)
     217             : {
     218             :         int i;
     219             : 
     220 11695161270 :         for (i = 0; i < tab->n_con; ++i)
     221 10898001967 :                 if (isl_tab_freeze_constraint(tab, i) < 0)
     222           0 :                         return -1;
     223             : 
     224   797159303 :         return 0;
     225             : }
     226             : 
     227             : /* Check for redundant constraints starting at offset.
     228             :  * Put the indices of the redundant constraints in index
     229             :  * and return the number of redundant constraints.
     230             :  */
     231    48109176 : static int n_non_redundant(isl_ctx *ctx, struct isl_tab *tab,
     232             :         int offset, int **index)
     233             : {
     234             :         int i, n;
     235    48109176 :         int n_test = tab->n_con - offset;
     236             : 
     237    48109176 :         if (isl_tab_detect_redundant(tab) < 0)
     238           0 :                 return -1;
     239             : 
     240    48109176 :         if (n_test == 0)
     241      252315 :                 return 0;
     242    47856861 :         if (!*index)
     243    30878784 :                 *index = isl_alloc_array(ctx, int, n_test);
     244    47856861 :         if (!*index)
     245           0 :                 return -1;
     246             : 
     247   495286785 :         for (n = 0, i = 0; i < n_test; ++i) {
     248             :                 int r;
     249   447429924 :                 r = isl_tab_is_redundant(tab, offset + i);
     250   447429924 :                 if (r < 0)
     251           0 :                         return -1;
     252   447429924 :                 if (r)
     253   371628633 :                         continue;
     254    75801291 :                 (*index)[n++] = i;
     255             :         }
     256             : 
     257    47856861 :         return n;
     258             : }
     259             : 
     260             : /* basic_map_collect_diff calls add on each of the pieces of
     261             :  * the set difference between bmap and map until the add method
     262             :  * return a negative value.
     263             :  */
     264             : struct isl_diff_collector {
     265             :         isl_stat (*add)(struct isl_diff_collector *dc,
     266             :                     __isl_take isl_basic_map *bmap);
     267             : };
     268             : 
     269             : /* Compute the set difference between bmap and map and call
     270             :  * dc->add on each of the piece until this function returns
     271             :  * a negative value.
     272             :  * Return 0 on success and -1 on error.  dc->add returning
     273             :  * a negative value is treated as an error, but the calling
     274             :  * function can interpret the results based on the state of dc.
     275             :  *
     276             :  * Assumes that map has known divs.
     277             :  *
     278             :  * The difference is computed by a backtracking algorithm.
     279             :  * Each level corresponds to a basic map in "map".
     280             :  * When a node in entered for the first time, we check
     281             :  * if the corresonding basic map intersects the current piece
     282             :  * of "bmap".  If not, we move to the next level.
     283             :  * Otherwise, we split the current piece into as many
     284             :  * pieces as there are non-redundant constraints of the current
     285             :  * basic map in the intersection.  Each of these pieces is
     286             :  * handled by a child of the current node.
     287             :  * In particular, if there are n non-redundant constraints,
     288             :  * then for each 0 <= i < n, a piece is cut off by adding
     289             :  * constraints 0 <= j < i and adding the opposite of constraint i.
     290             :  * If there are no non-redundant constraints, meaning that the current
     291             :  * piece is a subset of the current basic map, then we simply backtrack.
     292             :  *
     293             :  * In the leaves, we check if the remaining piece has any integer points
     294             :  * and if so, pass it along to dc->add.  As a special case, if nothing
     295             :  * has been removed when we end up in a leaf, we simply pass along
     296             :  * the original basic map.
     297             :  */
     298    11827020 : static isl_stat basic_map_collect_diff(__isl_take isl_basic_map *bmap,
     299             :         __isl_take isl_map *map, struct isl_diff_collector *dc)
     300             : {
     301             :         int i;
     302             :         int modified;
     303             :         int level;
     304             :         int init;
     305             :         isl_bool empty;
     306             :         isl_ctx *ctx;
     307    11827020 :         struct isl_tab *tab = NULL;
     308    11827020 :         struct isl_tab_undo **snap = NULL;
     309    11827020 :         int *k = NULL;
     310    11827020 :         int *n = NULL;
     311    11827020 :         int **index = NULL;
     312    11827020 :         int **div_map = NULL;
     313             : 
     314    11827020 :         empty = isl_basic_map_is_empty(bmap);
     315    11827020 :         if (empty) {
     316           0 :                 isl_basic_map_free(bmap);
     317           0 :                 isl_map_free(map);
     318           0 :                 return empty < 0 ? isl_stat_error : isl_stat_ok;
     319             :         }
     320             : 
     321    11827020 :         bmap = isl_basic_map_cow(bmap);
     322    11827020 :         map = isl_map_cow(map);
     323             : 
     324    11827020 :         if (!bmap || !map)
     325             :                 goto error;
     326             : 
     327    11827020 :         ctx = map->ctx;
     328    11827020 :         snap = isl_alloc_array(map->ctx, struct isl_tab_undo *, map->n);
     329    11827020 :         k = isl_alloc_array(map->ctx, int, map->n);
     330    11827020 :         n = isl_alloc_array(map->ctx, int, map->n);
     331    11827020 :         index = isl_calloc_array(map->ctx, int *, map->n);
     332    11827020 :         div_map = isl_calloc_array(map->ctx, int *, map->n);
     333    11827020 :         if (!snap || !k || !n || !index || !div_map)
     334             :                 goto error;
     335             : 
     336    11827020 :         bmap = isl_basic_map_order_divs(bmap);
     337    11827020 :         map = isl_map_order_divs(map);
     338             : 
     339    11827020 :         tab = isl_tab_from_basic_map(bmap, 1);
     340    11827020 :         if (!tab)
     341           0 :                 goto error;
     342             : 
     343    11827020 :         modified = 0;
     344    11827020 :         level = 0;
     345    11827020 :         init = 1;
     346             : 
     347  1663607105 :         while (level >= 0) {
     348  1643065969 :                 if (level >= map->n) {
     349             :                         int empty;
     350             :                         struct isl_basic_map *bm;
     351    39519135 :                         if (!modified) {
     352     3112904 :                                 if (dc->add(dc, isl_basic_map_copy(bmap)) < 0)
     353           0 :                                         goto error;
     354     3112904 :                                 break;
     355             :                         }
     356    36406231 :                         bm = isl_basic_map_copy(tab->bmap);
     357    36406231 :                         bm = isl_basic_map_cow(bm);
     358    36406231 :                         bm = isl_basic_map_update_from_tab(bm, tab);
     359    36406231 :                         bm = isl_basic_map_simplify(bm);
     360    36406231 :                         bm = isl_basic_map_finalize(bm);
     361    36406231 :                         empty = isl_basic_map_is_empty(bm);
     362    36406231 :                         if (empty)
     363     1255890 :                                 isl_basic_map_free(bm);
     364    35150341 :                         else if (dc->add(dc, bm) < 0)
     365           0 :                                 goto error;
     366    36406231 :                         if (empty < 0)
     367           0 :                                 goto error;
     368    36406231 :                         level--;
     369    36406231 :                         init = 0;
     370    36406231 :                         continue;
     371             :                 }
     372  1603546834 :                 if (init) {
     373             :                         int offset;
     374             :                         struct isl_tab_undo *snap2;
     375   797159303 :                         snap2 = isl_tab_snap(tab);
     376  1594318606 :                         if (tab_add_divs(tab, map->p[level],
     377   797159303 :                                          &div_map[level]) < 0)
     378           0 :                                 goto error;
     379   797159303 :                         offset = tab->n_con;
     380   797159303 :                         snap[level] = isl_tab_snap(tab);
     381   797159303 :                         if (tab_freeze_constraints(tab) < 0)
     382           0 :                                 goto error;
     383   797159303 :                         if (tab_add_constraints(tab, map->p[level],
     384   797159303 :                                                 div_map[level]) < 0)
     385           0 :                                 goto error;
     386   797159303 :                         k[level] = 0;
     387   797159303 :                         n[level] = 0;
     388   797159303 :                         if (tab->empty) {
     389   749050127 :                                 if (isl_tab_rollback(tab, snap2) < 0)
     390           0 :                                         goto error;
     391   749050127 :                                 level++;
     392   749050127 :                                 continue;
     393             :                         }
     394    48109176 :                         modified = 1;
     395    96218352 :                         n[level] = n_non_redundant(ctx, tab, offset,
     396    48109176 :                                                     &index[level]);
     397    48109176 :                         if (n[level] < 0)
     398           0 :                                 goto error;
     399    48109176 :                         if (n[level] == 0) {
     400    17955396 :                                 level--;
     401    17955396 :                                 init = 0;
     402    17955396 :                                 continue;
     403             :                         }
     404    30153780 :                         if (isl_tab_rollback(tab, snap[level]) < 0)
     405           0 :                                 goto error;
     406    60307560 :                         if (tab_add_constraint(tab, map->p[level],
     407    60307560 :                                         div_map[level], index[level][0], 1) < 0)
     408           0 :                                 goto error;
     409    30153780 :                         level++;
     410    30153780 :                         continue;
     411             :                 } else {
     412   806387531 :                         if (k[level] + 1 >= n[level]) {
     413   760740020 :                                 level--;
     414   760740020 :                                 continue;
     415             :                         }
     416    45647511 :                         if (isl_tab_rollback(tab, snap[level]) < 0)
     417           0 :                                 goto error;
     418    91295022 :                         if (tab_add_constraint(tab, map->p[level],
     419    45647511 :                                                 div_map[level],
     420    45647511 :                                                 index[level][k[level]], 0) < 0)
     421           0 :                                 goto error;
     422    45647511 :                         snap[level] = isl_tab_snap(tab);
     423    45647511 :                         k[level]++;
     424    91295022 :                         if (tab_add_constraint(tab, map->p[level],
     425    45647511 :                                                 div_map[level],
     426    45647511 :                                                 index[level][k[level]], 1) < 0)
     427           0 :                                 goto error;
     428    45647511 :                         level++;
     429    45647511 :                         init = 1;
     430    45647511 :                         continue;
     431             :                 }
     432             :         }
     433             : 
     434    11827020 :         isl_tab_free(tab);
     435    11827020 :         free(snap);
     436    11827020 :         free(n);
     437    11827020 :         free(k);
     438   536370494 :         for (i = 0; index && i < map->n; ++i)
     439   524543474 :                 free(index[i]);
     440    11827020 :         free(index);
     441   536370494 :         for (i = 0; div_map && i < map->n; ++i)
     442   524543474 :                 free(div_map[i]);
     443    11827020 :         free(div_map);
     444             : 
     445    11827020 :         isl_basic_map_free(bmap);
     446    11827020 :         isl_map_free(map);
     447             : 
     448    11827020 :         return isl_stat_ok;
     449             : error:
     450           0 :         isl_tab_free(tab);
     451           0 :         free(snap);
     452           0 :         free(n);
     453           0 :         free(k);
     454           0 :         for (i = 0; index && i < map->n; ++i)
     455           0 :                 free(index[i]);
     456           0 :         free(index);
     457           0 :         for (i = 0; div_map && i < map->n; ++i)
     458           0 :                 free(div_map[i]);
     459           0 :         free(div_map);
     460           0 :         isl_basic_map_free(bmap);
     461           0 :         isl_map_free(map);
     462           0 :         return isl_stat_error;
     463             : }
     464             : 
     465             : /* A diff collector that actually collects all parts of the
     466             :  * set difference in the field diff.
     467             :  */
     468             : struct isl_subtract_diff_collector {
     469             :         struct isl_diff_collector dc;
     470             :         struct isl_map *diff;
     471             : };
     472             : 
     473             : /* isl_subtract_diff_collector callback.
     474             :  */
     475    38263245 : static isl_stat basic_map_subtract_add(struct isl_diff_collector *dc,
     476             :                             __isl_take isl_basic_map *bmap)
     477             : {
     478             :         struct isl_subtract_diff_collector *sdc;
     479    38263245 :         sdc = (struct isl_subtract_diff_collector *)dc;
     480             : 
     481    38263245 :         sdc->diff = isl_map_union_disjoint(sdc->diff,
     482             :                         isl_map_from_basic_map(bmap));
     483             : 
     484    38263245 :         return sdc->diff ? isl_stat_ok : isl_stat_error;
     485             : }
     486             : 
     487             : /* Return the set difference between bmap and map.
     488             :  */
     489     6879666 : static __isl_give isl_map *basic_map_subtract(__isl_take isl_basic_map *bmap,
     490             :         __isl_take isl_map *map)
     491             : {
     492             :         struct isl_subtract_diff_collector sdc;
     493     6879666 :         sdc.dc.add = &basic_map_subtract_add;
     494     6879666 :         sdc.diff = isl_map_empty(isl_basic_map_get_space(bmap));
     495     6879666 :         if (basic_map_collect_diff(bmap, map, &sdc.dc) < 0) {
     496           0 :                 isl_map_free(sdc.diff);
     497           0 :                 sdc.diff = NULL;
     498             :         }
     499     6879666 :         return sdc.diff;
     500             : }
     501             : 
     502             : /* Return an empty map living in the same space as "map1" and "map2".
     503             :  */
     504      301022 : static __isl_give isl_map *replace_pair_by_empty( __isl_take isl_map *map1,
     505             :         __isl_take isl_map *map2)
     506             : {
     507             :         isl_space *space;
     508             : 
     509      301022 :         space = isl_map_get_space(map1);
     510      301022 :         isl_map_free(map1);
     511      301022 :         isl_map_free(map2);
     512      301022 :         return isl_map_empty(space);
     513             : }
     514             : 
     515             : /* Return the set difference between map1 and map2.
     516             :  * (U_i A_i) \ (U_j B_j) is computed as U_i (A_i \ (U_j B_j))
     517             :  *
     518             :  * If "map1" and "map2" are obviously equal to each other,
     519             :  * then return an empty map in the same space.
     520             :  *
     521             :  * If "map1" and "map2" are disjoint, then simply return "map1".
     522             :  */
     523     3324703 : static __isl_give isl_map *map_subtract( __isl_take isl_map *map1,
     524             :         __isl_take isl_map *map2)
     525             : {
     526             :         int i;
     527             :         int equal, disjoint;
     528             :         struct isl_map *diff;
     529             : 
     530     3324703 :         if (!map1 || !map2)
     531             :                 goto error;
     532             : 
     533     3324703 :         isl_assert(map1->ctx, isl_space_is_equal(map1->dim, map2->dim), goto error);
     534             : 
     535     3324703 :         equal = isl_map_plain_is_equal(map1, map2);
     536     3324703 :         if (equal < 0)
     537           0 :                 goto error;
     538     3324703 :         if (equal)
     539      301022 :                 return replace_pair_by_empty(map1, map2);
     540             : 
     541     3023681 :         disjoint = isl_map_is_disjoint(map1, map2);
     542     3023681 :         if (disjoint < 0)
     543           0 :                 goto error;
     544     3023681 :         if (disjoint) {
     545      832367 :                 isl_map_free(map2);
     546      832367 :                 return map1;
     547             :         }
     548             : 
     549     2191314 :         map1 = isl_map_compute_divs(map1);
     550     2191314 :         map2 = isl_map_compute_divs(map2);
     551     2191314 :         if (!map1 || !map2)
     552             :                 goto error;
     553             : 
     554     2191314 :         map1 = isl_map_remove_empty_parts(map1);
     555     2191314 :         map2 = isl_map_remove_empty_parts(map2);
     556             : 
     557     2191314 :         diff = isl_map_empty(isl_map_get_space(map1));
     558     9070980 :         for (i = 0; i < map1->n; ++i) {
     559             :                 struct isl_map *d;
     560     6879666 :                 d = basic_map_subtract(isl_basic_map_copy(map1->p[i]),
     561             :                                        isl_map_copy(map2));
     562     6879666 :                 if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT))
     563     2488799 :                         diff = isl_map_union_disjoint(diff, d);
     564             :                 else
     565     4390867 :                         diff = isl_map_union(diff, d);
     566             :         }
     567             : 
     568     2191314 :         isl_map_free(map1);
     569     2191314 :         isl_map_free(map2);
     570             : 
     571     2191314 :         return diff;
     572             : error:
     573           0 :         isl_map_free(map1);
     574           0 :         isl_map_free(map2);
     575           0 :         return NULL;
     576             : }
     577             : 
     578     3324703 : __isl_give isl_map *isl_map_subtract( __isl_take isl_map *map1,
     579             :         __isl_take isl_map *map2)
     580             : {
     581     3324703 :         return isl_map_align_params_map_map_and(map1, map2, &map_subtract);
     582             : }
     583             : 
     584      827045 : struct isl_set *isl_set_subtract(struct isl_set *set1, struct isl_set *set2)
     585             : {
     586      827045 :         return set_from_map(isl_map_subtract(set_to_map(set1),
     587             :                                             set_to_map(set2)));
     588             : }
     589             : 
     590             : /* Remove the elements of "dom" from the domain of "map".
     591             :  */
     592           0 : static __isl_give isl_map *map_subtract_domain(__isl_take isl_map *map,
     593             :         __isl_take isl_set *dom)
     594             : {
     595             :         isl_bool ok;
     596             :         isl_map *ext_dom;
     597             : 
     598           0 :         ok = isl_map_compatible_domain(map, dom);
     599           0 :         if (ok < 0)
     600           0 :                 goto error;
     601           0 :         if (!ok)
     602           0 :                 isl_die(isl_set_get_ctx(dom), isl_error_invalid,
     603             :                         "incompatible spaces", goto error);
     604             :         
     605           0 :         ext_dom = isl_map_universe(isl_map_get_space(map));
     606           0 :         ext_dom = isl_map_intersect_domain(ext_dom, dom);
     607           0 :         return isl_map_subtract(map, ext_dom);
     608             : error:
     609           0 :         isl_map_free(map);
     610           0 :         isl_set_free(dom);
     611           0 :         return NULL;
     612             : }
     613             : 
     614           0 : __isl_give isl_map *isl_map_subtract_domain(__isl_take isl_map *map,
     615             :         __isl_take isl_set *dom)
     616             : {
     617           0 :         return isl_map_align_params_map_map_and(map, dom, &map_subtract_domain);
     618             : }
     619             : 
     620             : /* Remove the elements of "dom" from the range of "map".
     621             :  */
     622           0 : static __isl_give isl_map *map_subtract_range(__isl_take isl_map *map,
     623             :         __isl_take isl_set *dom)
     624             : {
     625             :         isl_bool ok;
     626             :         isl_map *ext_dom;
     627             : 
     628           0 :         ok = isl_map_compatible_range(map, dom);
     629           0 :         if (ok < 0)
     630           0 :                 goto error;
     631           0 :         if (!ok)
     632           0 :                 isl_die(isl_set_get_ctx(dom), isl_error_invalid,
     633             :                         "incompatible spaces", goto error);
     634             :         
     635           0 :         ext_dom = isl_map_universe(isl_map_get_space(map));
     636           0 :         ext_dom = isl_map_intersect_range(ext_dom, dom);
     637           0 :         return isl_map_subtract(map, ext_dom);
     638             : error:
     639           0 :         isl_map_free(map);
     640           0 :         isl_set_free(dom);
     641           0 :         return NULL;
     642             : }
     643             : 
     644           0 : __isl_give isl_map *isl_map_subtract_range(__isl_take isl_map *map,
     645             :         __isl_take isl_set *dom)
     646             : {
     647           0 :         return isl_map_align_params_map_map_and(map, dom, &map_subtract_range);
     648             : }
     649             : 
     650             : /* A diff collector that aborts as soon as its add function is called,
     651             :  * setting empty to 0.
     652             :  */
     653             : struct isl_is_empty_diff_collector {
     654             :         struct isl_diff_collector dc;
     655             :         isl_bool empty;
     656             : };
     657             : 
     658             : /* isl_is_empty_diff_collector callback.
     659             :  */
     660           0 : static isl_stat basic_map_is_empty_add(struct isl_diff_collector *dc,
     661             :                             __isl_take isl_basic_map *bmap)
     662             : {
     663             :         struct isl_is_empty_diff_collector *edc;
     664           0 :         edc = (struct isl_is_empty_diff_collector *)dc;
     665             : 
     666           0 :         edc->empty = 0;
     667             : 
     668           0 :         isl_basic_map_free(bmap);
     669           0 :         return isl_stat_error;
     670             : }
     671             : 
     672             : /* Check if bmap \ map is empty by computing this set difference
     673             :  * and breaking off as soon as the difference is known to be non-empty.
     674             :  */
     675     4947354 : static isl_bool basic_map_diff_is_empty(__isl_keep isl_basic_map *bmap,
     676             :         __isl_keep isl_map *map)
     677             : {
     678             :         isl_bool empty;
     679             :         isl_stat r;
     680             :         struct isl_is_empty_diff_collector edc;
     681             : 
     682     4947354 :         empty = isl_basic_map_plain_is_empty(bmap);
     683     4947354 :         if (empty)
     684           0 :                 return empty;
     685             : 
     686     4947354 :         edc.dc.add = &basic_map_is_empty_add;
     687     4947354 :         edc.empty = isl_bool_true;
     688     4947354 :         r = basic_map_collect_diff(isl_basic_map_copy(bmap),
     689             :                                    isl_map_copy(map), &edc.dc);
     690     4947354 :         if (!edc.empty)
     691           0 :                 return isl_bool_false;
     692             : 
     693     4947354 :         return r < 0 ? isl_bool_error : isl_bool_true;
     694             : }
     695             : 
     696             : /* Check if map1 \ map2 is empty by checking if the set difference is empty
     697             :  * for each of the basic maps in map1.
     698             :  */
     699      200582 : static isl_bool map_diff_is_empty(__isl_keep isl_map *map1,
     700             :         __isl_keep isl_map *map2)
     701             : {
     702             :         int i;
     703      200582 :         isl_bool is_empty = isl_bool_true;
     704             : 
     705      200582 :         if (!map1 || !map2)
     706           0 :                 return isl_bool_error;
     707             :         
     708     5147936 :         for (i = 0; i < map1->n; ++i) {
     709     4947354 :                 is_empty = basic_map_diff_is_empty(map1->p[i], map2);
     710     4947354 :                 if (is_empty < 0 || !is_empty)
     711             :                          break;
     712             :         }
     713             : 
     714      200582 :         return is_empty;
     715             : }
     716             : 
     717             : /* Return true if "bmap" contains a single element.
     718             :  */
     719       22999 : isl_bool isl_basic_map_plain_is_singleton(__isl_keep isl_basic_map *bmap)
     720             : {
     721       22999 :         if (!bmap)
     722           0 :                 return isl_bool_error;
     723       22999 :         if (bmap->n_div)
     724           0 :                 return isl_bool_false;
     725       22999 :         if (bmap->n_ineq)
     726       20091 :                 return isl_bool_false;
     727        2908 :         return bmap->n_eq == isl_basic_map_total_dim(bmap);
     728             : }
     729             : 
     730             : /* Return true if "map" contains a single element.
     731             :  */
     732      200626 : isl_bool isl_map_plain_is_singleton(__isl_keep isl_map *map)
     733             : {
     734      200626 :         if (!map)
     735           0 :                 return isl_bool_error;
     736      200626 :         if (map->n != 1)
     737      177627 :                 return isl_bool_false;
     738             : 
     739       22999 :         return isl_basic_map_plain_is_singleton(map->p[0]);
     740             : }
     741             : 
     742             : /* Given a singleton basic map, extract the single element
     743             :  * as an isl_point.
     744             :  */
     745          44 : static __isl_give isl_point *singleton_extract_point(
     746             :         __isl_keep isl_basic_map *bmap)
     747             : {
     748             :         int j;
     749             :         unsigned dim;
     750             :         struct isl_vec *point;
     751             :         isl_int m;
     752             : 
     753          44 :         if (!bmap)
     754           0 :                 return NULL;
     755             : 
     756          44 :         dim = isl_basic_map_total_dim(bmap);
     757          44 :         isl_assert(bmap->ctx, bmap->n_eq == dim, return NULL);
     758          44 :         point = isl_vec_alloc(bmap->ctx, 1 + dim);
     759          44 :         if (!point)
     760           0 :                 return NULL;
     761             : 
     762          44 :         isl_int_init(m);
     763             : 
     764          44 :         isl_int_set_si(point->el[0], 1);
     765         267 :         for (j = 0; j < bmap->n_eq; ++j) {
     766         223 :                 int i = dim - 1 - j;
     767         223 :                 isl_assert(bmap->ctx,
     768             :                     isl_seq_first_non_zero(bmap->eq[j] + 1, i) == -1,
     769             :                     goto error);
     770         223 :                 isl_assert(bmap->ctx,
     771             :                     isl_int_is_one(bmap->eq[j][1 + i]) ||
     772             :                     isl_int_is_negone(bmap->eq[j][1 + i]),
     773             :                     goto error);
     774         223 :                 isl_assert(bmap->ctx,
     775             :                     isl_seq_first_non_zero(bmap->eq[j]+1+i+1, dim-i-1) == -1,
     776             :                     goto error);
     777             : 
     778         223 :                 isl_int_gcd(m, point->el[0], bmap->eq[j][1 + i]);
     779         223 :                 isl_int_divexact(m, bmap->eq[j][1 + i], m);
     780         223 :                 isl_int_abs(m, m);
     781         223 :                 isl_seq_scale(point->el, point->el, m, 1 + i);
     782         223 :                 isl_int_divexact(m, point->el[0], bmap->eq[j][1 + i]);
     783         223 :                 isl_int_neg(m, m);
     784         223 :                 isl_int_mul(point->el[1 + i], m, bmap->eq[j][0]);
     785             :         }
     786             : 
     787          44 :         isl_int_clear(m);
     788          44 :         return isl_point_alloc(isl_basic_map_get_space(bmap), point);
     789             : error:
     790           0 :         isl_int_clear(m);
     791           0 :         isl_vec_free(point);
     792           0 :         return NULL;
     793             : }
     794             : 
     795             : /* Return isl_bool_true if the singleton map "map1" is a subset of "map2",
     796             :  * i.e., if the single element of "map1" is also an element of "map2".
     797             :  * Assumes "map2" has known divs.
     798             :  */
     799          44 : static isl_bool map_is_singleton_subset(__isl_keep isl_map *map1,
     800             :         __isl_keep isl_map *map2)
     801             : {
     802             :         int i;
     803          44 :         isl_bool is_subset = isl_bool_false;
     804             :         struct isl_point *point;
     805             : 
     806          44 :         if (!map1 || !map2)
     807           0 :                 return isl_bool_error;
     808          44 :         if (map1->n != 1)
     809           0 :                 isl_die(isl_map_get_ctx(map1), isl_error_invalid,
     810             :                         "expecting single-disjunct input",
     811             :                         return isl_bool_error);
     812             : 
     813          44 :         point = singleton_extract_point(map1->p[0]);
     814          44 :         if (!point)
     815           0 :                 return isl_bool_error;
     816             : 
     817          44 :         for (i = 0; i < map2->n; ++i) {
     818          44 :                 is_subset = isl_basic_map_contains_point(map2->p[i], point);
     819          44 :                 if (is_subset)
     820          44 :                         break;
     821             :         }
     822             : 
     823          44 :         isl_point_free(point);
     824          44 :         return is_subset;
     825             : }
     826             : 
     827      203490 : static isl_bool map_is_subset(__isl_keep isl_map *map1,
     828             :         __isl_keep isl_map *map2)
     829             : {
     830      203490 :         isl_bool is_subset = isl_bool_false;
     831             :         isl_bool empty, single;
     832             :         isl_bool rat1, rat2;
     833             : 
     834      203490 :         if (!map1 || !map2)
     835           0 :                 return isl_bool_error;
     836             : 
     837      203490 :         if (!isl_map_has_equal_space(map1, map2))
     838           0 :                 return isl_bool_false;
     839             : 
     840      203490 :         empty = isl_map_is_empty(map1);
     841      203490 :         if (empty < 0)
     842           0 :                 return isl_bool_error;
     843      203490 :         if (empty)
     844           0 :                 return isl_bool_true;
     845             : 
     846      203490 :         empty = isl_map_is_empty(map2);
     847      203490 :         if (empty < 0)
     848           0 :                 return isl_bool_error;
     849      203490 :         if (empty)
     850           0 :                 return isl_bool_false;
     851             : 
     852      203490 :         rat1 = isl_map_has_rational(map1);
     853      203490 :         rat2 = isl_map_has_rational(map2);
     854      203490 :         if (rat1 < 0 || rat2 < 0)
     855           0 :                 return isl_bool_error;
     856      203490 :         if (rat1 && !rat2)
     857           0 :                 return isl_bool_false;
     858             : 
     859      203490 :         if (isl_map_plain_is_universe(map2))
     860        2864 :                 return isl_bool_true;
     861             : 
     862      200626 :         single = isl_map_plain_is_singleton(map1);
     863      200626 :         if (single < 0)
     864           0 :                 return isl_bool_error;
     865      200626 :         map2 = isl_map_compute_divs(isl_map_copy(map2));
     866      200626 :         if (single) {
     867          44 :                 is_subset = map_is_singleton_subset(map1, map2);
     868          44 :                 isl_map_free(map2);
     869          44 :                 return is_subset;
     870             :         }
     871      200582 :         is_subset = map_diff_is_empty(map1, map2);
     872      200582 :         isl_map_free(map2);
     873             : 
     874      200582 :         return is_subset;
     875             : }
     876             : 
     877      203490 : isl_bool isl_map_is_subset(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
     878             : {
     879      203490 :         return isl_map_align_params_map_map_and_test(map1, map2,
     880             :                                                         &map_is_subset);
     881             : }
     882             : 
     883           0 : isl_bool isl_set_is_subset(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
     884             : {
     885           0 :         return isl_map_is_subset(set_to_map(set1), set_to_map(set2));
     886             : }
     887             : 
     888           0 : __isl_give isl_map *isl_map_make_disjoint(__isl_take isl_map *map)
     889             : {
     890             :         int i;
     891             :         struct isl_subtract_diff_collector sdc;
     892           0 :         sdc.dc.add = &basic_map_subtract_add;
     893             : 
     894           0 :         if (!map)
     895           0 :                 return NULL;
     896           0 :         if (ISL_F_ISSET(map, ISL_MAP_DISJOINT))
     897           0 :                 return map;
     898           0 :         if (map->n <= 1)
     899           0 :                 return map;
     900             : 
     901           0 :         map = isl_map_compute_divs(map);
     902           0 :         map = isl_map_remove_empty_parts(map);
     903             : 
     904           0 :         if (!map || map->n <= 1)
     905           0 :                 return map;
     906             : 
     907           0 :         sdc.diff = isl_map_from_basic_map(isl_basic_map_copy(map->p[0]));
     908             : 
     909           0 :         for (i = 1; i < map->n; ++i) {
     910           0 :                 struct isl_basic_map *bmap = isl_basic_map_copy(map->p[i]);
     911           0 :                 struct isl_map *copy = isl_map_copy(sdc.diff);
     912           0 :                 if (basic_map_collect_diff(bmap, copy, &sdc.dc) < 0) {
     913           0 :                         isl_map_free(sdc.diff);
     914           0 :                         sdc.diff = NULL;
     915           0 :                         break;
     916             :                 }
     917             :         }
     918             : 
     919           0 :         isl_map_free(map);
     920             : 
     921           0 :         return sdc.diff;
     922             : }
     923             : 
     924           0 : __isl_give isl_set *isl_set_make_disjoint(__isl_take isl_set *set)
     925             : {
     926           0 :         return set_from_map(isl_map_make_disjoint(set_to_map(set)));
     927             : }
     928             : 
     929     2497658 : __isl_give isl_map *isl_map_complement(__isl_take isl_map *map)
     930             : {
     931             :         isl_map *universe;
     932             : 
     933     2497658 :         if (!map)
     934           0 :                 return NULL;
     935             : 
     936     2497658 :         universe = isl_map_universe(isl_map_get_space(map));
     937             : 
     938     2497658 :         return isl_map_subtract(universe, map);
     939             : }
     940             : 
     941     2497658 : __isl_give isl_set *isl_set_complement(__isl_take isl_set *set)
     942             : {
     943     2497658 :         return isl_map_complement(set);
     944             : }

Generated by: LCOV version 1.12