/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/External/isl/isl_map_subtract.c
Line | Count | Source (jump to first uncovered line) |
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 | | static void expand_constraint(isl_vec *v, unsigned dim, |
33 | | isl_int *c, int *div_map, unsigned n_div) |
34 | 339k | { |
35 | 339k | int i; |
36 | 339k | |
37 | 339k | isl_seq_cpy(v->el, c, 1 + dim); |
38 | 339k | isl_seq_clr(v->el + 1 + dim, v->size - (1 + dim)); |
39 | 339k | |
40 | 393k | for (i = 0; i < n_div; ++i54.1k ) { |
41 | 54.1k | int pos = 1 + dim + div_map[i]; |
42 | 54.1k | isl_int_add(v->el[pos], v->el[pos], c[1 + dim + i]); |
43 | 54.1k | } |
44 | 339k | } |
45 | | |
46 | | /* Add all constraints of bmap to tab. The equalities of bmap |
47 | | * are added as a pair of inequalities. |
48 | | */ |
49 | | static isl_stat tab_add_constraints(struct isl_tab *tab, |
50 | | __isl_keep isl_basic_map *bmap, int *div_map) |
51 | 76.6k | { |
52 | 76.6k | int i; |
53 | 76.6k | unsigned dim; |
54 | 76.6k | unsigned tab_total; |
55 | 76.6k | unsigned bmap_total; |
56 | 76.6k | isl_vec *v; |
57 | 76.6k | |
58 | 76.6k | if (!tab || !bmap) |
59 | 0 | return isl_stat_error; |
60 | 76.6k | |
61 | 76.6k | tab_total = isl_basic_map_total_dim(tab->bmap); |
62 | 76.6k | bmap_total = isl_basic_map_total_dim(bmap); |
63 | 76.6k | dim = isl_space_dim(tab->bmap->dim, isl_dim_all); |
64 | 76.6k | |
65 | 76.6k | if (isl_tab_extend_cons(tab, 2 * bmap->n_eq + bmap->n_ineq) < 0) |
66 | 0 | return isl_stat_error; |
67 | 76.6k | |
68 | 76.6k | v = isl_vec_alloc(bmap->ctx, 1 + tab_total); |
69 | 76.6k | if (!v) |
70 | 0 | return isl_stat_error; |
71 | 76.6k | |
72 | 111k | for (i = 0; 76.6k i < bmap->n_eq; ++i34.8k ) { |
73 | 39.7k | expand_constraint(v, dim, bmap->eq[i], div_map, bmap->n_div); |
74 | 39.7k | if (isl_tab_add_ineq(tab, v->el) < 0) |
75 | 0 | goto error; |
76 | 39.7k | isl_seq_neg(bmap->eq[i], bmap->eq[i], 1 + bmap_total); |
77 | 39.7k | expand_constraint(v, dim, bmap->eq[i], div_map, bmap->n_div); |
78 | 39.7k | if (isl_tab_add_ineq(tab, v->el) < 0) |
79 | 0 | goto error; |
80 | 39.7k | isl_seq_neg(bmap->eq[i], bmap->eq[i], 1 + bmap_total); |
81 | 39.7k | if (tab->empty) |
82 | 4.89k | break; |
83 | 39.7k | } |
84 | 76.6k | |
85 | 258k | for (i = 0; 76.6k i < bmap->n_ineq; ++i181k ) { |
86 | 207k | expand_constraint(v, dim, bmap->ineq[i], div_map, bmap->n_div); |
87 | 207k | if (isl_tab_add_ineq(tab, v->el) < 0) |
88 | 0 | goto error; |
89 | 207k | if (tab->empty) |
90 | 26.2k | break; |
91 | 207k | } |
92 | 76.6k | |
93 | 76.6k | isl_vec_free(v); |
94 | 76.6k | return isl_stat_ok; |
95 | 0 | error: |
96 | 0 | isl_vec_free(v); |
97 | 0 | return isl_stat_error; |
98 | 76.6k | } |
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 | | 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 | 52.2k | { |
112 | 52.2k | unsigned dim; |
113 | 52.2k | unsigned tab_total; |
114 | 52.2k | unsigned bmap_total; |
115 | 52.2k | isl_vec *v; |
116 | 52.2k | isl_stat r; |
117 | 52.2k | |
118 | 52.2k | if (!tab || !bmap) |
119 | 0 | return isl_stat_error; |
120 | 52.2k | |
121 | 52.2k | tab_total = isl_basic_map_total_dim(tab->bmap); |
122 | 52.2k | bmap_total = isl_basic_map_total_dim(bmap); |
123 | 52.2k | dim = isl_space_dim(tab->bmap->dim, isl_dim_all); |
124 | 52.2k | |
125 | 52.2k | v = isl_vec_alloc(bmap->ctx, 1 + tab_total); |
126 | 52.2k | if (!v) |
127 | 0 | return isl_stat_error; |
128 | 52.2k | |
129 | 52.2k | if (c < 2 * bmap->n_eq) { |
130 | 22.6k | if ((c % 2) != oppose) |
131 | 9.85k | isl_seq_neg(bmap->eq[c/2], bmap->eq[c/2], |
132 | 9.85k | 1 + bmap_total); |
133 | 22.6k | if (oppose) |
134 | 22.6k | isl_int_sub_ui15.9k (bmap->eq[c/2][0], bmap->eq[c/2][0], 1); |
135 | 22.6k | expand_constraint(v, dim, bmap->eq[c/2], div_map, bmap->n_div); |
136 | 22.6k | r = isl_tab_add_ineq(tab, v->el); |
137 | 22.6k | if (oppose) |
138 | 22.6k | isl_int_add_ui15.9k (bmap->eq[c/2][0], bmap->eq[c/2][0], 1); |
139 | 22.6k | if ((c % 2) != oppose) |
140 | 9.85k | isl_seq_neg(bmap->eq[c/2], bmap->eq[c/2], |
141 | 9.85k | 1 + bmap_total); |
142 | 29.6k | } else { |
143 | 29.6k | c -= 2 * bmap->n_eq; |
144 | 29.6k | if (oppose) { |
145 | 26.4k | isl_seq_neg(bmap->ineq[c], bmap->ineq[c], |
146 | 26.4k | 1 + bmap_total); |
147 | 26.4k | isl_int_sub_ui(bmap->ineq[c][0], bmap->ineq[c][0], 1); |
148 | 26.4k | } |
149 | 29.6k | expand_constraint(v, dim, bmap->ineq[c], div_map, bmap->n_div); |
150 | 29.6k | r = isl_tab_add_ineq(tab, v->el); |
151 | 29.6k | if (oppose) { |
152 | 26.4k | isl_int_add_ui(bmap->ineq[c][0], bmap->ineq[c][0], 1); |
153 | 26.4k | isl_seq_neg(bmap->ineq[c], bmap->ineq[c], |
154 | 26.4k | 1 + bmap_total); |
155 | 26.4k | } |
156 | 29.6k | } |
157 | 52.2k | |
158 | 52.2k | isl_vec_free(v); |
159 | 52.2k | return r; |
160 | 52.2k | } |
161 | | |
162 | | static isl_stat tab_add_divs(struct isl_tab *tab, |
163 | | __isl_keep isl_basic_map *bmap, int **div_map) |
164 | 76.6k | { |
165 | 76.6k | int i, j; |
166 | 76.6k | struct isl_vec *vec; |
167 | 76.6k | unsigned total; |
168 | 76.6k | unsigned dim; |
169 | 76.6k | |
170 | 76.6k | if (!bmap) |
171 | 0 | return isl_stat_error; |
172 | 76.6k | if (!bmap->n_div) |
173 | 70.7k | return isl_stat_ok; |
174 | 5.86k | |
175 | 5.86k | if (!*div_map) |
176 | 4.71k | *div_map = isl_alloc_array(bmap->ctx, int, bmap->n_div); |
177 | 5.86k | if (!*div_map) |
178 | 0 | return isl_stat_error; |
179 | 5.86k | |
180 | 5.86k | total = isl_basic_map_total_dim(tab->bmap); |
181 | 5.86k | dim = total - tab->bmap->n_div; |
182 | 5.86k | vec = isl_vec_alloc(bmap->ctx, 2 + total + bmap->n_div); |
183 | 5.86k | if (!vec) |
184 | 0 | return isl_stat_error; |
185 | 5.86k | |
186 | 14.9k | for (i = 0; 5.86k i < bmap->n_div; ++i9.10k ) { |
187 | 9.10k | isl_seq_cpy(vec->el, bmap->div[i], 2 + dim); |
188 | 9.10k | isl_seq_clr(vec->el + 2 + dim, tab->bmap->n_div); |
189 | 13.0k | for (j = 0; j < i; ++j3.89k ) |
190 | 9.10k | isl_int_add3.89k (vec->el[2 + dim + (*div_map)[j]], |
191 | 9.10k | vec->el[2 + dim + (*div_map)[j]], |
192 | 9.10k | bmap->div[i][2 + dim + j]); |
193 | 16.8k | for (j = 0; j < tab->bmap->n_div; ++j7.71k ) |
194 | 13.4k | if (isl_seq_eq(tab->bmap->div[j], |
195 | 13.4k | vec->el, 2 + dim + tab->bmap->n_div)) |
196 | 5.71k | break; |
197 | 9.10k | (*div_map)[i] = j; |
198 | 9.10k | if (j == tab->bmap->n_div) { |
199 | 3.38k | vec->size = 2 + dim + tab->bmap->n_div; |
200 | 3.38k | if (isl_tab_add_div(tab, vec) < 0) |
201 | 0 | goto error; |
202 | 3.38k | } |
203 | 9.10k | } |
204 | 5.86k | |
205 | 5.86k | isl_vec_free(vec); |
206 | 5.86k | |
207 | 5.86k | return isl_stat_ok; |
208 | 0 | error: |
209 | 0 | isl_vec_free(vec); |
210 | 0 |
|
211 | 0 | return isl_stat_error; |
212 | 5.86k | } |
213 | | |
214 | | /* Freeze all constraints of tableau tab. |
215 | | */ |
216 | | static int tab_freeze_constraints(struct isl_tab *tab) |
217 | 76.6k | { |
218 | 76.6k | int i; |
219 | 76.6k | |
220 | 500k | for (i = 0; i < tab->n_con; ++i424k ) |
221 | 424k | if (isl_tab_freeze_constraint(tab, i) < 0) |
222 | 0 | return -1; |
223 | 76.6k | |
224 | 76.6k | return 0; |
225 | 76.6k | } |
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 | | static int n_non_redundant(isl_ctx *ctx, struct isl_tab *tab, |
232 | | int offset, int **index) |
233 | 49.7k | { |
234 | 49.7k | int i, n; |
235 | 49.7k | int n_test = tab->n_con - offset; |
236 | 49.7k | |
237 | 49.7k | if (isl_tab_detect_redundant(tab) < 0) |
238 | 0 | return -1; |
239 | 49.7k | |
240 | 49.7k | if (n_test == 0) |
241 | 2.46k | return 0; |
242 | 47.2k | if (!*index) |
243 | 46.7k | *index = isl_alloc_array(ctx, int, n_test); |
244 | 47.2k | if (!*index) |
245 | 0 | return -1; |
246 | 47.2k | |
247 | 261k | for (n = 0, i = 0; 47.2k i < n_test; ++i214k ) { |
248 | 214k | int r; |
249 | 214k | r = isl_tab_is_redundant(tab, offset + i); |
250 | 214k | if (r < 0) |
251 | 0 | return -1; |
252 | 214k | if (r) |
253 | 163k | continue; |
254 | 51.3k | (*index)[n++] = i; |
255 | 51.3k | } |
256 | 47.2k | |
257 | 47.2k | return n; |
258 | 47.2k | } |
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 | | 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 | 47.7k | { |
301 | 47.7k | int i; |
302 | 47.7k | int modified; |
303 | 47.7k | int level; |
304 | 47.7k | int init; |
305 | 47.7k | isl_bool empty; |
306 | 47.7k | isl_ctx *ctx; |
307 | 47.7k | struct isl_tab *tab = NULL; |
308 | 47.7k | struct isl_tab_undo **snap = NULL; |
309 | 47.7k | int *k = NULL; |
310 | 47.7k | int *n = NULL; |
311 | 47.7k | int **index = NULL; |
312 | 47.7k | int **div_map = NULL; |
313 | 47.7k | |
314 | 47.7k | empty = isl_basic_map_is_empty(bmap); |
315 | 47.7k | if (empty) { |
316 | 6 | isl_basic_map_free(bmap); |
317 | 6 | isl_map_free(map); |
318 | 6 | return empty < 0 ? isl_stat_error0 : isl_stat_ok; |
319 | 6 | } |
320 | 47.7k | |
321 | 47.7k | bmap = isl_basic_map_cow(bmap); |
322 | 47.7k | map = isl_map_cow(map); |
323 | 47.7k | |
324 | 47.7k | if (!bmap || !map) |
325 | 0 | goto error; |
326 | 47.7k | |
327 | 47.7k | ctx = map->ctx; |
328 | 47.7k | snap = isl_alloc_array(map->ctx, struct isl_tab_undo *, map->n); |
329 | 47.7k | k = isl_alloc_array(map->ctx, int, map->n); |
330 | 47.7k | n = isl_alloc_array(map->ctx, int, map->n); |
331 | 47.7k | index = isl_calloc_array(map->ctx, int *, map->n); |
332 | 47.7k | div_map = isl_calloc_array(map->ctx, int *, map->n); |
333 | 47.7k | if (!snap || !k || !n || !index || !div_map) |
334 | 0 | goto error; |
335 | 47.7k | |
336 | 47.7k | bmap = isl_basic_map_order_divs(bmap); |
337 | 47.7k | map = isl_map_order_divs(map); |
338 | 47.7k | |
339 | 47.7k | tab = isl_tab_from_basic_map(bmap, 1); |
340 | 47.7k | if (!tab) |
341 | 0 | goto error; |
342 | 47.7k | |
343 | 47.7k | modified = 0; |
344 | 47.7k | level = 0; |
345 | 47.7k | init = 1; |
346 | 47.7k | |
347 | 196k | while (level >= 0) { |
348 | 163k | if (level >= map->n) { |
349 | 40.3k | int empty; |
350 | 40.3k | struct isl_basic_map *bm; |
351 | 40.3k | if (!modified) { |
352 | 6.46k | if (dc->add(dc, isl_basic_map_copy(bmap)) < 0) |
353 | 1.64k | goto error; |
354 | 4.82k | break; |
355 | 4.82k | } |
356 | 33.8k | bm = isl_basic_map_copy(tab->bmap); |
357 | 33.8k | bm = isl_basic_map_cow(bm); |
358 | 33.8k | bm = isl_basic_map_update_from_tab(bm, tab); |
359 | 33.8k | bm = isl_basic_map_simplify(bm); |
360 | 33.8k | bm = isl_basic_map_finalize(bm); |
361 | 33.8k | empty = isl_basic_map_is_empty(bm); |
362 | 33.8k | if (empty) |
363 | 1.04k | isl_basic_map_free(bm); |
364 | 32.8k | else if (dc->add(dc, bm) < 0) |
365 | 8.16k | goto error; |
366 | 25.7k | if (empty < 0) |
367 | 0 | goto error; |
368 | 25.7k | level--; |
369 | 25.7k | init = 0; |
370 | 25.7k | continue; |
371 | 25.7k | } |
372 | 123k | if (init) { |
373 | 76.6k | int offset; |
374 | 76.6k | struct isl_tab_undo *snap2; |
375 | 76.6k | snap2 = isl_tab_snap(tab); |
376 | 76.6k | if (tab_add_divs(tab, map->p[level], |
377 | 76.6k | &div_map[level]) < 0) |
378 | 0 | goto error; |
379 | 76.6k | offset = tab->n_con; |
380 | 76.6k | snap[level] = isl_tab_snap(tab); |
381 | 76.6k | if (tab_freeze_constraints(tab) < 0) |
382 | 0 | goto error; |
383 | 76.6k | if (tab_add_constraints(tab, map->p[level], |
384 | 76.6k | div_map[level]) < 0) |
385 | 0 | goto error; |
386 | 76.6k | k[level] = 0; |
387 | 76.6k | n[level] = 0; |
388 | 76.6k | if (tab->empty) { |
389 | 26.8k | if (isl_tab_rollback(tab, snap2) < 0) |
390 | 0 | goto error; |
391 | 26.8k | level++; |
392 | 26.8k | continue; |
393 | 26.8k | } |
394 | 49.7k | modified = 1; |
395 | 49.7k | n[level] = n_non_redundant(ctx, tab, offset, |
396 | 49.7k | &index[level]); |
397 | 49.7k | if (n[level] < 0) |
398 | 0 | goto error; |
399 | 49.7k | if (n[level] == 0) { |
400 | 17.3k | level--; |
401 | 17.3k | init = 0; |
402 | 17.3k | continue; |
403 | 17.3k | } |
404 | 32.4k | if (isl_tab_rollback(tab, snap[level]) < 0) |
405 | 0 | goto error; |
406 | 32.4k | if (tab_add_constraint(tab, map->p[level], |
407 | 32.4k | div_map[level], index[level][0], 1) < 0) |
408 | 0 | goto error; |
409 | 32.4k | level++; |
410 | 32.4k | continue; |
411 | 46.9k | } else { |
412 | 46.9k | if (k[level] + 1 >= n[level]) { |
413 | 36.9k | level--; |
414 | 36.9k | continue; |
415 | 36.9k | } |
416 | 9.93k | if (isl_tab_rollback(tab, snap[level]) < 0) |
417 | 0 | goto error; |
418 | 9.93k | if (tab_add_constraint(tab, map->p[level], |
419 | 9.93k | div_map[level], |
420 | 9.93k | index[level][k[level]], 0) < 0) |
421 | 0 | goto error; |
422 | 9.93k | snap[level] = isl_tab_snap(tab); |
423 | 9.93k | k[level]++; |
424 | 9.93k | if (tab_add_constraint(tab, map->p[level], |
425 | 9.93k | div_map[level], |
426 | 9.93k | index[level][k[level]], 1) < 0) |
427 | 0 | goto error; |
428 | 9.93k | level++; |
429 | 9.93k | init = 1; |
430 | 9.93k | continue; |
431 | 9.93k | } |
432 | 123k | } |
433 | 47.7k | |
434 | 47.7k | isl_tab_free(tab); |
435 | 37.8k | free(snap); |
436 | 37.8k | free(n); |
437 | 37.8k | free(k); |
438 | 94.7k | for (i = 0; index && i < map->n; ++i56.8k ) |
439 | 56.8k | free(index[i]); |
440 | 37.8k | free(index); |
441 | 94.7k | for (i = 0; div_map && i < map->n; ++i56.8k ) |
442 | 56.8k | free(div_map[i]); |
443 | 37.8k | free(div_map); |
444 | 37.8k | |
445 | 37.8k | isl_basic_map_free(bmap); |
446 | 37.8k | isl_map_free(map); |
447 | 37.8k | |
448 | 37.8k | return isl_stat_ok; |
449 | 9.81k | error: |
450 | 9.81k | isl_tab_free(tab); |
451 | 9.81k | free(snap); |
452 | 9.81k | free(n); |
453 | 9.81k | free(k); |
454 | 26.7k | for (i = 0; index && i < map->n; ++i16.9k ) |
455 | 16.9k | free(index[i]); |
456 | 9.81k | free(index); |
457 | 26.7k | for (i = 0; div_map && i < map->n; ++i16.9k ) |
458 | 16.9k | free(div_map[i]); |
459 | 9.81k | free(div_map); |
460 | 9.81k | isl_basic_map_free(bmap); |
461 | 9.81k | isl_map_free(map); |
462 | 9.81k | return isl_stat_error; |
463 | 47.7k | } |
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 | | static isl_stat basic_map_subtract_add(struct isl_diff_collector *dc, |
476 | | __isl_take isl_basic_map *bmap) |
477 | 29.4k | { |
478 | 29.4k | struct isl_subtract_diff_collector *sdc; |
479 | 29.4k | sdc = (struct isl_subtract_diff_collector *)dc; |
480 | 29.4k | |
481 | 29.4k | sdc->diff = isl_map_union_disjoint(sdc->diff, |
482 | 29.4k | isl_map_from_basic_map(bmap)); |
483 | 29.4k | |
484 | 29.4k | return sdc->diff ? isl_stat_ok : isl_stat_error0 ; |
485 | 29.4k | } |
486 | | |
487 | | /* Return the set difference between bmap and map. |
488 | | */ |
489 | | static __isl_give isl_map *basic_map_subtract(__isl_take isl_basic_map *bmap, |
490 | | __isl_take isl_map *map) |
491 | 26.0k | { |
492 | 26.0k | struct isl_subtract_diff_collector sdc; |
493 | 26.0k | sdc.dc.add = &basic_map_subtract_add; |
494 | 26.0k | sdc.diff = isl_map_empty(isl_basic_map_get_space(bmap)); |
495 | 26.0k | if (basic_map_collect_diff(bmap, map, &sdc.dc) < 0) { |
496 | 0 | isl_map_free(sdc.diff); |
497 | 0 | sdc.diff = NULL; |
498 | 0 | } |
499 | 26.0k | return sdc.diff; |
500 | 26.0k | } |
501 | | |
502 | | /* Return an empty map living in the same space as "map1" and "map2". |
503 | | */ |
504 | | static __isl_give isl_map *replace_pair_by_empty( __isl_take isl_map *map1, |
505 | | __isl_take isl_map *map2) |
506 | 4.65k | { |
507 | 4.65k | isl_space *space; |
508 | 4.65k | |
509 | 4.65k | space = isl_map_get_space(map1); |
510 | 4.65k | isl_map_free(map1); |
511 | 4.65k | isl_map_free(map2); |
512 | 4.65k | return isl_map_empty(space); |
513 | 4.65k | } |
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 | | static __isl_give isl_map *map_subtract( __isl_take isl_map *map1, |
524 | | __isl_take isl_map *map2) |
525 | 32.9k | { |
526 | 32.9k | int i; |
527 | 32.9k | int equal, disjoint; |
528 | 32.9k | struct isl_map *diff; |
529 | 32.9k | |
530 | 32.9k | if (!map1 || !map2) |
531 | 0 | goto error; |
532 | 32.9k | |
533 | 32.9k | isl_assert(map1->ctx, isl_space_is_equal(map1->dim, map2->dim), goto error); |
534 | 32.9k | |
535 | 32.9k | equal = isl_map_plain_is_equal(map1, map2); |
536 | 32.9k | if (equal < 0) |
537 | 0 | goto error; |
538 | 32.9k | if (equal) |
539 | 4.65k | return replace_pair_by_empty(map1, map2); |
540 | 28.2k | |
541 | 28.2k | disjoint = isl_map_is_disjoint(map1, map2); |
542 | 28.2k | if (disjoint < 0) |
543 | 0 | goto error; |
544 | 28.2k | if (disjoint) { |
545 | 16.1k | isl_map_free(map2); |
546 | 16.1k | return map1; |
547 | 16.1k | } |
548 | 12.1k | |
549 | 12.1k | map1 = isl_map_compute_divs(map1); |
550 | 12.1k | map2 = isl_map_compute_divs(map2); |
551 | 12.1k | if (!map1 || !map2) |
552 | 0 | goto error; |
553 | 12.1k | |
554 | 12.1k | map1 = isl_map_remove_empty_parts(map1); |
555 | 12.1k | map2 = isl_map_remove_empty_parts(map2); |
556 | 12.1k | |
557 | 12.1k | diff = isl_map_empty(isl_map_get_space(map1)); |
558 | 38.1k | for (i = 0; i < map1->n; ++i26.0k ) { |
559 | 26.0k | struct isl_map *d; |
560 | 26.0k | d = basic_map_subtract(isl_basic_map_copy(map1->p[i]), |
561 | 26.0k | isl_map_copy(map2)); |
562 | 26.0k | if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT)) |
563 | 26.0k | diff = isl_map_union_disjoint(diff, d)9.81k ; |
564 | 16.2k | else |
565 | 16.2k | diff = isl_map_union(diff, d); |
566 | 26.0k | } |
567 | 12.1k | |
568 | 12.1k | isl_map_free(map1); |
569 | 12.1k | isl_map_free(map2); |
570 | 12.1k | |
571 | 12.1k | return diff; |
572 | 0 | error: |
573 | 0 | isl_map_free(map1); |
574 | 0 | isl_map_free(map2); |
575 | 0 | return NULL; |
576 | 12.1k | } |
577 | | |
578 | | __isl_give isl_map *isl_map_subtract( __isl_take isl_map *map1, |
579 | | __isl_take isl_map *map2) |
580 | 32.9k | { |
581 | 32.9k | return isl_map_align_params_map_map_and(map1, map2, &map_subtract); |
582 | 32.9k | } |
583 | | |
584 | | struct isl_set *isl_set_subtract(struct isl_set *set1, struct isl_set *set2) |
585 | 21.9k | { |
586 | 21.9k | return set_from_map(isl_map_subtract(set_to_map(set1), |
587 | 21.9k | set_to_map(set2))); |
588 | 21.9k | } |
589 | | |
590 | | /* Remove the elements of "dom" from the domain of "map". |
591 | | */ |
592 | | static __isl_give isl_map *map_subtract_domain(__isl_take isl_map *map, |
593 | | __isl_take isl_set *dom) |
594 | 96 | { |
595 | 96 | isl_bool ok; |
596 | 96 | isl_map *ext_dom; |
597 | 96 | |
598 | 96 | ok = isl_map_compatible_domain(map, dom); |
599 | 96 | if (ok < 0) |
600 | 0 | goto error; |
601 | 96 | if (!ok) |
602 | 96 | isl_die0 (isl_set_get_ctx(dom), isl_error_invalid, |
603 | 96 | "incompatible spaces", goto error); |
604 | 96 | |
605 | 96 | ext_dom = isl_map_universe(isl_map_get_space(map)); |
606 | 96 | ext_dom = isl_map_intersect_domain(ext_dom, dom); |
607 | 96 | return isl_map_subtract(map, ext_dom); |
608 | 0 | error: |
609 | 0 | isl_map_free(map); |
610 | 0 | isl_set_free(dom); |
611 | 0 | return NULL; |
612 | 96 | } |
613 | | |
614 | | __isl_give isl_map *isl_map_subtract_domain(__isl_take isl_map *map, |
615 | | __isl_take isl_set *dom) |
616 | 96 | { |
617 | 96 | return isl_map_align_params_map_map_and(map, dom, &map_subtract_domain); |
618 | 96 | } |
619 | | |
620 | | /* Remove the elements of "dom" from the range of "map". |
621 | | */ |
622 | | static __isl_give isl_map *map_subtract_range(__isl_take isl_map *map, |
623 | | __isl_take isl_set *dom) |
624 | 2 | { |
625 | 2 | isl_bool ok; |
626 | 2 | isl_map *ext_dom; |
627 | 2 | |
628 | 2 | ok = isl_map_compatible_range(map, dom); |
629 | 2 | if (ok < 0) |
630 | 0 | goto error; |
631 | 2 | if (!ok) |
632 | 2 | isl_die0 (isl_set_get_ctx(dom), isl_error_invalid, |
633 | 2 | "incompatible spaces", goto error); |
634 | 2 | |
635 | 2 | ext_dom = isl_map_universe(isl_map_get_space(map)); |
636 | 2 | ext_dom = isl_map_intersect_range(ext_dom, dom); |
637 | 2 | return isl_map_subtract(map, ext_dom); |
638 | 0 | error: |
639 | 0 | isl_map_free(map); |
640 | 0 | isl_set_free(dom); |
641 | 0 | return NULL; |
642 | 2 | } |
643 | | |
644 | | __isl_give isl_map *isl_map_subtract_range(__isl_take isl_map *map, |
645 | | __isl_take isl_set *dom) |
646 | 2 | { |
647 | 2 | return isl_map_align_params_map_map_and(map, dom, &map_subtract_range); |
648 | 2 | } |
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 | | static isl_stat basic_map_is_empty_add(struct isl_diff_collector *dc, |
661 | | __isl_take isl_basic_map *bmap) |
662 | 9.81k | { |
663 | 9.81k | struct isl_is_empty_diff_collector *edc; |
664 | 9.81k | edc = (struct isl_is_empty_diff_collector *)dc; |
665 | 9.81k | |
666 | 9.81k | edc->empty = 0; |
667 | 9.81k | |
668 | 9.81k | isl_basic_map_free(bmap); |
669 | 9.81k | return isl_stat_error; |
670 | 9.81k | } |
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 | | static isl_bool basic_map_diff_is_empty(__isl_keep isl_basic_map *bmap, |
676 | | __isl_keep isl_map *map) |
677 | 21.2k | { |
678 | 21.2k | isl_bool empty; |
679 | 21.2k | isl_stat r; |
680 | 21.2k | struct isl_is_empty_diff_collector edc; |
681 | 21.2k | |
682 | 21.2k | empty = isl_basic_map_plain_is_empty(bmap); |
683 | 21.2k | if (empty) |
684 | 1 | return empty; |
685 | 21.2k | |
686 | 21.2k | edc.dc.add = &basic_map_is_empty_add; |
687 | 21.2k | edc.empty = isl_bool_true; |
688 | 21.2k | r = basic_map_collect_diff(isl_basic_map_copy(bmap), |
689 | 21.2k | isl_map_copy(map), &edc.dc); |
690 | 21.2k | if (!edc.empty) |
691 | 9.81k | return isl_bool_false; |
692 | 11.4k | |
693 | 11.4k | return r < 0 ? isl_bool_error0 : isl_bool_true; |
694 | 11.4k | } |
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 | | static isl_bool map_diff_is_empty(__isl_keep isl_map *map1, |
700 | | __isl_keep isl_map *map2) |
701 | 19.7k | { |
702 | 19.7k | int i; |
703 | 19.7k | isl_bool is_empty = isl_bool_true; |
704 | 19.7k | |
705 | 19.7k | if (!map1 || !map2) |
706 | 0 | return isl_bool_error; |
707 | 19.7k | |
708 | 31.2k | for (i = 0; 19.7k i < map1->n; ++i11.4k ) { |
709 | 21.2k | is_empty = basic_map_diff_is_empty(map1->p[i], map2); |
710 | 21.2k | if (is_empty < 0 || !is_empty) |
711 | 9.81k | break; |
712 | 21.2k | } |
713 | 19.7k | |
714 | 19.7k | return is_empty; |
715 | 19.7k | } |
716 | | |
717 | | /* Return true if "bmap" contains a single element. |
718 | | */ |
719 | | isl_bool isl_basic_map_plain_is_singleton(__isl_keep isl_basic_map *bmap) |
720 | 17.6k | { |
721 | 17.6k | if (!bmap) |
722 | 0 | return isl_bool_error; |
723 | 17.6k | if (bmap->n_div) |
724 | 1.92k | return isl_bool_false; |
725 | 15.6k | if (bmap->n_ineq) |
726 | 13.3k | return isl_bool_false; |
727 | 2.33k | return bmap->n_eq == isl_basic_map_total_dim(bmap); |
728 | 2.33k | } |
729 | | |
730 | | /* Return true if "map" contains a single element. |
731 | | */ |
732 | | isl_bool isl_map_plain_is_singleton(__isl_keep isl_map *map) |
733 | 20.1k | { |
734 | 20.1k | if (!map) |
735 | 0 | return isl_bool_error; |
736 | 20.1k | if (map->n != 1) |
737 | 2.54k | return isl_bool_false; |
738 | 17.6k | |
739 | 17.6k | return isl_basic_map_plain_is_singleton(map->p[0]); |
740 | 17.6k | } |
741 | | |
742 | | /* Given a singleton basic map, extract the single element |
743 | | * as an isl_point. |
744 | | */ |
745 | | static __isl_give isl_point *singleton_extract_point( |
746 | | __isl_keep isl_basic_map *bmap) |
747 | 404 | { |
748 | 404 | int j; |
749 | 404 | unsigned dim; |
750 | 404 | struct isl_vec *point; |
751 | 404 | isl_int m; |
752 | 404 | |
753 | 404 | if (!bmap) |
754 | 0 | return NULL; |
755 | 404 | |
756 | 404 | dim = isl_basic_map_total_dim(bmap); |
757 | 404 | isl_assert(bmap->ctx, bmap->n_eq == dim, return NULL); |
758 | 404 | point = isl_vec_alloc(bmap->ctx, 1 + dim); |
759 | 404 | if (!point) |
760 | 0 | return NULL; |
761 | 404 | |
762 | 404 | isl_int_init(m); |
763 | 404 | |
764 | 404 | isl_int_set_si(point->el[0], 1); |
765 | 892 | for (j = 0; j < bmap->n_eq; ++j488 ) { |
766 | 488 | int i = dim - 1 - j; |
767 | 488 | isl_assert(bmap->ctx, |
768 | 488 | isl_seq_first_non_zero(bmap->eq[j] + 1, i) == -1, |
769 | 488 | goto error); |
770 | 488 | isl_assert(bmap->ctx, |
771 | 488 | isl_int_is_one(bmap->eq[j][1 + i]) || |
772 | 488 | isl_int_is_negone(bmap->eq[j][1 + i]), |
773 | 488 | goto error); |
774 | 488 | isl_assert(bmap->ctx, |
775 | 488 | isl_seq_first_non_zero(bmap->eq[j]+1+i+1, dim-i-1) == -1, |
776 | 488 | goto error); |
777 | 488 | |
778 | 488 | isl_int_gcd(m, point->el[0], bmap->eq[j][1 + i]); |
779 | 488 | isl_int_divexact(m, bmap->eq[j][1 + i], m); |
780 | 488 | isl_int_abs(m, m); |
781 | 488 | isl_seq_scale(point->el, point->el, m, 1 + i); |
782 | 488 | isl_int_divexact(m, point->el[0], bmap->eq[j][1 + i]); |
783 | 488 | isl_int_neg(m, m); |
784 | 488 | isl_int_mul(point->el[1 + i], m, bmap->eq[j][0]); |
785 | 488 | } |
786 | 404 | |
787 | 404 | isl_int_clear(m); |
788 | 404 | return isl_point_alloc(isl_basic_map_get_space(bmap), point); |
789 | 0 | error: |
790 | 0 | isl_int_clear(m); |
791 | 0 | isl_vec_free(point); |
792 | 0 | return NULL; |
793 | 404 | } |
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 | | static isl_bool map_is_singleton_subset(__isl_keep isl_map *map1, |
800 | | __isl_keep isl_map *map2) |
801 | 404 | { |
802 | 404 | int i; |
803 | 404 | isl_bool is_subset = isl_bool_false; |
804 | 404 | struct isl_point *point; |
805 | 404 | |
806 | 404 | if (!map1 || !map2) |
807 | 0 | return isl_bool_error; |
808 | 404 | if (map1->n != 1) |
809 | 404 | isl_die0 (isl_map_get_ctx(map1), isl_error_invalid, |
810 | 404 | "expecting single-disjunct input", |
811 | 404 | return isl_bool_error); |
812 | 404 | |
813 | 404 | point = singleton_extract_point(map1->p[0]); |
814 | 404 | if (!point) |
815 | 0 | return isl_bool_error; |
816 | 404 | |
817 | 470 | for (i = 0; 404 i < map2->n; ++i66 ) { |
818 | 426 | is_subset = isl_basic_map_contains_point(map2->p[i], point); |
819 | 426 | if (is_subset) |
820 | 360 | break; |
821 | 426 | } |
822 | 404 | |
823 | 404 | isl_point_free(point); |
824 | 404 | return is_subset; |
825 | 404 | } |
826 | | |
827 | | static isl_bool map_is_subset(__isl_keep isl_map *map1, |
828 | | __isl_keep isl_map *map2) |
829 | 45.0k | { |
830 | 45.0k | isl_bool is_subset = isl_bool_false; |
831 | 45.0k | isl_bool empty, single; |
832 | 45.0k | isl_bool rat1, rat2; |
833 | 45.0k | |
834 | 45.0k | if (!map1 || !map2) |
835 | 0 | return isl_bool_error; |
836 | 45.0k | |
837 | 45.0k | if (!isl_map_has_equal_space(map1, map2)) |
838 | 159 | return isl_bool_false; |
839 | 44.9k | |
840 | 44.9k | empty = isl_map_is_empty(map1); |
841 | 44.9k | if (empty < 0) |
842 | 0 | return isl_bool_error; |
843 | 44.9k | if (empty) |
844 | 133 | return isl_bool_true; |
845 | 44.7k | |
846 | 44.7k | empty = isl_map_is_empty(map2); |
847 | 44.7k | if (empty < 0) |
848 | 0 | return isl_bool_error; |
849 | 44.7k | if (empty) |
850 | 17.6k | return isl_bool_false; |
851 | 27.1k | |
852 | 27.1k | rat1 = isl_map_has_rational(map1); |
853 | 27.1k | rat2 = isl_map_has_rational(map2); |
854 | 27.1k | if (rat1 < 0 || rat2 < 0) |
855 | 0 | return isl_bool_error; |
856 | 27.1k | if (rat1 && !rat214 ) |
857 | 2 | return isl_bool_false; |
858 | 27.1k | |
859 | 27.1k | if (isl_map_plain_is_universe(map2)) |
860 | 6.99k | return isl_bool_true; |
861 | 20.1k | |
862 | 20.1k | single = isl_map_plain_is_singleton(map1); |
863 | 20.1k | if (single < 0) |
864 | 0 | return isl_bool_error; |
865 | 20.1k | map2 = isl_map_compute_divs(isl_map_copy(map2)); |
866 | 20.1k | if (single) { |
867 | 404 | is_subset = map_is_singleton_subset(map1, map2); |
868 | 404 | isl_map_free(map2); |
869 | 404 | return is_subset; |
870 | 404 | } |
871 | 19.7k | is_subset = map_diff_is_empty(map1, map2); |
872 | 19.7k | isl_map_free(map2); |
873 | 19.7k | |
874 | 19.7k | return is_subset; |
875 | 19.7k | } |
876 | | |
877 | | isl_bool isl_map_is_subset(__isl_keep isl_map *map1, __isl_keep isl_map *map2) |
878 | 45.0k | { |
879 | 45.0k | return isl_map_align_params_map_map_and_test(map1, map2, |
880 | 45.0k | &map_is_subset); |
881 | 45.0k | } |
882 | | |
883 | | isl_bool isl_set_is_subset(__isl_keep isl_set *set1, __isl_keep isl_set *set2) |
884 | 24.8k | { |
885 | 24.8k | return isl_map_is_subset(set_to_map(set1), set_to_map(set2)); |
886 | 24.8k | } |
887 | | |
888 | | __isl_give isl_map *isl_map_make_disjoint(__isl_take isl_map *map) |
889 | 6.69k | { |
890 | 6.69k | int i; |
891 | 6.69k | struct isl_subtract_diff_collector sdc; |
892 | 6.69k | sdc.dc.add = &basic_map_subtract_add; |
893 | 6.69k | |
894 | 6.69k | if (!map) |
895 | 0 | return NULL; |
896 | 6.69k | if (ISL_F_ISSET(map, ISL_MAP_DISJOINT)) |
897 | 6.69k | return map3.57k ; |
898 | 3.12k | if (map->n <= 1) |
899 | 2.87k | return map; |
900 | 252 | |
901 | 252 | map = isl_map_compute_divs(map); |
902 | 252 | map = isl_map_remove_empty_parts(map); |
903 | 252 | |
904 | 252 | if (!map || map->n <= 1) |
905 | 0 | return map; |
906 | 252 | |
907 | 252 | sdc.diff = isl_map_from_basic_map(isl_basic_map_copy(map->p[0])); |
908 | 252 | |
909 | 682 | for (i = 1; i < map->n; ++i430 ) { |
910 | 430 | struct isl_basic_map *bmap = isl_basic_map_copy(map->p[i]); |
911 | 430 | struct isl_map *copy = isl_map_copy(sdc.diff); |
912 | 430 | 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 | 0 | } |
917 | 430 | } |
918 | 252 | |
919 | 252 | isl_map_free(map); |
920 | 252 | |
921 | 252 | return sdc.diff; |
922 | 252 | } |
923 | | |
924 | | __isl_give isl_set *isl_set_make_disjoint(__isl_take isl_set *set) |
925 | 6.66k | { |
926 | 6.66k | return set_from_map(isl_map_make_disjoint(set_to_map(set))); |
927 | 6.66k | } |
928 | | |
929 | | __isl_give isl_map *isl_map_complement(__isl_take isl_map *map) |
930 | 6.50k | { |
931 | 6.50k | isl_map *universe; |
932 | 6.50k | |
933 | 6.50k | if (!map) |
934 | 0 | return NULL; |
935 | 6.50k | |
936 | 6.50k | universe = isl_map_universe(isl_map_get_space(map)); |
937 | 6.50k | |
938 | 6.50k | return isl_map_subtract(universe, map); |
939 | 6.50k | } |
940 | | |
941 | | __isl_give isl_set *isl_set_complement(__isl_take isl_set *set) |
942 | 6.50k | { |
943 | 6.50k | return isl_map_complement(set); |
944 | 6.50k | } |