1 | /* |
2 | * Copyright 2008-2009 Katholieke Universiteit Leuven |
3 | * Copyright 2010 INRIA Saclay |
4 | * Copyright 2012-2014 Ecole Normale Superieure |
5 | * Copyright 2014 INRIA Rocquencourt |
6 | * Copyright 2016 INRIA Paris |
7 | * Copyright 2016 Sven Verdoolaege |
8 | * Copyright 2018-2019 Cerebras Systems |
9 | * |
10 | * Use of this software is governed by the MIT license |
11 | * |
12 | * Written by Sven Verdoolaege, K.U.Leuven, Departement |
13 | * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium |
14 | * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite, |
15 | * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France |
16 | * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France |
17 | * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, |
18 | * B.P. 105 - 78153 Le Chesnay, France |
19 | * and Centre de Recherche Inria de Paris, 2 rue Simone Iff - Voie DQ12, |
20 | * CS 42112, 75589 Paris Cedex 12, France |
21 | * and Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA |
22 | */ |
23 | |
24 | #include <string.h> |
25 | #include <isl_ctx_private.h> |
26 | #include <isl_map_private.h> |
27 | #include <isl_blk.h> |
28 | #include <isl_id_private.h> |
29 | #include <isl/constraint.h> |
30 | #include "isl_space_private.h" |
31 | #include "isl_equalities.h" |
32 | #include <isl_lp_private.h> |
33 | #include <isl_seq.h> |
34 | #include <isl/set.h> |
35 | #include <isl/map.h> |
36 | #include <isl_reordering.h> |
37 | #include "isl_sample.h" |
38 | #include <isl_sort.h> |
39 | #include "isl_tab.h" |
40 | #include <isl/vec.h> |
41 | #include <isl_mat_private.h> |
42 | #include <isl_vec_private.h> |
43 | #include <isl_dim_map.h> |
44 | #include <isl_local_space_private.h> |
45 | #include <isl_aff_private.h> |
46 | #include <isl_options_private.h> |
47 | #include <isl_morph.h> |
48 | #include <isl_val_private.h> |
49 | #include <isl_printer_private.h> |
50 | |
51 | #include <bset_to_bmap.c> |
52 | #include <bset_from_bmap.c> |
53 | #include <set_to_map.c> |
54 | #include <set_from_map.c> |
55 | |
56 | /* Treat "bset" as a basic map. |
57 | * Internally, isl_basic_set is defined to isl_basic_map, so in practice, |
58 | * this function performs a redundant cast. |
59 | */ |
60 | static __isl_keep const isl_basic_map *const_bset_to_bmap( |
61 | __isl_keep const isl_basic_set *bset) |
62 | { |
63 | return (const isl_basic_map *) bset; |
64 | } |
65 | |
66 | #undef TYPE |
67 | #define TYPE isl_basic_map |
68 | #include "has_single_reference_templ.c" |
69 | |
70 | static unsigned pos(__isl_keep isl_space *space, enum isl_dim_type type) |
71 | { |
72 | switch (type) { |
73 | case isl_dim_param: return 1; |
74 | case isl_dim_in: return 1 + space->nparam; |
75 | case isl_dim_out: return 1 + space->nparam + space->n_in; |
76 | default: return 0; |
77 | } |
78 | } |
79 | |
80 | isl_size isl_basic_map_dim(__isl_keep isl_basic_map *bmap, |
81 | enum isl_dim_type type) |
82 | { |
83 | if (!bmap) |
84 | return isl_size_error; |
85 | switch (type) { |
86 | case isl_dim_cst: return 1; |
87 | case isl_dim_param: |
88 | case isl_dim_in: |
89 | case isl_dim_out: return isl_space_dim(space: bmap->dim, type); |
90 | case isl_dim_div: return bmap->n_div; |
91 | case isl_dim_all: return isl_basic_map_total_dim(bmap); |
92 | default: return 0; |
93 | } |
94 | } |
95 | |
96 | /* Return the space of "map". |
97 | */ |
98 | __isl_keep isl_space *isl_map_peek_space(__isl_keep const isl_map *map) |
99 | { |
100 | return map ? map->dim : NULL; |
101 | } |
102 | |
103 | /* Return the space of "set". |
104 | */ |
105 | __isl_keep isl_space *isl_set_peek_space(__isl_keep isl_set *set) |
106 | { |
107 | return isl_map_peek_space(map: set_to_map(set)); |
108 | } |
109 | |
110 | isl_size isl_map_dim(__isl_keep isl_map *map, enum isl_dim_type type) |
111 | { |
112 | return isl_space_dim(space: isl_map_peek_space(map), type); |
113 | } |
114 | |
115 | /* Return the dimensionality of the domain (tuple) of the map. |
116 | */ |
117 | isl_size isl_map_domain_tuple_dim(__isl_keep isl_map *map) |
118 | { |
119 | return isl_map_dim(map, type: isl_dim_in); |
120 | } |
121 | |
122 | /* Return the dimensionality of the range (tuple) of the map. |
123 | */ |
124 | isl_size isl_map_range_tuple_dim(__isl_keep isl_map *map) |
125 | { |
126 | return isl_map_dim(map, type: isl_dim_out); |
127 | } |
128 | |
129 | isl_size isl_set_dim(__isl_keep isl_set *set, enum isl_dim_type type) |
130 | { |
131 | return isl_map_dim(map: set_to_map(set), type); |
132 | } |
133 | |
134 | /* Return the dimensionality of the (tuple of the) set. |
135 | */ |
136 | isl_size isl_set_tuple_dim(__isl_keep isl_set *set) |
137 | { |
138 | return isl_set_dim(set, type: isl_dim_set); |
139 | } |
140 | |
141 | /* Return the position of the variables of the given type |
142 | * within the sequence of variables of "bmap". |
143 | */ |
144 | isl_size isl_basic_map_var_offset(__isl_keep isl_basic_map *bmap, |
145 | enum isl_dim_type type) |
146 | { |
147 | isl_space *space; |
148 | |
149 | space = isl_basic_map_peek_space(bmap); |
150 | if (!space) |
151 | return isl_size_error; |
152 | |
153 | switch (type) { |
154 | case isl_dim_param: |
155 | case isl_dim_in: |
156 | case isl_dim_out: return isl_space_offset(space, type); |
157 | case isl_dim_div: return isl_space_dim(space, type: isl_dim_all); |
158 | case isl_dim_cst: |
159 | default: |
160 | isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, |
161 | "invalid dimension type" , return isl_size_error); |
162 | } |
163 | } |
164 | |
165 | /* Return the position of the variables of the given type |
166 | * within the sequence of variables of "bset". |
167 | */ |
168 | isl_size isl_basic_set_var_offset(__isl_keep isl_basic_set *bset, |
169 | enum isl_dim_type type) |
170 | { |
171 | return isl_basic_map_var_offset(bmap: bset_to_bmap(bset), type); |
172 | } |
173 | |
174 | /* Return the position of the coefficients of the variables of the given type |
175 | * within the sequence of coefficients of "bmap". |
176 | */ |
177 | unsigned isl_basic_map_offset(__isl_keep isl_basic_map *bmap, |
178 | enum isl_dim_type type) |
179 | { |
180 | switch (type) { |
181 | case isl_dim_cst: return 0; |
182 | case isl_dim_param: |
183 | case isl_dim_in: |
184 | case isl_dim_out: |
185 | case isl_dim_div: return 1 + isl_basic_map_var_offset(bmap, type); |
186 | default: return 0; |
187 | } |
188 | } |
189 | |
190 | unsigned isl_basic_set_offset(__isl_keep isl_basic_set *bset, |
191 | enum isl_dim_type type) |
192 | { |
193 | return isl_basic_map_offset(bmap: bset, type); |
194 | } |
195 | |
196 | static unsigned map_offset(__isl_keep isl_map *map, enum isl_dim_type type) |
197 | { |
198 | return pos(space: map->dim, type); |
199 | } |
200 | |
201 | isl_size isl_basic_set_dim(__isl_keep isl_basic_set *bset, |
202 | enum isl_dim_type type) |
203 | { |
204 | return isl_basic_map_dim(bmap: bset, type); |
205 | } |
206 | |
207 | isl_size isl_basic_set_n_dim(__isl_keep isl_basic_set *bset) |
208 | { |
209 | return isl_basic_set_dim(bset, type: isl_dim_set); |
210 | } |
211 | |
212 | isl_size isl_basic_set_n_param(__isl_keep isl_basic_set *bset) |
213 | { |
214 | return isl_basic_set_dim(bset, type: isl_dim_param); |
215 | } |
216 | |
217 | isl_size isl_basic_set_total_dim(__isl_keep const isl_basic_set *bset) |
218 | { |
219 | return isl_basic_map_total_dim(bmap: const_bset_to_bmap(bset)); |
220 | } |
221 | |
222 | isl_size isl_set_n_dim(__isl_keep isl_set *set) |
223 | { |
224 | return isl_set_dim(set, type: isl_dim_set); |
225 | } |
226 | |
227 | isl_size isl_set_n_param(__isl_keep isl_set *set) |
228 | { |
229 | return isl_set_dim(set, type: isl_dim_param); |
230 | } |
231 | |
232 | isl_size isl_basic_map_total_dim(__isl_keep const isl_basic_map *bmap) |
233 | { |
234 | isl_size dim; |
235 | |
236 | if (!bmap) |
237 | return isl_size_error; |
238 | dim = isl_space_dim(space: bmap->dim, type: isl_dim_all); |
239 | if (dim < 0) |
240 | return isl_size_error; |
241 | return dim + bmap->n_div; |
242 | } |
243 | |
244 | /* Return the number of equality constraints in the description of "bmap". |
245 | * Return isl_size_error on error. |
246 | */ |
247 | isl_size isl_basic_map_n_equality(__isl_keep isl_basic_map *bmap) |
248 | { |
249 | if (!bmap) |
250 | return isl_size_error; |
251 | return bmap->n_eq; |
252 | } |
253 | |
254 | /* Return the number of equality constraints in the description of "bset". |
255 | * Return isl_size_error on error. |
256 | */ |
257 | isl_size isl_basic_set_n_equality(__isl_keep isl_basic_set *bset) |
258 | { |
259 | return isl_basic_map_n_equality(bmap: bset_to_bmap(bset)); |
260 | } |
261 | |
262 | /* Return the number of inequality constraints in the description of "bmap". |
263 | * Return isl_size_error on error. |
264 | */ |
265 | isl_size isl_basic_map_n_inequality(__isl_keep isl_basic_map *bmap) |
266 | { |
267 | if (!bmap) |
268 | return isl_size_error; |
269 | return bmap->n_ineq; |
270 | } |
271 | |
272 | /* Return the number of inequality constraints in the description of "bset". |
273 | * Return isl_size_error on error. |
274 | */ |
275 | isl_size isl_basic_set_n_inequality(__isl_keep isl_basic_set *bset) |
276 | { |
277 | return isl_basic_map_n_inequality(bmap: bset_to_bmap(bset)); |
278 | } |
279 | |
280 | /* Do "bmap1" and "bmap2" have the same parameters? |
281 | */ |
282 | static isl_bool isl_basic_map_has_equal_params(__isl_keep isl_basic_map *bmap1, |
283 | __isl_keep isl_basic_map *bmap2) |
284 | { |
285 | isl_space *space1, *space2; |
286 | |
287 | space1 = isl_basic_map_peek_space(bmap: bmap1); |
288 | space2 = isl_basic_map_peek_space(bmap: bmap2); |
289 | return isl_space_has_equal_params(space1, space2); |
290 | } |
291 | |
292 | /* Do "map1" and "map2" have the same parameters? |
293 | */ |
294 | isl_bool isl_map_has_equal_params(__isl_keep isl_map *map1, |
295 | __isl_keep isl_map *map2) |
296 | { |
297 | isl_space *space1, *space2; |
298 | |
299 | space1 = isl_map_peek_space(map: map1); |
300 | space2 = isl_map_peek_space(map: map2); |
301 | return isl_space_has_equal_params(space1, space2); |
302 | } |
303 | |
304 | /* Do "map" and "set" have the same parameters? |
305 | */ |
306 | static isl_bool isl_map_set_has_equal_params(__isl_keep isl_map *map, |
307 | __isl_keep isl_set *set) |
308 | { |
309 | return isl_map_has_equal_params(map1: map, map2: set_to_map(set)); |
310 | } |
311 | |
312 | /* Is the tuple of type "type" of "bmap" the same as the single tuple of "bset"? |
313 | */ |
314 | static isl_bool isl_basic_map_set_tuple_is_equal(__isl_keep isl_basic_map *bmap, |
315 | enum isl_dim_type type, __isl_keep isl_basic_set *bset) |
316 | { |
317 | isl_space *bmap_space, *bset_space; |
318 | |
319 | bmap_space = isl_basic_map_peek_space(bmap); |
320 | bset_space = isl_basic_set_peek_space(bset); |
321 | return isl_space_tuple_is_equal(space1: bmap_space, type1: type, |
322 | space2: bset_space, type2: isl_dim_set); |
323 | } |
324 | |
325 | /* Is the tuple of type "type" of "map" the same as the single tuple of "set"? |
326 | */ |
327 | static isl_bool isl_map_set_tuple_is_equal(__isl_keep isl_map *map, |
328 | enum isl_dim_type type, __isl_keep isl_set *set) |
329 | { |
330 | return isl_map_tuple_is_equal(map1: map, type1: type, map2: set_to_map(set), type2: isl_dim_set); |
331 | } |
332 | |
333 | isl_bool isl_map_compatible_domain(__isl_keep isl_map *map, |
334 | __isl_keep isl_set *set) |
335 | { |
336 | isl_bool m; |
337 | if (!map || !set) |
338 | return isl_bool_error; |
339 | m = isl_map_has_equal_params(map1: map, map2: set_to_map(set)); |
340 | if (m < 0 || !m) |
341 | return m; |
342 | return isl_map_set_tuple_is_equal(map, type: isl_dim_in, set); |
343 | } |
344 | |
345 | isl_bool isl_basic_map_compatible_domain(__isl_keep isl_basic_map *bmap, |
346 | __isl_keep isl_basic_set *bset) |
347 | { |
348 | isl_bool m; |
349 | if (!bmap || !bset) |
350 | return isl_bool_error; |
351 | m = isl_basic_map_has_equal_params(bmap1: bmap, bmap2: bset_to_bmap(bset)); |
352 | if (m < 0 || !m) |
353 | return m; |
354 | return isl_basic_map_set_tuple_is_equal(bmap, type: isl_dim_in, bset); |
355 | } |
356 | |
357 | isl_bool isl_map_compatible_range(__isl_keep isl_map *map, |
358 | __isl_keep isl_set *set) |
359 | { |
360 | isl_bool m; |
361 | if (!map || !set) |
362 | return isl_bool_error; |
363 | m = isl_map_has_equal_params(map1: map, map2: set_to_map(set)); |
364 | if (m < 0 || !m) |
365 | return m; |
366 | return isl_map_set_tuple_is_equal(map, type: isl_dim_out, set); |
367 | } |
368 | |
369 | isl_bool isl_basic_map_compatible_range(__isl_keep isl_basic_map *bmap, |
370 | __isl_keep isl_basic_set *bset) |
371 | { |
372 | isl_bool m; |
373 | if (!bmap || !bset) |
374 | return isl_bool_error; |
375 | m = isl_basic_map_has_equal_params(bmap1: bmap, bmap2: bset_to_bmap(bset)); |
376 | if (m < 0 || !m) |
377 | return m; |
378 | return isl_basic_map_set_tuple_is_equal(bmap, type: isl_dim_out, bset); |
379 | } |
380 | |
381 | isl_ctx *isl_basic_map_get_ctx(__isl_keep isl_basic_map *bmap) |
382 | { |
383 | return bmap ? bmap->ctx : NULL; |
384 | } |
385 | |
386 | isl_ctx *isl_basic_set_get_ctx(__isl_keep isl_basic_set *bset) |
387 | { |
388 | return bset ? bset->ctx : NULL; |
389 | } |
390 | |
391 | isl_ctx *isl_map_get_ctx(__isl_keep isl_map *map) |
392 | { |
393 | return map ? map->ctx : NULL; |
394 | } |
395 | |
396 | isl_ctx *isl_set_get_ctx(__isl_keep isl_set *set) |
397 | { |
398 | return set ? set->ctx : NULL; |
399 | } |
400 | |
401 | /* Return the space of "bmap". |
402 | */ |
403 | __isl_keep isl_space *isl_basic_map_peek_space( |
404 | __isl_keep const isl_basic_map *bmap) |
405 | { |
406 | return bmap ? bmap->dim : NULL; |
407 | } |
408 | |
409 | /* Return the space of "bset". |
410 | */ |
411 | __isl_keep isl_space *isl_basic_set_peek_space(__isl_keep isl_basic_set *bset) |
412 | { |
413 | return isl_basic_map_peek_space(bmap: bset_to_bmap(bset)); |
414 | } |
415 | |
416 | __isl_give isl_space *isl_basic_map_get_space(__isl_keep isl_basic_map *bmap) |
417 | { |
418 | return isl_space_copy(space: isl_basic_map_peek_space(bmap)); |
419 | } |
420 | |
421 | __isl_give isl_space *isl_basic_set_get_space(__isl_keep isl_basic_set *bset) |
422 | { |
423 | return isl_basic_map_get_space(bmap: bset_to_bmap(bset)); |
424 | } |
425 | |
426 | /* Return the space of "bmap". |
427 | * This may be either a copy or the space itself |
428 | * if there is only one reference to "bmap". |
429 | * This allows the space to be modified inplace |
430 | * if both the basic map and its space have only a single reference. |
431 | * The caller is not allowed to modify "bmap" between this call and |
432 | * a subsequent call to isl_basic_map_restore_space. |
433 | * The only exception is that isl_basic_map_free can be called instead. |
434 | */ |
435 | static __isl_give isl_space *isl_basic_map_take_space( |
436 | __isl_keep isl_basic_map *bmap) |
437 | { |
438 | isl_space *space; |
439 | |
440 | if (!bmap) |
441 | return NULL; |
442 | if (bmap->ref != 1) |
443 | return isl_basic_map_get_space(bmap); |
444 | space = bmap->dim; |
445 | bmap->dim = NULL; |
446 | return space; |
447 | } |
448 | |
449 | /* Set the space of "bmap" to "space", where the space of "bmap" may be missing |
450 | * due to a preceding call to isl_basic_map_take_space. |
451 | * However, in this case, "bmap" only has a single reference and |
452 | * then the call to isl_basic_map_cow has no effect. |
453 | */ |
454 | static __isl_give isl_basic_map *isl_basic_map_restore_space( |
455 | __isl_take isl_basic_map *bmap, __isl_take isl_space *space) |
456 | { |
457 | if (!bmap || !space) |
458 | goto error; |
459 | |
460 | if (bmap->dim == space) { |
461 | isl_space_free(space); |
462 | return bmap; |
463 | } |
464 | |
465 | bmap = isl_basic_map_cow(bmap); |
466 | if (!bmap) |
467 | goto error; |
468 | isl_space_free(space: bmap->dim); |
469 | bmap->dim = space; |
470 | |
471 | return bmap; |
472 | error: |
473 | isl_basic_map_free(bmap); |
474 | isl_space_free(space); |
475 | return NULL; |
476 | } |
477 | |
478 | /* Extract the divs in "bmap" as a matrix. |
479 | */ |
480 | __isl_give isl_mat *isl_basic_map_get_divs(__isl_keep isl_basic_map *bmap) |
481 | { |
482 | int i; |
483 | isl_ctx *ctx; |
484 | isl_mat *div; |
485 | isl_size v_div; |
486 | unsigned cols; |
487 | |
488 | v_div = isl_basic_map_var_offset(bmap, type: isl_dim_div); |
489 | if (v_div < 0) |
490 | return NULL; |
491 | |
492 | ctx = isl_basic_map_get_ctx(bmap); |
493 | cols = 1 + 1 + v_div + bmap->n_div; |
494 | div = isl_mat_alloc(ctx, n_row: bmap->n_div, n_col: cols); |
495 | if (!div) |
496 | return NULL; |
497 | |
498 | for (i = 0; i < bmap->n_div; ++i) |
499 | isl_seq_cpy(dst: div->row[i], src: bmap->div[i], len: cols); |
500 | |
501 | return div; |
502 | } |
503 | |
504 | /* Extract the divs in "bset" as a matrix. |
505 | */ |
506 | __isl_give isl_mat *isl_basic_set_get_divs(__isl_keep isl_basic_set *bset) |
507 | { |
508 | return isl_basic_map_get_divs(bmap: bset); |
509 | } |
510 | |
511 | __isl_give isl_local_space *isl_basic_map_get_local_space( |
512 | __isl_keep isl_basic_map *bmap) |
513 | { |
514 | isl_mat *div; |
515 | |
516 | if (!bmap) |
517 | return NULL; |
518 | |
519 | div = isl_basic_map_get_divs(bmap); |
520 | return isl_local_space_alloc_div(space: isl_space_copy(space: bmap->dim), div); |
521 | } |
522 | |
523 | __isl_give isl_local_space *isl_basic_set_get_local_space( |
524 | __isl_keep isl_basic_set *bset) |
525 | { |
526 | return isl_basic_map_get_local_space(bmap: bset); |
527 | } |
528 | |
529 | /* For each known div d = floor(f/m), add the constraints |
530 | * |
531 | * f - m d >= 0 |
532 | * -(f-(m-1)) + m d >= 0 |
533 | * |
534 | * Do not finalize the result. |
535 | */ |
536 | static __isl_give isl_basic_map *add_known_div_constraints( |
537 | __isl_take isl_basic_map *bmap) |
538 | { |
539 | int i; |
540 | isl_size n_div; |
541 | |
542 | n_div = isl_basic_map_dim(bmap, type: isl_dim_div); |
543 | if (n_div < 0) |
544 | return isl_basic_map_free(bmap); |
545 | if (n_div == 0) |
546 | return bmap; |
547 | bmap = isl_basic_map_cow(bmap); |
548 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq: 0, n_ineq: 2 * n_div); |
549 | if (!bmap) |
550 | return NULL; |
551 | for (i = 0; i < n_div; ++i) { |
552 | if (isl_int_is_zero(bmap->div[i][0])) |
553 | continue; |
554 | bmap = isl_basic_map_add_div_constraints(bmap, div: i); |
555 | } |
556 | |
557 | return bmap; |
558 | } |
559 | |
560 | __isl_give isl_basic_map *isl_basic_map_from_local_space( |
561 | __isl_take isl_local_space *ls) |
562 | { |
563 | int i; |
564 | isl_size n_div; |
565 | isl_basic_map *bmap; |
566 | |
567 | n_div = isl_local_space_dim(ls, type: isl_dim_div); |
568 | if (n_div < 0) |
569 | ls = isl_local_space_free(ls); |
570 | if (!ls) |
571 | return NULL; |
572 | |
573 | bmap = isl_basic_map_alloc_space(space: isl_local_space_get_space(ls), |
574 | extra: n_div, n_eq: 0, n_ineq: 2 * n_div); |
575 | |
576 | for (i = 0; i < n_div; ++i) |
577 | if (isl_basic_map_alloc_div(bmap) < 0) |
578 | goto error; |
579 | |
580 | for (i = 0; i < n_div; ++i) |
581 | isl_seq_cpy(dst: bmap->div[i], src: ls->div->row[i], len: ls->div->n_col); |
582 | bmap = add_known_div_constraints(bmap); |
583 | |
584 | isl_local_space_free(ls); |
585 | return bmap; |
586 | error: |
587 | isl_local_space_free(ls); |
588 | isl_basic_map_free(bmap); |
589 | return NULL; |
590 | } |
591 | |
592 | __isl_give isl_basic_set *isl_basic_set_from_local_space( |
593 | __isl_take isl_local_space *ls) |
594 | { |
595 | return isl_basic_map_from_local_space(ls); |
596 | } |
597 | |
598 | __isl_give isl_space *isl_map_get_space(__isl_keep isl_map *map) |
599 | { |
600 | return isl_space_copy(space: isl_map_peek_space(map)); |
601 | } |
602 | |
603 | __isl_give isl_space *isl_set_get_space(__isl_keep isl_set *set) |
604 | { |
605 | if (!set) |
606 | return NULL; |
607 | return isl_space_copy(space: set->dim); |
608 | } |
609 | |
610 | /* Return the space of "map". |
611 | * This may be either a copy or the space itself |
612 | * if there is only one reference to "map". |
613 | * This allows the space to be modified inplace |
614 | * if both the map and its space have only a single reference. |
615 | * The caller is not allowed to modify "map" between this call and |
616 | * a subsequent call to isl_map_restore_space. |
617 | * The only exception is that isl_map_free can be called instead. |
618 | */ |
619 | static __isl_give isl_space *isl_map_take_space(__isl_keep isl_map *map) |
620 | { |
621 | isl_space *space; |
622 | |
623 | if (!map) |
624 | return NULL; |
625 | if (map->ref != 1) |
626 | return isl_map_get_space(map); |
627 | space = map->dim; |
628 | map->dim = NULL; |
629 | return space; |
630 | } |
631 | |
632 | /* Set the space of "map" to "space", where the space of "map" may be missing |
633 | * due to a preceding call to isl_map_take_space. |
634 | * However, in this case, "map" only has a single reference and |
635 | * then the call to isl_map_cow has no effect. |
636 | */ |
637 | static __isl_give isl_map *isl_map_restore_space(__isl_take isl_map *map, |
638 | __isl_take isl_space *space) |
639 | { |
640 | if (!map || !space) |
641 | goto error; |
642 | |
643 | if (map->dim == space) { |
644 | isl_space_free(space); |
645 | return map; |
646 | } |
647 | |
648 | map = isl_map_cow(map); |
649 | if (!map) |
650 | goto error; |
651 | isl_space_free(space: map->dim); |
652 | map->dim = space; |
653 | |
654 | return map; |
655 | error: |
656 | isl_map_free(map); |
657 | isl_space_free(space); |
658 | return NULL; |
659 | } |
660 | |
661 | __isl_give isl_basic_map *isl_basic_map_set_tuple_name( |
662 | __isl_take isl_basic_map *bmap, enum isl_dim_type type, const char *s) |
663 | { |
664 | isl_space *space; |
665 | |
666 | space = isl_basic_map_take_space(bmap); |
667 | space = isl_space_set_tuple_name(space, type, s); |
668 | bmap = isl_basic_map_restore_space(bmap, space); |
669 | bmap = isl_basic_map_finalize(bmap); |
670 | return bmap; |
671 | } |
672 | |
673 | __isl_give isl_basic_set *isl_basic_set_set_tuple_name( |
674 | __isl_take isl_basic_set *bset, const char *s) |
675 | { |
676 | return isl_basic_map_set_tuple_name(bmap: bset, type: isl_dim_set, s); |
677 | } |
678 | |
679 | const char *isl_basic_map_get_tuple_name(__isl_keep isl_basic_map *bmap, |
680 | enum isl_dim_type type) |
681 | { |
682 | return bmap ? isl_space_get_tuple_name(space: bmap->dim, type) : NULL; |
683 | } |
684 | |
685 | __isl_give isl_map *isl_map_set_tuple_name(__isl_take isl_map *map, |
686 | enum isl_dim_type type, const char *s) |
687 | { |
688 | int i; |
689 | isl_space *space; |
690 | |
691 | map = isl_map_cow(map); |
692 | if (!map) |
693 | return NULL; |
694 | |
695 | for (i = 0; i < map->n; ++i) { |
696 | map->p[i] = isl_basic_map_set_tuple_name(bmap: map->p[i], type, s); |
697 | if (!map->p[i]) |
698 | goto error; |
699 | } |
700 | |
701 | space = isl_map_take_space(map); |
702 | space = isl_space_set_tuple_name(space, type, s); |
703 | map = isl_map_restore_space(map, space); |
704 | |
705 | return map; |
706 | error: |
707 | isl_map_free(map); |
708 | return NULL; |
709 | } |
710 | |
711 | /* Replace the identifier of the tuple of type "type" by "id". |
712 | */ |
713 | __isl_give isl_basic_map *isl_basic_map_set_tuple_id( |
714 | __isl_take isl_basic_map *bmap, |
715 | enum isl_dim_type type, __isl_take isl_id *id) |
716 | { |
717 | isl_space *space; |
718 | |
719 | space = isl_basic_map_take_space(bmap); |
720 | space = isl_space_set_tuple_id(space, type, id); |
721 | bmap = isl_basic_map_restore_space(bmap, space); |
722 | bmap = isl_basic_map_finalize(bmap); |
723 | return bmap; |
724 | } |
725 | |
726 | /* Replace the identifier of the tuple by "id". |
727 | */ |
728 | __isl_give isl_basic_set *isl_basic_set_set_tuple_id( |
729 | __isl_take isl_basic_set *bset, __isl_take isl_id *id) |
730 | { |
731 | return isl_basic_map_set_tuple_id(bmap: bset, type: isl_dim_set, id); |
732 | } |
733 | |
734 | /* Does the input or output tuple have a name? |
735 | */ |
736 | isl_bool isl_map_has_tuple_name(__isl_keep isl_map *map, enum isl_dim_type type) |
737 | { |
738 | return map ? isl_space_has_tuple_name(space: map->dim, type) : isl_bool_error; |
739 | } |
740 | |
741 | const char *isl_map_get_tuple_name(__isl_keep isl_map *map, |
742 | enum isl_dim_type type) |
743 | { |
744 | return map ? isl_space_get_tuple_name(space: map->dim, type) : NULL; |
745 | } |
746 | |
747 | __isl_give isl_set *isl_set_set_tuple_name(__isl_take isl_set *set, |
748 | const char *s) |
749 | { |
750 | return set_from_map(isl_map_set_tuple_name(map: set_to_map(set), |
751 | type: isl_dim_set, s)); |
752 | } |
753 | |
754 | __isl_give isl_map *isl_map_set_tuple_id(__isl_take isl_map *map, |
755 | enum isl_dim_type type, __isl_take isl_id *id) |
756 | { |
757 | isl_space *space; |
758 | |
759 | space = isl_map_take_space(map); |
760 | space = isl_space_set_tuple_id(space, type, id); |
761 | map = isl_map_restore_space(map, space); |
762 | |
763 | return isl_map_reset_space(map, space: isl_map_get_space(map)); |
764 | } |
765 | |
766 | /* Replace the identifier of the domain tuple of "map" by "id". |
767 | */ |
768 | __isl_give isl_map *isl_map_set_domain_tuple_id(__isl_take isl_map *map, |
769 | __isl_take isl_id *id) |
770 | { |
771 | return isl_map_set_tuple_id(map, type: isl_dim_in, id); |
772 | } |
773 | |
774 | /* Replace the identifier of the range tuple of "map" by "id". |
775 | */ |
776 | __isl_give isl_map *isl_map_set_range_tuple_id(__isl_take isl_map *map, |
777 | __isl_take isl_id *id) |
778 | { |
779 | return isl_map_set_tuple_id(map, type: isl_dim_out, id); |
780 | } |
781 | |
782 | __isl_give isl_set *isl_set_set_tuple_id(__isl_take isl_set *set, |
783 | __isl_take isl_id *id) |
784 | { |
785 | return isl_map_set_tuple_id(map: set, type: isl_dim_set, id); |
786 | } |
787 | |
788 | __isl_give isl_map *isl_map_reset_tuple_id(__isl_take isl_map *map, |
789 | enum isl_dim_type type) |
790 | { |
791 | isl_space *space; |
792 | |
793 | space = isl_map_take_space(map); |
794 | space = isl_space_reset_tuple_id(space, type); |
795 | map = isl_map_restore_space(map, space); |
796 | |
797 | return isl_map_reset_space(map, space: isl_map_get_space(map)); |
798 | } |
799 | |
800 | __isl_give isl_set *isl_set_reset_tuple_id(__isl_take isl_set *set) |
801 | { |
802 | return isl_map_reset_tuple_id(map: set, type: isl_dim_set); |
803 | } |
804 | |
805 | isl_bool isl_map_has_tuple_id(__isl_keep isl_map *map, enum isl_dim_type type) |
806 | { |
807 | return map ? isl_space_has_tuple_id(space: map->dim, type) : isl_bool_error; |
808 | } |
809 | |
810 | /* Does the domain tuple of "map" have an identifier? |
811 | */ |
812 | isl_bool isl_map_has_domain_tuple_id(__isl_keep isl_map *map) |
813 | { |
814 | return isl_map_has_tuple_id(map, type: isl_dim_in); |
815 | } |
816 | |
817 | /* Does the range tuple of "map" have an identifier? |
818 | */ |
819 | isl_bool isl_map_has_range_tuple_id(__isl_keep isl_map *map) |
820 | { |
821 | return isl_map_has_tuple_id(map, type: isl_dim_out); |
822 | } |
823 | |
824 | __isl_give isl_id *isl_map_get_tuple_id(__isl_keep isl_map *map, |
825 | enum isl_dim_type type) |
826 | { |
827 | return map ? isl_space_get_tuple_id(space: map->dim, type) : NULL; |
828 | } |
829 | |
830 | /* Return the identifier of the domain tuple of "map", assuming it has one. |
831 | */ |
832 | __isl_give isl_id *isl_map_get_domain_tuple_id(__isl_keep isl_map *map) |
833 | { |
834 | return isl_map_get_tuple_id(map, type: isl_dim_in); |
835 | } |
836 | |
837 | /* Return the identifier of the range tuple of "map", assuming it has one. |
838 | */ |
839 | __isl_give isl_id *isl_map_get_range_tuple_id(__isl_keep isl_map *map) |
840 | { |
841 | return isl_map_get_tuple_id(map, type: isl_dim_out); |
842 | } |
843 | |
844 | isl_bool isl_set_has_tuple_id(__isl_keep isl_set *set) |
845 | { |
846 | return isl_map_has_tuple_id(map: set, type: isl_dim_set); |
847 | } |
848 | |
849 | __isl_give isl_id *isl_set_get_tuple_id(__isl_keep isl_set *set) |
850 | { |
851 | return isl_map_get_tuple_id(map: set, type: isl_dim_set); |
852 | } |
853 | |
854 | /* Does the set tuple have a name? |
855 | */ |
856 | isl_bool isl_set_has_tuple_name(__isl_keep isl_set *set) |
857 | { |
858 | if (!set) |
859 | return isl_bool_error; |
860 | return isl_space_has_tuple_name(space: set->dim, type: isl_dim_set); |
861 | } |
862 | |
863 | |
864 | const char *isl_basic_set_get_tuple_name(__isl_keep isl_basic_set *bset) |
865 | { |
866 | return bset ? isl_space_get_tuple_name(space: bset->dim, type: isl_dim_set) : NULL; |
867 | } |
868 | |
869 | const char *isl_set_get_tuple_name(__isl_keep isl_set *set) |
870 | { |
871 | return set ? isl_space_get_tuple_name(space: set->dim, type: isl_dim_set) : NULL; |
872 | } |
873 | |
874 | const char *isl_basic_map_get_dim_name(__isl_keep isl_basic_map *bmap, |
875 | enum isl_dim_type type, unsigned pos) |
876 | { |
877 | return bmap ? isl_space_get_dim_name(space: bmap->dim, type, pos) : NULL; |
878 | } |
879 | |
880 | const char *isl_basic_set_get_dim_name(__isl_keep isl_basic_set *bset, |
881 | enum isl_dim_type type, unsigned pos) |
882 | { |
883 | return bset ? isl_space_get_dim_name(space: bset->dim, type, pos) : NULL; |
884 | } |
885 | |
886 | /* Does the given dimension have a name? |
887 | */ |
888 | isl_bool isl_map_has_dim_name(__isl_keep isl_map *map, |
889 | enum isl_dim_type type, unsigned pos) |
890 | { |
891 | if (!map) |
892 | return isl_bool_error; |
893 | return isl_space_has_dim_name(space: map->dim, type, pos); |
894 | } |
895 | |
896 | const char *isl_map_get_dim_name(__isl_keep isl_map *map, |
897 | enum isl_dim_type type, unsigned pos) |
898 | { |
899 | return map ? isl_space_get_dim_name(space: map->dim, type, pos) : NULL; |
900 | } |
901 | |
902 | const char *isl_set_get_dim_name(__isl_keep isl_set *set, |
903 | enum isl_dim_type type, unsigned pos) |
904 | { |
905 | return set ? isl_space_get_dim_name(space: set->dim, type, pos) : NULL; |
906 | } |
907 | |
908 | /* Does the given dimension have a name? |
909 | */ |
910 | isl_bool isl_set_has_dim_name(__isl_keep isl_set *set, |
911 | enum isl_dim_type type, unsigned pos) |
912 | { |
913 | if (!set) |
914 | return isl_bool_error; |
915 | return isl_space_has_dim_name(space: set->dim, type, pos); |
916 | } |
917 | |
918 | __isl_give isl_basic_map *isl_basic_map_set_dim_name( |
919 | __isl_take isl_basic_map *bmap, |
920 | enum isl_dim_type type, unsigned pos, const char *s) |
921 | { |
922 | isl_space *space; |
923 | |
924 | space = isl_basic_map_take_space(bmap); |
925 | space = isl_space_set_dim_name(space, type, pos, name: s); |
926 | bmap = isl_basic_map_restore_space(bmap, space); |
927 | return isl_basic_map_finalize(bmap); |
928 | } |
929 | |
930 | __isl_give isl_map *isl_map_set_dim_name(__isl_take isl_map *map, |
931 | enum isl_dim_type type, unsigned pos, const char *s) |
932 | { |
933 | int i; |
934 | isl_space *space; |
935 | |
936 | map = isl_map_cow(map); |
937 | if (!map) |
938 | return NULL; |
939 | |
940 | for (i = 0; i < map->n; ++i) { |
941 | map->p[i] = isl_basic_map_set_dim_name(bmap: map->p[i], type, pos, s); |
942 | if (!map->p[i]) |
943 | goto error; |
944 | } |
945 | |
946 | space = isl_map_take_space(map); |
947 | space = isl_space_set_dim_name(space, type, pos, name: s); |
948 | map = isl_map_restore_space(map, space); |
949 | |
950 | return map; |
951 | error: |
952 | isl_map_free(map); |
953 | return NULL; |
954 | } |
955 | |
956 | __isl_give isl_basic_set *isl_basic_set_set_dim_name( |
957 | __isl_take isl_basic_set *bset, |
958 | enum isl_dim_type type, unsigned pos, const char *s) |
959 | { |
960 | return bset_from_bmap(bmap: isl_basic_map_set_dim_name(bmap: bset_to_bmap(bset), |
961 | type, pos, s)); |
962 | } |
963 | |
964 | __isl_give isl_set *isl_set_set_dim_name(__isl_take isl_set *set, |
965 | enum isl_dim_type type, unsigned pos, const char *s) |
966 | { |
967 | return set_from_map(isl_map_set_dim_name(map: set_to_map(set), |
968 | type, pos, s)); |
969 | } |
970 | |
971 | isl_bool isl_basic_map_has_dim_id(__isl_keep isl_basic_map *bmap, |
972 | enum isl_dim_type type, unsigned pos) |
973 | { |
974 | if (!bmap) |
975 | return isl_bool_error; |
976 | return isl_space_has_dim_id(space: bmap->dim, type, pos); |
977 | } |
978 | |
979 | __isl_give isl_id *isl_basic_set_get_dim_id(__isl_keep isl_basic_set *bset, |
980 | enum isl_dim_type type, unsigned pos) |
981 | { |
982 | return bset ? isl_space_get_dim_id(space: bset->dim, type, pos) : NULL; |
983 | } |
984 | |
985 | isl_bool isl_map_has_dim_id(__isl_keep isl_map *map, |
986 | enum isl_dim_type type, unsigned pos) |
987 | { |
988 | return map ? isl_space_has_dim_id(space: map->dim, type, pos) : isl_bool_error; |
989 | } |
990 | |
991 | __isl_give isl_id *isl_map_get_dim_id(__isl_keep isl_map *map, |
992 | enum isl_dim_type type, unsigned pos) |
993 | { |
994 | return map ? isl_space_get_dim_id(space: map->dim, type, pos) : NULL; |
995 | } |
996 | |
997 | isl_bool isl_set_has_dim_id(__isl_keep isl_set *set, |
998 | enum isl_dim_type type, unsigned pos) |
999 | { |
1000 | return isl_map_has_dim_id(map: set, type, pos); |
1001 | } |
1002 | |
1003 | __isl_give isl_id *isl_set_get_dim_id(__isl_keep isl_set *set, |
1004 | enum isl_dim_type type, unsigned pos) |
1005 | { |
1006 | return isl_map_get_dim_id(map: set, type, pos); |
1007 | } |
1008 | |
1009 | __isl_give isl_map *isl_map_set_dim_id(__isl_take isl_map *map, |
1010 | enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) |
1011 | { |
1012 | isl_space *space; |
1013 | |
1014 | space = isl_map_take_space(map); |
1015 | space = isl_space_set_dim_id(space, type, pos, id); |
1016 | map = isl_map_restore_space(map, space); |
1017 | |
1018 | return isl_map_reset_space(map, space: isl_map_get_space(map)); |
1019 | } |
1020 | |
1021 | __isl_give isl_set *isl_set_set_dim_id(__isl_take isl_set *set, |
1022 | enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) |
1023 | { |
1024 | return isl_map_set_dim_id(map: set, type, pos, id); |
1025 | } |
1026 | |
1027 | int isl_map_find_dim_by_id(__isl_keep isl_map *map, enum isl_dim_type type, |
1028 | __isl_keep isl_id *id) |
1029 | { |
1030 | if (!map) |
1031 | return -1; |
1032 | return isl_space_find_dim_by_id(space: map->dim, type, id); |
1033 | } |
1034 | |
1035 | int isl_set_find_dim_by_id(__isl_keep isl_set *set, enum isl_dim_type type, |
1036 | __isl_keep isl_id *id) |
1037 | { |
1038 | return isl_map_find_dim_by_id(map: set, type, id); |
1039 | } |
1040 | |
1041 | /* Return the position of the dimension of the given type and name |
1042 | * in "bmap". |
1043 | * Return -1 if no such dimension can be found. |
1044 | */ |
1045 | int isl_basic_map_find_dim_by_name(__isl_keep isl_basic_map *bmap, |
1046 | enum isl_dim_type type, const char *name) |
1047 | { |
1048 | if (!bmap) |
1049 | return -1; |
1050 | return isl_space_find_dim_by_name(space: bmap->dim, type, name); |
1051 | } |
1052 | |
1053 | int isl_map_find_dim_by_name(__isl_keep isl_map *map, enum isl_dim_type type, |
1054 | const char *name) |
1055 | { |
1056 | if (!map) |
1057 | return -1; |
1058 | return isl_space_find_dim_by_name(space: map->dim, type, name); |
1059 | } |
1060 | |
1061 | int isl_set_find_dim_by_name(__isl_keep isl_set *set, enum isl_dim_type type, |
1062 | const char *name) |
1063 | { |
1064 | return isl_map_find_dim_by_name(map: set, type, name); |
1065 | } |
1066 | |
1067 | /* Check whether equality i of bset is a pure stride constraint |
1068 | * on a single dimension, i.e., of the form |
1069 | * |
1070 | * v = k e |
1071 | * |
1072 | * with k a constant and e an existentially quantified variable. |
1073 | */ |
1074 | isl_bool isl_basic_set_eq_is_stride(__isl_keep isl_basic_set *bset, int i) |
1075 | { |
1076 | isl_size nparam; |
1077 | isl_size d; |
1078 | isl_size n_div; |
1079 | int pos1; |
1080 | int pos2; |
1081 | |
1082 | nparam = isl_basic_set_dim(bset, type: isl_dim_param); |
1083 | d = isl_basic_set_dim(bset, type: isl_dim_set); |
1084 | n_div = isl_basic_set_dim(bset, type: isl_dim_div); |
1085 | if (nparam < 0 || d < 0 || n_div < 0) |
1086 | return isl_bool_error; |
1087 | |
1088 | if (!isl_int_is_zero(bset->eq[i][0])) |
1089 | return isl_bool_false; |
1090 | |
1091 | if (isl_seq_first_non_zero(p: bset->eq[i] + 1, len: nparam) != -1) |
1092 | return isl_bool_false; |
1093 | pos1 = isl_seq_first_non_zero(p: bset->eq[i] + 1 + nparam, len: d); |
1094 | if (pos1 == -1) |
1095 | return isl_bool_false; |
1096 | if (isl_seq_first_non_zero(p: bset->eq[i] + 1 + nparam + pos1 + 1, |
1097 | len: d - pos1 - 1) != -1) |
1098 | return isl_bool_false; |
1099 | |
1100 | pos2 = isl_seq_first_non_zero(p: bset->eq[i] + 1 + nparam + d, len: n_div); |
1101 | if (pos2 == -1) |
1102 | return isl_bool_false; |
1103 | if (isl_seq_first_non_zero(p: bset->eq[i] + 1 + nparam + d + pos2 + 1, |
1104 | len: n_div - pos2 - 1) != -1) |
1105 | return isl_bool_false; |
1106 | if (!isl_int_is_one(bset->eq[i][1 + nparam + pos1]) && |
1107 | !isl_int_is_negone(bset->eq[i][1 + nparam + pos1])) |
1108 | return isl_bool_false; |
1109 | |
1110 | return isl_bool_true; |
1111 | } |
1112 | |
1113 | /* Reset the user pointer on all identifiers of parameters and tuples |
1114 | * of the space of "map". |
1115 | */ |
1116 | __isl_give isl_map *isl_map_reset_user(__isl_take isl_map *map) |
1117 | { |
1118 | isl_space *space; |
1119 | |
1120 | space = isl_map_get_space(map); |
1121 | space = isl_space_reset_user(space); |
1122 | map = isl_map_reset_space(map, space); |
1123 | |
1124 | return map; |
1125 | } |
1126 | |
1127 | /* Reset the user pointer on all identifiers of parameters and tuples |
1128 | * of the space of "set". |
1129 | */ |
1130 | __isl_give isl_set *isl_set_reset_user(__isl_take isl_set *set) |
1131 | { |
1132 | return isl_map_reset_user(map: set); |
1133 | } |
1134 | |
1135 | isl_bool isl_basic_map_is_rational(__isl_keep isl_basic_map *bmap) |
1136 | { |
1137 | if (!bmap) |
1138 | return isl_bool_error; |
1139 | return ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL); |
1140 | } |
1141 | |
1142 | /* Has "map" been marked as a rational map? |
1143 | * In particular, have all basic maps in "map" been marked this way? |
1144 | * An empty map is not considered to be rational. |
1145 | * Maps where only some of the basic maps are marked rational |
1146 | * are not allowed. |
1147 | */ |
1148 | isl_bool isl_map_is_rational(__isl_keep isl_map *map) |
1149 | { |
1150 | int i; |
1151 | isl_bool rational; |
1152 | |
1153 | if (!map) |
1154 | return isl_bool_error; |
1155 | if (map->n == 0) |
1156 | return isl_bool_false; |
1157 | rational = isl_basic_map_is_rational(bmap: map->p[0]); |
1158 | if (rational < 0) |
1159 | return rational; |
1160 | for (i = 1; i < map->n; ++i) { |
1161 | isl_bool rational_i; |
1162 | |
1163 | rational_i = isl_basic_map_is_rational(bmap: map->p[i]); |
1164 | if (rational_i < 0) |
1165 | return rational_i; |
1166 | if (rational != rational_i) |
1167 | isl_die(isl_map_get_ctx(map), isl_error_unsupported, |
1168 | "mixed rational and integer basic maps " |
1169 | "not supported" , return isl_bool_error); |
1170 | } |
1171 | |
1172 | return rational; |
1173 | } |
1174 | |
1175 | /* Has "set" been marked as a rational set? |
1176 | * In particular, have all basic set in "set" been marked this way? |
1177 | * An empty set is not considered to be rational. |
1178 | * Sets where only some of the basic sets are marked rational |
1179 | * are not allowed. |
1180 | */ |
1181 | isl_bool isl_set_is_rational(__isl_keep isl_set *set) |
1182 | { |
1183 | return isl_map_is_rational(map: set); |
1184 | } |
1185 | |
1186 | int isl_basic_set_is_rational(__isl_keep isl_basic_set *bset) |
1187 | { |
1188 | return isl_basic_map_is_rational(bmap: bset); |
1189 | } |
1190 | |
1191 | /* Does "bmap" contain any rational points? |
1192 | * |
1193 | * If "bmap" has an equality for each dimension, equating the dimension |
1194 | * to an integer constant, then it has no rational points, even if it |
1195 | * is marked as rational. |
1196 | */ |
1197 | isl_bool isl_basic_map_has_rational(__isl_keep isl_basic_map *bmap) |
1198 | { |
1199 | isl_bool has_rational = isl_bool_true; |
1200 | isl_size total; |
1201 | |
1202 | if (!bmap) |
1203 | return isl_bool_error; |
1204 | if (isl_basic_map_plain_is_empty(bmap)) |
1205 | return isl_bool_false; |
1206 | if (!isl_basic_map_is_rational(bmap)) |
1207 | return isl_bool_false; |
1208 | bmap = isl_basic_map_copy(bmap); |
1209 | bmap = isl_basic_map_implicit_equalities(bmap); |
1210 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
1211 | if (total < 0) |
1212 | return isl_bool_error; |
1213 | if (bmap->n_eq == total) { |
1214 | int i, j; |
1215 | for (i = 0; i < bmap->n_eq; ++i) { |
1216 | j = isl_seq_first_non_zero(p: bmap->eq[i] + 1, len: total); |
1217 | if (j < 0) |
1218 | break; |
1219 | if (!isl_int_is_one(bmap->eq[i][1 + j]) && |
1220 | !isl_int_is_negone(bmap->eq[i][1 + j])) |
1221 | break; |
1222 | j = isl_seq_first_non_zero(p: bmap->eq[i] + 1 + j + 1, |
1223 | len: total - j - 1); |
1224 | if (j >= 0) |
1225 | break; |
1226 | } |
1227 | if (i == bmap->n_eq) |
1228 | has_rational = isl_bool_false; |
1229 | } |
1230 | isl_basic_map_free(bmap); |
1231 | |
1232 | return has_rational; |
1233 | } |
1234 | |
1235 | /* Does "map" contain any rational points? |
1236 | */ |
1237 | isl_bool isl_map_has_rational(__isl_keep isl_map *map) |
1238 | { |
1239 | int i; |
1240 | isl_bool has_rational; |
1241 | |
1242 | if (!map) |
1243 | return isl_bool_error; |
1244 | for (i = 0; i < map->n; ++i) { |
1245 | has_rational = isl_basic_map_has_rational(bmap: map->p[i]); |
1246 | if (has_rational < 0 || has_rational) |
1247 | return has_rational; |
1248 | } |
1249 | return isl_bool_false; |
1250 | } |
1251 | |
1252 | /* Does "set" contain any rational points? |
1253 | */ |
1254 | isl_bool isl_set_has_rational(__isl_keep isl_set *set) |
1255 | { |
1256 | return isl_map_has_rational(map: set); |
1257 | } |
1258 | |
1259 | /* Is this basic set a parameter domain? |
1260 | */ |
1261 | isl_bool isl_basic_set_is_params(__isl_keep isl_basic_set *bset) |
1262 | { |
1263 | if (!bset) |
1264 | return isl_bool_error; |
1265 | return isl_space_is_params(space: bset->dim); |
1266 | } |
1267 | |
1268 | /* Is this set a parameter domain? |
1269 | */ |
1270 | isl_bool isl_set_is_params(__isl_keep isl_set *set) |
1271 | { |
1272 | if (!set) |
1273 | return isl_bool_error; |
1274 | return isl_space_is_params(space: set->dim); |
1275 | } |
1276 | |
1277 | /* Is this map actually a parameter domain? |
1278 | * Users should never call this function. Outside of isl, |
1279 | * a map can never be a parameter domain. |
1280 | */ |
1281 | isl_bool isl_map_is_params(__isl_keep isl_map *map) |
1282 | { |
1283 | if (!map) |
1284 | return isl_bool_error; |
1285 | return isl_space_is_params(space: map->dim); |
1286 | } |
1287 | |
1288 | static __isl_give isl_basic_map *basic_map_init(isl_ctx *ctx, |
1289 | __isl_take isl_basic_map *bmap, unsigned , |
1290 | unsigned n_eq, unsigned n_ineq) |
1291 | { |
1292 | int i; |
1293 | isl_space *space = isl_basic_map_peek_space(bmap); |
1294 | isl_size n_var = isl_space_dim(space, type: isl_dim_all); |
1295 | size_t row_size = 1 + n_var + extra; |
1296 | |
1297 | bmap->ctx = ctx; |
1298 | isl_ctx_ref(ctx); |
1299 | |
1300 | if (n_var < 0) |
1301 | return isl_basic_map_free(bmap); |
1302 | |
1303 | bmap->block = isl_blk_alloc(ctx, n: (n_ineq + n_eq) * row_size); |
1304 | if (isl_blk_is_error(block: bmap->block)) |
1305 | goto error; |
1306 | |
1307 | bmap->ineq = isl_alloc_array(ctx, isl_int *, n_ineq + n_eq); |
1308 | if ((n_ineq + n_eq) && !bmap->ineq) |
1309 | goto error; |
1310 | |
1311 | if (extra == 0) { |
1312 | bmap->block2 = isl_blk_empty(); |
1313 | bmap->div = NULL; |
1314 | } else { |
1315 | bmap->block2 = isl_blk_alloc(ctx, n: extra * (1 + row_size)); |
1316 | if (isl_blk_is_error(block: bmap->block2)) |
1317 | goto error; |
1318 | |
1319 | bmap->div = isl_alloc_array(ctx, isl_int *, extra); |
1320 | if (!bmap->div) |
1321 | goto error; |
1322 | } |
1323 | |
1324 | for (i = 0; i < n_ineq + n_eq; ++i) |
1325 | bmap->ineq[i] = bmap->block.data + i * row_size; |
1326 | |
1327 | for (i = 0; i < extra; ++i) |
1328 | bmap->div[i] = bmap->block2.data + i * (1 + row_size); |
1329 | |
1330 | bmap->ref = 1; |
1331 | bmap->flags = 0; |
1332 | bmap->c_size = n_eq + n_ineq; |
1333 | bmap->eq = bmap->ineq + n_ineq; |
1334 | bmap->extra = extra; |
1335 | bmap->n_eq = 0; |
1336 | bmap->n_ineq = 0; |
1337 | bmap->n_div = 0; |
1338 | bmap->sample = NULL; |
1339 | |
1340 | return bmap; |
1341 | error: |
1342 | isl_basic_map_free(bmap); |
1343 | return NULL; |
1344 | } |
1345 | |
1346 | __isl_give isl_basic_set *isl_basic_set_alloc(isl_ctx *ctx, |
1347 | unsigned nparam, unsigned dim, unsigned , |
1348 | unsigned n_eq, unsigned n_ineq) |
1349 | { |
1350 | struct isl_basic_map *bmap; |
1351 | isl_space *space; |
1352 | |
1353 | space = isl_space_set_alloc(ctx, nparam, dim); |
1354 | if (!space) |
1355 | return NULL; |
1356 | |
1357 | bmap = isl_basic_map_alloc_space(space, extra, n_eq, n_ineq); |
1358 | return bset_from_bmap(bmap); |
1359 | } |
1360 | |
1361 | __isl_give isl_basic_set *isl_basic_set_alloc_space(__isl_take isl_space *space, |
1362 | unsigned , unsigned n_eq, unsigned n_ineq) |
1363 | { |
1364 | struct isl_basic_map *bmap; |
1365 | if (!space) |
1366 | return NULL; |
1367 | isl_assert(space->ctx, space->n_in == 0, goto error); |
1368 | bmap = isl_basic_map_alloc_space(space, extra, n_eq, n_ineq); |
1369 | return bset_from_bmap(bmap); |
1370 | error: |
1371 | isl_space_free(space); |
1372 | return NULL; |
1373 | } |
1374 | |
1375 | __isl_give isl_basic_map *isl_basic_map_alloc_space(__isl_take isl_space *space, |
1376 | unsigned , unsigned n_eq, unsigned n_ineq) |
1377 | { |
1378 | struct isl_basic_map *bmap; |
1379 | |
1380 | if (!space) |
1381 | return NULL; |
1382 | bmap = isl_calloc_type(space->ctx, struct isl_basic_map); |
1383 | if (!bmap) |
1384 | goto error; |
1385 | bmap->dim = space; |
1386 | |
1387 | return basic_map_init(ctx: space->ctx, bmap, extra, n_eq, n_ineq); |
1388 | error: |
1389 | isl_space_free(space); |
1390 | return NULL; |
1391 | } |
1392 | |
1393 | __isl_give isl_basic_map *isl_basic_map_alloc(isl_ctx *ctx, |
1394 | unsigned nparam, unsigned in, unsigned out, unsigned , |
1395 | unsigned n_eq, unsigned n_ineq) |
1396 | { |
1397 | struct isl_basic_map *bmap; |
1398 | isl_space *space; |
1399 | |
1400 | space = isl_space_alloc(ctx, nparam, n_in: in, n_out: out); |
1401 | if (!space) |
1402 | return NULL; |
1403 | |
1404 | bmap = isl_basic_map_alloc_space(space, extra, n_eq, n_ineq); |
1405 | return bmap; |
1406 | } |
1407 | |
1408 | static __isl_give isl_basic_map *dup_constraints(__isl_take isl_basic_map *dst, |
1409 | __isl_keep isl_basic_map *src) |
1410 | { |
1411 | int i; |
1412 | isl_size total = isl_basic_map_dim(bmap: src, type: isl_dim_all); |
1413 | |
1414 | if (!dst || total < 0) |
1415 | return isl_basic_map_free(bmap: dst); |
1416 | |
1417 | for (i = 0; i < src->n_eq; ++i) { |
1418 | int j = isl_basic_map_alloc_equality(bmap: dst); |
1419 | if (j < 0) |
1420 | return isl_basic_map_free(bmap: dst); |
1421 | isl_seq_cpy(dst: dst->eq[j], src: src->eq[i], len: 1+total); |
1422 | } |
1423 | |
1424 | for (i = 0; i < src->n_ineq; ++i) { |
1425 | int j = isl_basic_map_alloc_inequality(bmap: dst); |
1426 | if (j < 0) |
1427 | return isl_basic_map_free(bmap: dst); |
1428 | isl_seq_cpy(dst: dst->ineq[j], src: src->ineq[i], len: 1+total); |
1429 | } |
1430 | |
1431 | for (i = 0; i < src->n_div; ++i) { |
1432 | int j = isl_basic_map_alloc_div(bmap: dst); |
1433 | if (j < 0) |
1434 | return isl_basic_map_free(bmap: dst); |
1435 | isl_seq_cpy(dst: dst->div[j], src: src->div[i], len: 1+1+total); |
1436 | } |
1437 | ISL_F_SET(dst, ISL_BASIC_SET_FINAL); |
1438 | return dst; |
1439 | } |
1440 | |
1441 | __isl_give isl_basic_map *isl_basic_map_dup(__isl_keep isl_basic_map *bmap) |
1442 | { |
1443 | struct isl_basic_map *dup; |
1444 | |
1445 | if (!bmap) |
1446 | return NULL; |
1447 | dup = isl_basic_map_alloc_space(space: isl_space_copy(space: bmap->dim), |
1448 | extra: bmap->n_div, n_eq: bmap->n_eq, n_ineq: bmap->n_ineq); |
1449 | dup = dup_constraints(dst: dup, src: bmap); |
1450 | if (!dup) |
1451 | return NULL; |
1452 | dup->flags = bmap->flags; |
1453 | dup->sample = isl_vec_copy(vec: bmap->sample); |
1454 | return dup; |
1455 | } |
1456 | |
1457 | __isl_give isl_basic_set *isl_basic_set_dup(__isl_keep isl_basic_set *bset) |
1458 | { |
1459 | struct isl_basic_map *dup; |
1460 | |
1461 | dup = isl_basic_map_dup(bmap: bset_to_bmap(bset)); |
1462 | return bset_from_bmap(bmap: dup); |
1463 | } |
1464 | |
1465 | __isl_give isl_basic_set *isl_basic_set_copy(__isl_keep isl_basic_set *bset) |
1466 | { |
1467 | return bset_from_bmap(bmap: isl_basic_map_copy(bmap: bset_to_bmap(bset))); |
1468 | } |
1469 | |
1470 | __isl_give isl_set *isl_set_copy(__isl_keep isl_set *set) |
1471 | { |
1472 | if (!set) |
1473 | return NULL; |
1474 | |
1475 | set->ref++; |
1476 | return set; |
1477 | } |
1478 | |
1479 | __isl_give isl_basic_map *isl_basic_map_copy(__isl_keep isl_basic_map *bmap) |
1480 | { |
1481 | if (!bmap) |
1482 | return NULL; |
1483 | |
1484 | if (ISL_F_ISSET(bmap, ISL_BASIC_SET_FINAL)) { |
1485 | bmap->ref++; |
1486 | return bmap; |
1487 | } |
1488 | bmap = isl_basic_map_dup(bmap); |
1489 | if (bmap) |
1490 | ISL_F_SET(bmap, ISL_BASIC_SET_FINAL); |
1491 | return bmap; |
1492 | } |
1493 | |
1494 | __isl_give isl_map *isl_map_copy(__isl_keep isl_map *map) |
1495 | { |
1496 | if (!map) |
1497 | return NULL; |
1498 | |
1499 | map->ref++; |
1500 | return map; |
1501 | } |
1502 | |
1503 | __isl_null isl_basic_map *isl_basic_map_free(__isl_take isl_basic_map *bmap) |
1504 | { |
1505 | if (!bmap) |
1506 | return NULL; |
1507 | |
1508 | if (--bmap->ref > 0) |
1509 | return NULL; |
1510 | |
1511 | isl_ctx_deref(ctx: bmap->ctx); |
1512 | free(ptr: bmap->div); |
1513 | isl_blk_free(ctx: bmap->ctx, block: bmap->block2); |
1514 | free(ptr: bmap->ineq); |
1515 | isl_blk_free(ctx: bmap->ctx, block: bmap->block); |
1516 | isl_vec_free(vec: bmap->sample); |
1517 | isl_space_free(space: bmap->dim); |
1518 | free(ptr: bmap); |
1519 | |
1520 | return NULL; |
1521 | } |
1522 | |
1523 | __isl_null isl_basic_set *isl_basic_set_free(__isl_take isl_basic_set *bset) |
1524 | { |
1525 | return isl_basic_map_free(bmap: bset_to_bmap(bset)); |
1526 | } |
1527 | |
1528 | static int room_for_con(__isl_keep isl_basic_map *bmap, unsigned n) |
1529 | { |
1530 | return bmap->n_eq + bmap->n_ineq + n <= bmap->c_size; |
1531 | } |
1532 | |
1533 | /* Check that "bset" does not involve any parameters. |
1534 | */ |
1535 | isl_stat isl_basic_set_check_no_params(__isl_keep isl_basic_set *bset) |
1536 | { |
1537 | isl_size nparam; |
1538 | |
1539 | nparam = isl_basic_set_dim(bset, type: isl_dim_param); |
1540 | if (nparam < 0) |
1541 | return isl_stat_error; |
1542 | if (nparam != 0) |
1543 | isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid, |
1544 | "basic set should not have any parameters" , |
1545 | return isl_stat_error); |
1546 | return isl_stat_ok; |
1547 | } |
1548 | |
1549 | /* Check that "bset" does not involve any local variables. |
1550 | */ |
1551 | isl_stat isl_basic_set_check_no_locals(__isl_keep isl_basic_set *bset) |
1552 | { |
1553 | isl_size n_div; |
1554 | |
1555 | n_div = isl_basic_set_dim(bset, type: isl_dim_div); |
1556 | if (n_div < 0) |
1557 | return isl_stat_error; |
1558 | if (n_div != 0) |
1559 | isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid, |
1560 | "basic set should not have any local variables" , |
1561 | return isl_stat_error); |
1562 | return isl_stat_ok; |
1563 | } |
1564 | |
1565 | #undef TYPE |
1566 | #define TYPE isl_map |
1567 | |
1568 | #include "isl_check_named_params_templ.c" |
1569 | |
1570 | #undef TYPE |
1571 | #define TYPE isl_basic_map |
1572 | |
1573 | static |
1574 | #include "isl_check_named_params_templ.c" |
1575 | |
1576 | /* Check that "bmap1" and "bmap2" have the same parameters, |
1577 | * reporting an error if they do not. |
1578 | */ |
1579 | static isl_stat isl_basic_map_check_equal_params( |
1580 | __isl_keep isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2) |
1581 | { |
1582 | isl_bool match; |
1583 | |
1584 | match = isl_basic_map_has_equal_params(bmap1, bmap2); |
1585 | if (match < 0) |
1586 | return isl_stat_error; |
1587 | if (!match) |
1588 | isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid, |
1589 | "parameters don't match" , return isl_stat_error); |
1590 | return isl_stat_ok; |
1591 | } |
1592 | |
1593 | #undef TYPE |
1594 | #define TYPE isl_map |
1595 | |
1596 | #include "isl_align_params_bin_templ.c" |
1597 | |
1598 | #undef SUFFIX |
1599 | #define SUFFIX set |
1600 | #undef ARG1 |
1601 | #define ARG1 isl_map |
1602 | #undef ARG2 |
1603 | #define ARG2 isl_set |
1604 | |
1605 | #include "isl_align_params_templ.c" |
1606 | |
1607 | isl_bool isl_map_align_params_map_map_and_test(__isl_keep isl_map *map1, |
1608 | __isl_keep isl_map *map2, |
1609 | isl_bool (*fn)(__isl_keep isl_map *map1, __isl_keep isl_map *map2)) |
1610 | { |
1611 | isl_bool r; |
1612 | |
1613 | if (!map1 || !map2) |
1614 | return isl_bool_error; |
1615 | if (isl_map_has_equal_params(map1, map2)) |
1616 | return fn(map1, map2); |
1617 | if (isl_map_check_named_params(obj: map1) < 0) |
1618 | return isl_bool_error; |
1619 | if (isl_map_check_named_params(obj: map2) < 0) |
1620 | return isl_bool_error; |
1621 | map1 = isl_map_copy(map: map1); |
1622 | map2 = isl_map_copy(map: map2); |
1623 | map1 = isl_map_align_params(map: map1, model: isl_map_get_space(map: map2)); |
1624 | map2 = isl_map_align_params(map: map2, model: isl_map_get_space(map: map1)); |
1625 | r = fn(map1, map2); |
1626 | isl_map_free(map: map1); |
1627 | isl_map_free(map: map2); |
1628 | return r; |
1629 | } |
1630 | |
1631 | int isl_basic_map_alloc_equality(__isl_keep isl_basic_map *bmap) |
1632 | { |
1633 | isl_size total; |
1634 | struct isl_ctx *ctx; |
1635 | |
1636 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
1637 | if (total < 0) |
1638 | return -1; |
1639 | ctx = bmap->ctx; |
1640 | isl_assert(ctx, room_for_con(bmap, 1), return -1); |
1641 | isl_assert(ctx, (bmap->eq - bmap->ineq) + bmap->n_eq <= bmap->c_size, |
1642 | return -1); |
1643 | ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT); |
1644 | ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_IMPLICIT); |
1645 | ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES); |
1646 | ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS); |
1647 | if ((bmap->eq - bmap->ineq) + bmap->n_eq == bmap->c_size) { |
1648 | isl_int *t; |
1649 | int j = isl_basic_map_alloc_inequality(bmap); |
1650 | if (j < 0) |
1651 | return -1; |
1652 | t = bmap->ineq[j]; |
1653 | bmap->ineq[j] = bmap->ineq[bmap->n_ineq - 1]; |
1654 | bmap->ineq[bmap->n_ineq - 1] = bmap->eq[-1]; |
1655 | bmap->eq[-1] = t; |
1656 | bmap->n_eq++; |
1657 | bmap->n_ineq--; |
1658 | bmap->eq--; |
1659 | return 0; |
1660 | } |
1661 | isl_seq_clr(p: bmap->eq[bmap->n_eq] + 1 + total, |
1662 | len: bmap->extra - bmap->n_div); |
1663 | return bmap->n_eq++; |
1664 | } |
1665 | |
1666 | int isl_basic_set_alloc_equality(__isl_keep isl_basic_set *bset) |
1667 | { |
1668 | return isl_basic_map_alloc_equality(bmap: bset_to_bmap(bset)); |
1669 | } |
1670 | |
1671 | __isl_give isl_basic_map *isl_basic_map_free_equality( |
1672 | __isl_take isl_basic_map *bmap, unsigned n) |
1673 | { |
1674 | if (!bmap) |
1675 | return NULL; |
1676 | if (n > bmap->n_eq) |
1677 | isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, |
1678 | "invalid number of equalities" , |
1679 | isl_basic_map_free(bmap)); |
1680 | bmap->n_eq -= n; |
1681 | return bmap; |
1682 | } |
1683 | |
1684 | __isl_give isl_basic_set *isl_basic_set_free_equality( |
1685 | __isl_take isl_basic_set *bset, unsigned n) |
1686 | { |
1687 | return bset_from_bmap(bmap: isl_basic_map_free_equality(bmap: bset_to_bmap(bset), |
1688 | n)); |
1689 | } |
1690 | |
1691 | /* Drop the equality constraint at position "pos", |
1692 | * preserving the order of the other equality constraints. |
1693 | */ |
1694 | int isl_basic_map_drop_equality(__isl_keep isl_basic_map *bmap, unsigned pos) |
1695 | { |
1696 | isl_int *t; |
1697 | int r; |
1698 | |
1699 | if (!bmap) |
1700 | return -1; |
1701 | isl_assert(bmap->ctx, pos < bmap->n_eq, return -1); |
1702 | |
1703 | t = bmap->eq[pos]; |
1704 | bmap->n_eq--; |
1705 | for (r = pos; r < bmap->n_eq; ++r) |
1706 | bmap->eq[r] = bmap->eq[r + 1]; |
1707 | bmap->eq[bmap->n_eq] = t; |
1708 | |
1709 | return 0; |
1710 | } |
1711 | |
1712 | /* Turn inequality "pos" of "bmap" into an equality. |
1713 | * |
1714 | * In particular, we move the inequality in front of the equalities |
1715 | * and move the last inequality in the position of the moved inequality. |
1716 | * Note that isl_tab_make_equalities_explicit depends on this particular |
1717 | * change in the ordering of the constraints. |
1718 | */ |
1719 | void isl_basic_map_inequality_to_equality( |
1720 | __isl_keep isl_basic_map *bmap, unsigned pos) |
1721 | { |
1722 | isl_int *t; |
1723 | |
1724 | t = bmap->ineq[pos]; |
1725 | bmap->ineq[pos] = bmap->ineq[bmap->n_ineq - 1]; |
1726 | bmap->ineq[bmap->n_ineq - 1] = bmap->eq[-1]; |
1727 | bmap->eq[-1] = t; |
1728 | bmap->n_eq++; |
1729 | bmap->n_ineq--; |
1730 | bmap->eq--; |
1731 | ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT); |
1732 | ISL_F_CLR(bmap, ISL_BASIC_MAP_SORTED); |
1733 | ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS); |
1734 | ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES); |
1735 | } |
1736 | |
1737 | static int room_for_ineq(__isl_keep isl_basic_map *bmap, unsigned n) |
1738 | { |
1739 | return bmap->n_ineq + n <= bmap->eq - bmap->ineq; |
1740 | } |
1741 | |
1742 | int isl_basic_map_alloc_inequality(__isl_keep isl_basic_map *bmap) |
1743 | { |
1744 | isl_size total; |
1745 | struct isl_ctx *ctx; |
1746 | |
1747 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
1748 | if (total < 0) |
1749 | return -1; |
1750 | ctx = bmap->ctx; |
1751 | isl_assert(ctx, room_for_ineq(bmap, 1), return -1); |
1752 | ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_IMPLICIT); |
1753 | ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT); |
1754 | ISL_F_CLR(bmap, ISL_BASIC_MAP_SORTED); |
1755 | ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES); |
1756 | isl_seq_clr(p: bmap->ineq[bmap->n_ineq] + 1 + total, |
1757 | len: bmap->extra - bmap->n_div); |
1758 | return bmap->n_ineq++; |
1759 | } |
1760 | |
1761 | int isl_basic_set_alloc_inequality(__isl_keep isl_basic_set *bset) |
1762 | { |
1763 | return isl_basic_map_alloc_inequality(bmap: bset_to_bmap(bset)); |
1764 | } |
1765 | |
1766 | __isl_give isl_basic_map *isl_basic_map_free_inequality( |
1767 | __isl_take isl_basic_map *bmap, unsigned n) |
1768 | { |
1769 | if (!bmap) |
1770 | return NULL; |
1771 | if (n > bmap->n_ineq) |
1772 | isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, |
1773 | "invalid number of inequalities" , |
1774 | return isl_basic_map_free(bmap)); |
1775 | bmap->n_ineq -= n; |
1776 | return bmap; |
1777 | } |
1778 | |
1779 | __isl_give isl_basic_set *isl_basic_set_free_inequality( |
1780 | __isl_take isl_basic_set *bset, unsigned n) |
1781 | { |
1782 | return bset_from_bmap(bmap: isl_basic_map_free_inequality(bmap: bset_to_bmap(bset), |
1783 | n)); |
1784 | } |
1785 | |
1786 | int isl_basic_map_drop_inequality(__isl_keep isl_basic_map *bmap, unsigned pos) |
1787 | { |
1788 | isl_int *t; |
1789 | if (!bmap) |
1790 | return -1; |
1791 | isl_assert(bmap->ctx, pos < bmap->n_ineq, return -1); |
1792 | |
1793 | if (pos != bmap->n_ineq - 1) { |
1794 | t = bmap->ineq[pos]; |
1795 | bmap->ineq[pos] = bmap->ineq[bmap->n_ineq - 1]; |
1796 | bmap->ineq[bmap->n_ineq - 1] = t; |
1797 | ISL_F_CLR(bmap, ISL_BASIC_MAP_SORTED); |
1798 | } |
1799 | bmap->n_ineq--; |
1800 | return 0; |
1801 | } |
1802 | |
1803 | int isl_basic_set_drop_inequality(__isl_keep isl_basic_set *bset, unsigned pos) |
1804 | { |
1805 | return isl_basic_map_drop_inequality(bmap: bset_to_bmap(bset), pos); |
1806 | } |
1807 | |
1808 | __isl_give isl_basic_map *isl_basic_map_add_eq(__isl_take isl_basic_map *bmap, |
1809 | isl_int *eq) |
1810 | { |
1811 | isl_bool empty; |
1812 | isl_size total; |
1813 | int k; |
1814 | |
1815 | empty = isl_basic_map_plain_is_empty(bmap); |
1816 | if (empty < 0) |
1817 | return isl_basic_map_free(bmap); |
1818 | if (empty) |
1819 | return bmap; |
1820 | |
1821 | bmap = isl_basic_map_cow(bmap); |
1822 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq: 1, n_ineq: 0); |
1823 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
1824 | if (total < 0) |
1825 | return isl_basic_map_free(bmap); |
1826 | k = isl_basic_map_alloc_equality(bmap); |
1827 | if (k < 0) |
1828 | goto error; |
1829 | isl_seq_cpy(dst: bmap->eq[k], src: eq, len: 1 + total); |
1830 | return bmap; |
1831 | error: |
1832 | isl_basic_map_free(bmap); |
1833 | return NULL; |
1834 | } |
1835 | |
1836 | __isl_give isl_basic_set *isl_basic_set_add_eq(__isl_take isl_basic_set *bset, |
1837 | isl_int *eq) |
1838 | { |
1839 | return bset_from_bmap(bmap: isl_basic_map_add_eq(bmap: bset_to_bmap(bset), eq)); |
1840 | } |
1841 | |
1842 | __isl_give isl_basic_map *isl_basic_map_add_ineq(__isl_take isl_basic_map *bmap, |
1843 | isl_int *ineq) |
1844 | { |
1845 | isl_size total; |
1846 | int k; |
1847 | |
1848 | bmap = isl_basic_map_cow(bmap); |
1849 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq: 0, n_ineq: 1); |
1850 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
1851 | if (total < 0) |
1852 | return isl_basic_map_free(bmap); |
1853 | k = isl_basic_map_alloc_inequality(bmap); |
1854 | if (k < 0) |
1855 | goto error; |
1856 | isl_seq_cpy(dst: bmap->ineq[k], src: ineq, len: 1 + total); |
1857 | return bmap; |
1858 | error: |
1859 | isl_basic_map_free(bmap); |
1860 | return NULL; |
1861 | } |
1862 | |
1863 | __isl_give isl_basic_set *isl_basic_set_add_ineq(__isl_take isl_basic_set *bset, |
1864 | isl_int *ineq) |
1865 | { |
1866 | return bset_from_bmap(bmap: isl_basic_map_add_ineq(bmap: bset_to_bmap(bset), ineq)); |
1867 | } |
1868 | |
1869 | int isl_basic_map_alloc_div(__isl_keep isl_basic_map *bmap) |
1870 | { |
1871 | isl_size total; |
1872 | |
1873 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
1874 | if (total < 0) |
1875 | return -1; |
1876 | isl_assert(bmap->ctx, bmap->n_div < bmap->extra, return -1); |
1877 | isl_seq_clr(p: bmap->div[bmap->n_div] + 1 + 1 + total, |
1878 | len: bmap->extra - bmap->n_div); |
1879 | ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS); |
1880 | return bmap->n_div++; |
1881 | } |
1882 | |
1883 | int isl_basic_set_alloc_div(__isl_keep isl_basic_set *bset) |
1884 | { |
1885 | return isl_basic_map_alloc_div(bmap: bset_to_bmap(bset)); |
1886 | } |
1887 | |
1888 | #undef TYPE |
1889 | #define TYPE isl_basic_map |
1890 | #include "check_type_range_templ.c" |
1891 | |
1892 | /* Check that there are "n" dimensions of type "type" starting at "first" |
1893 | * in "bset". |
1894 | */ |
1895 | isl_stat isl_basic_set_check_range(__isl_keep isl_basic_set *bset, |
1896 | enum isl_dim_type type, unsigned first, unsigned n) |
1897 | { |
1898 | return isl_basic_map_check_range(obj: bset_to_bmap(bset), |
1899 | type, first, n); |
1900 | } |
1901 | |
1902 | /* Insert an extra integer division, prescribed by "div", to "bmap" |
1903 | * at (integer division) position "pos". |
1904 | * |
1905 | * The integer division is first added at the end and then moved |
1906 | * into the right position. |
1907 | */ |
1908 | __isl_give isl_basic_map *isl_basic_map_insert_div( |
1909 | __isl_take isl_basic_map *bmap, int pos, __isl_keep isl_vec *div) |
1910 | { |
1911 | int i, k; |
1912 | isl_size total; |
1913 | |
1914 | bmap = isl_basic_map_cow(bmap); |
1915 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
1916 | if (total < 0 || !div) |
1917 | return isl_basic_map_free(bmap); |
1918 | |
1919 | if (div->size != 1 + 1 + total) |
1920 | isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, |
1921 | "unexpected size" , return isl_basic_map_free(bmap)); |
1922 | if (isl_basic_map_check_range(obj: bmap, type: isl_dim_div, first: pos, n: 0) < 0) |
1923 | return isl_basic_map_free(bmap); |
1924 | |
1925 | bmap = isl_basic_map_extend(base: bmap, extra: 1, n_eq: 0, n_ineq: 2); |
1926 | k = isl_basic_map_alloc_div(bmap); |
1927 | if (k < 0) |
1928 | return isl_basic_map_free(bmap); |
1929 | isl_seq_cpy(dst: bmap->div[k], src: div->el, len: div->size); |
1930 | isl_int_set_si(bmap->div[k][div->size], 0); |
1931 | |
1932 | for (i = k; i > pos; --i) |
1933 | bmap = isl_basic_map_swap_div(bmap, a: i, b: i - 1); |
1934 | |
1935 | return bmap; |
1936 | } |
1937 | |
1938 | isl_stat isl_basic_map_free_div(__isl_keep isl_basic_map *bmap, unsigned n) |
1939 | { |
1940 | if (!bmap) |
1941 | return isl_stat_error; |
1942 | isl_assert(bmap->ctx, n <= bmap->n_div, return isl_stat_error); |
1943 | bmap->n_div -= n; |
1944 | return isl_stat_ok; |
1945 | } |
1946 | |
1947 | static __isl_give isl_basic_map *add_constraints( |
1948 | __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2, |
1949 | unsigned i_pos, unsigned o_pos) |
1950 | { |
1951 | isl_size total, n_param, n_in, n_out, n_div; |
1952 | unsigned o_in, o_out; |
1953 | isl_ctx *ctx; |
1954 | isl_space *space; |
1955 | struct isl_dim_map *dim_map; |
1956 | |
1957 | space = isl_basic_map_peek_space(bmap: bmap2); |
1958 | if (!bmap1 || !space) |
1959 | goto error; |
1960 | |
1961 | total = isl_basic_map_dim(bmap: bmap1, type: isl_dim_all); |
1962 | n_param = isl_basic_map_dim(bmap: bmap2, type: isl_dim_param); |
1963 | n_in = isl_basic_map_dim(bmap: bmap2, type: isl_dim_in); |
1964 | o_in = isl_basic_map_offset(bmap: bmap1, type: isl_dim_in) - 1 + i_pos; |
1965 | n_out = isl_basic_map_dim(bmap: bmap2, type: isl_dim_out); |
1966 | o_out = isl_basic_map_offset(bmap: bmap1, type: isl_dim_out) - 1 + o_pos; |
1967 | n_div = isl_basic_map_dim(bmap: bmap2, type: isl_dim_div); |
1968 | if (total < 0 || n_param < 0 || n_in < 0 || n_out < 0 || n_div < 0) |
1969 | goto error; |
1970 | ctx = isl_basic_map_get_ctx(bmap: bmap1); |
1971 | dim_map = isl_dim_map_alloc(ctx, len: total + n_div); |
1972 | isl_dim_map_dim_range(dim_map, space, type: isl_dim_param, first: 0, n: n_param, dst_pos: 0); |
1973 | isl_dim_map_dim_range(dim_map, space, type: isl_dim_in, first: 0, n: n_in, dst_pos: o_in); |
1974 | isl_dim_map_dim_range(dim_map, space, type: isl_dim_out, first: 0, n: n_out, dst_pos: o_out); |
1975 | isl_dim_map_div(dim_map, bmap: bmap2, dst_pos: total); |
1976 | |
1977 | return isl_basic_map_add_constraints_dim_map(dst: bmap1, src: bmap2, dim_map); |
1978 | error: |
1979 | isl_basic_map_free(bmap: bmap1); |
1980 | isl_basic_map_free(bmap: bmap2); |
1981 | return NULL; |
1982 | } |
1983 | |
1984 | __isl_give isl_basic_map *isl_basic_map_extend(__isl_take isl_basic_map *base, |
1985 | unsigned , unsigned n_eq, unsigned n_ineq) |
1986 | { |
1987 | isl_space *space; |
1988 | struct isl_basic_map *ext; |
1989 | unsigned flags; |
1990 | int dims_ok; |
1991 | |
1992 | if (!base) |
1993 | goto error; |
1994 | |
1995 | dims_ok = base->extra >= base->n_div + extra; |
1996 | |
1997 | if (dims_ok && room_for_con(bmap: base, n: n_eq + n_ineq) && |
1998 | room_for_ineq(bmap: base, n: n_ineq)) |
1999 | return base; |
2000 | |
2001 | extra += base->extra; |
2002 | n_eq += base->n_eq; |
2003 | n_ineq += base->n_ineq; |
2004 | |
2005 | space = isl_basic_map_get_space(bmap: base); |
2006 | ext = isl_basic_map_alloc_space(space, extra, n_eq, n_ineq); |
2007 | if (!ext) |
2008 | goto error; |
2009 | |
2010 | if (dims_ok) |
2011 | ext->sample = isl_vec_copy(vec: base->sample); |
2012 | flags = base->flags; |
2013 | ext = add_constraints(bmap1: ext, bmap2: base, i_pos: 0, o_pos: 0); |
2014 | if (ext) { |
2015 | ext->flags = flags; |
2016 | ISL_F_CLR(ext, ISL_BASIC_SET_FINAL); |
2017 | } |
2018 | |
2019 | return ext; |
2020 | |
2021 | error: |
2022 | isl_basic_map_free(bmap: base); |
2023 | return NULL; |
2024 | } |
2025 | |
2026 | __isl_give isl_basic_set *isl_basic_set_extend(__isl_take isl_basic_set *base, |
2027 | unsigned , unsigned n_eq, unsigned n_ineq) |
2028 | { |
2029 | return bset_from_bmap(bmap: isl_basic_map_extend(base: bset_to_bmap(bset: base), |
2030 | extra, n_eq, n_ineq)); |
2031 | } |
2032 | |
2033 | __isl_give isl_basic_map *isl_basic_map_extend_constraints( |
2034 | __isl_take isl_basic_map *base, unsigned n_eq, unsigned n_ineq) |
2035 | { |
2036 | return isl_basic_map_extend(base, extra: 0, n_eq, n_ineq); |
2037 | } |
2038 | |
2039 | __isl_give isl_basic_set *isl_basic_set_extend_constraints( |
2040 | __isl_take isl_basic_set *base, unsigned n_eq, unsigned n_ineq) |
2041 | { |
2042 | isl_basic_map *bmap = bset_to_bmap(bset: base); |
2043 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq, n_ineq); |
2044 | return bset_from_bmap(bmap); |
2045 | } |
2046 | |
2047 | __isl_give isl_basic_set *isl_basic_set_cow(__isl_take isl_basic_set *bset) |
2048 | { |
2049 | return bset_from_bmap(bmap: isl_basic_map_cow(bmap: bset_to_bmap(bset))); |
2050 | } |
2051 | |
2052 | __isl_give isl_basic_map *isl_basic_map_cow(__isl_take isl_basic_map *bmap) |
2053 | { |
2054 | if (!bmap) |
2055 | return NULL; |
2056 | |
2057 | if (bmap->ref > 1) { |
2058 | bmap->ref--; |
2059 | bmap = isl_basic_map_dup(bmap); |
2060 | } |
2061 | if (bmap) { |
2062 | ISL_F_CLR(bmap, ISL_BASIC_SET_FINAL); |
2063 | ISL_F_CLR(bmap, ISL_BASIC_MAP_REDUCED_COEFFICIENTS); |
2064 | } |
2065 | return bmap; |
2066 | } |
2067 | |
2068 | /* Clear all cached information in "map", either because it is about |
2069 | * to be modified or because it is being freed. |
2070 | * Always return the same pointer that is passed in. |
2071 | * This is needed for the use in isl_map_free. |
2072 | */ |
2073 | static __isl_give isl_map *clear_caches(__isl_take isl_map *map) |
2074 | { |
2075 | isl_basic_map_free(bmap: map->cached_simple_hull[0]); |
2076 | isl_basic_map_free(bmap: map->cached_simple_hull[1]); |
2077 | map->cached_simple_hull[0] = NULL; |
2078 | map->cached_simple_hull[1] = NULL; |
2079 | return map; |
2080 | } |
2081 | |
2082 | __isl_give isl_set *isl_set_cow(__isl_take isl_set *set) |
2083 | { |
2084 | return isl_map_cow(map: set); |
2085 | } |
2086 | |
2087 | /* Return an isl_map that is equal to "map" and that has only |
2088 | * a single reference. |
2089 | * |
2090 | * If the original input already has only one reference, then |
2091 | * simply return it, but clear all cached information, since |
2092 | * it may be rendered invalid by the operations that will be |
2093 | * performed on the result. |
2094 | * |
2095 | * Otherwise, create a duplicate (without any cached information). |
2096 | */ |
2097 | __isl_give isl_map *isl_map_cow(__isl_take isl_map *map) |
2098 | { |
2099 | if (!map) |
2100 | return NULL; |
2101 | |
2102 | if (map->ref == 1) |
2103 | return clear_caches(map); |
2104 | map->ref--; |
2105 | return isl_map_dup(map); |
2106 | } |
2107 | |
2108 | static void swap_vars(struct isl_blk blk, isl_int *a, |
2109 | unsigned a_len, unsigned b_len) |
2110 | { |
2111 | isl_seq_cpy(dst: blk.data, src: a+a_len, len: b_len); |
2112 | isl_seq_cpy(dst: blk.data+b_len, src: a, len: a_len); |
2113 | isl_seq_cpy(dst: a, src: blk.data, len: b_len+a_len); |
2114 | } |
2115 | |
2116 | static __isl_give isl_basic_map *isl_basic_map_swap_vars( |
2117 | __isl_take isl_basic_map *bmap, unsigned pos, unsigned n1, unsigned n2) |
2118 | { |
2119 | int i; |
2120 | struct isl_blk blk; |
2121 | |
2122 | if (isl_basic_map_check_range(obj: bmap, type: isl_dim_all, first: pos - 1, n: n1 + n2) < 0) |
2123 | goto error; |
2124 | |
2125 | if (n1 == 0 || n2 == 0) |
2126 | return bmap; |
2127 | |
2128 | bmap = isl_basic_map_cow(bmap); |
2129 | if (!bmap) |
2130 | return NULL; |
2131 | |
2132 | blk = isl_blk_alloc(ctx: bmap->ctx, n: n1 + n2); |
2133 | if (isl_blk_is_error(block: blk)) |
2134 | goto error; |
2135 | |
2136 | for (i = 0; i < bmap->n_eq; ++i) |
2137 | swap_vars(blk, |
2138 | a: bmap->eq[i] + pos, a_len: n1, b_len: n2); |
2139 | |
2140 | for (i = 0; i < bmap->n_ineq; ++i) |
2141 | swap_vars(blk, |
2142 | a: bmap->ineq[i] + pos, a_len: n1, b_len: n2); |
2143 | |
2144 | for (i = 0; i < bmap->n_div; ++i) |
2145 | swap_vars(blk, |
2146 | a: bmap->div[i]+1 + pos, a_len: n1, b_len: n2); |
2147 | |
2148 | isl_blk_free(ctx: bmap->ctx, block: blk); |
2149 | |
2150 | ISL_F_CLR(bmap, ISL_BASIC_SET_SORTED); |
2151 | bmap = isl_basic_map_gauss(bmap, NULL); |
2152 | return isl_basic_map_finalize(bmap); |
2153 | error: |
2154 | isl_basic_map_free(bmap); |
2155 | return NULL; |
2156 | } |
2157 | |
2158 | /* The given basic map has turned out to be empty. |
2159 | * Explicitly mark it as such and change the representation |
2160 | * to a canonical representation of the empty basic map. |
2161 | * Since the basic map has conflicting constraints, |
2162 | * it must have at least one constraint, except perhaps |
2163 | * if it was already explicitly marked as being empty. |
2164 | * Do nothing in the latter case, i.e., if it has been marked empty and |
2165 | * has no constraints. |
2166 | */ |
2167 | __isl_give isl_basic_map *isl_basic_map_set_to_empty( |
2168 | __isl_take isl_basic_map *bmap) |
2169 | { |
2170 | int i = 0; |
2171 | isl_bool empty; |
2172 | isl_size n; |
2173 | isl_size total; |
2174 | |
2175 | n = isl_basic_map_n_constraint(bmap); |
2176 | empty = isl_basic_map_plain_is_empty(bmap); |
2177 | if (n < 0 || empty < 0) |
2178 | return isl_basic_map_free(bmap); |
2179 | if (n == 0 && empty) |
2180 | return bmap; |
2181 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
2182 | if (total < 0) |
2183 | return isl_basic_map_free(bmap); |
2184 | if (isl_basic_map_free_div(bmap, n: bmap->n_div) < 0) |
2185 | return isl_basic_map_free(bmap); |
2186 | bmap = isl_basic_map_free_inequality(bmap, n: bmap->n_ineq); |
2187 | if (!bmap) |
2188 | return NULL; |
2189 | if (bmap->n_eq > 0) { |
2190 | bmap = isl_basic_map_free_equality(bmap, n: bmap->n_eq - 1); |
2191 | if (!bmap) |
2192 | return NULL; |
2193 | } else { |
2194 | i = isl_basic_map_alloc_equality(bmap); |
2195 | if (i < 0) |
2196 | goto error; |
2197 | } |
2198 | isl_int_set_si(bmap->eq[i][0], 1); |
2199 | isl_seq_clr(p: bmap->eq[i]+1, len: total); |
2200 | ISL_F_SET(bmap, ISL_BASIC_MAP_EMPTY); |
2201 | isl_vec_free(vec: bmap->sample); |
2202 | bmap->sample = NULL; |
2203 | return isl_basic_map_finalize(bmap); |
2204 | error: |
2205 | isl_basic_map_free(bmap); |
2206 | return NULL; |
2207 | } |
2208 | |
2209 | __isl_give isl_basic_set *isl_basic_set_set_to_empty( |
2210 | __isl_take isl_basic_set *bset) |
2211 | { |
2212 | return bset_from_bmap(bmap: isl_basic_map_set_to_empty(bmap: bset_to_bmap(bset))); |
2213 | } |
2214 | |
2215 | __isl_give isl_basic_map *isl_basic_map_set_rational( |
2216 | __isl_take isl_basic_map *bmap) |
2217 | { |
2218 | if (!bmap) |
2219 | return NULL; |
2220 | |
2221 | if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) |
2222 | return bmap; |
2223 | |
2224 | bmap = isl_basic_map_cow(bmap); |
2225 | if (!bmap) |
2226 | return NULL; |
2227 | |
2228 | ISL_F_SET(bmap, ISL_BASIC_MAP_RATIONAL); |
2229 | |
2230 | return isl_basic_map_finalize(bmap); |
2231 | } |
2232 | |
2233 | __isl_give isl_basic_set *isl_basic_set_set_rational( |
2234 | __isl_take isl_basic_set *bset) |
2235 | { |
2236 | return isl_basic_map_set_rational(bmap: bset); |
2237 | } |
2238 | |
2239 | __isl_give isl_basic_set *isl_basic_set_set_integral( |
2240 | __isl_take isl_basic_set *bset) |
2241 | { |
2242 | if (!bset) |
2243 | return NULL; |
2244 | |
2245 | if (!ISL_F_ISSET(bset, ISL_BASIC_MAP_RATIONAL)) |
2246 | return bset; |
2247 | |
2248 | bset = isl_basic_set_cow(bset); |
2249 | if (!bset) |
2250 | return NULL; |
2251 | |
2252 | ISL_F_CLR(bset, ISL_BASIC_MAP_RATIONAL); |
2253 | |
2254 | return isl_basic_set_finalize(bset); |
2255 | } |
2256 | |
2257 | __isl_give isl_map *isl_map_set_rational(__isl_take isl_map *map) |
2258 | { |
2259 | int i; |
2260 | |
2261 | map = isl_map_cow(map); |
2262 | if (!map) |
2263 | return NULL; |
2264 | for (i = 0; i < map->n; ++i) { |
2265 | map->p[i] = isl_basic_map_set_rational(bmap: map->p[i]); |
2266 | if (!map->p[i]) |
2267 | goto error; |
2268 | } |
2269 | return map; |
2270 | error: |
2271 | isl_map_free(map); |
2272 | return NULL; |
2273 | } |
2274 | |
2275 | __isl_give isl_set *isl_set_set_rational(__isl_take isl_set *set) |
2276 | { |
2277 | return isl_map_set_rational(map: set); |
2278 | } |
2279 | |
2280 | /* Swap divs "a" and "b" in "bmap" (without modifying any of the constraints |
2281 | * of "bmap"). |
2282 | */ |
2283 | static void swap_div(__isl_keep isl_basic_map *bmap, int a, int b) |
2284 | { |
2285 | isl_int *t = bmap->div[a]; |
2286 | bmap->div[a] = bmap->div[b]; |
2287 | bmap->div[b] = t; |
2288 | } |
2289 | |
2290 | /* Swap divs "a" and "b" in "bmap" and adjust the constraints and |
2291 | * div definitions accordingly. |
2292 | */ |
2293 | __isl_give isl_basic_map *isl_basic_map_swap_div(__isl_take isl_basic_map *bmap, |
2294 | int a, int b) |
2295 | { |
2296 | int i; |
2297 | isl_size off; |
2298 | |
2299 | off = isl_basic_map_var_offset(bmap, type: isl_dim_div); |
2300 | if (off < 0) |
2301 | return isl_basic_map_free(bmap); |
2302 | |
2303 | swap_div(bmap, a, b); |
2304 | |
2305 | for (i = 0; i < bmap->n_eq; ++i) |
2306 | isl_int_swap(bmap->eq[i][1+off+a], bmap->eq[i][1+off+b]); |
2307 | |
2308 | for (i = 0; i < bmap->n_ineq; ++i) |
2309 | isl_int_swap(bmap->ineq[i][1+off+a], bmap->ineq[i][1+off+b]); |
2310 | |
2311 | for (i = 0; i < bmap->n_div; ++i) |
2312 | isl_int_swap(bmap->div[i][1+1+off+a], bmap->div[i][1+1+off+b]); |
2313 | ISL_F_CLR(bmap, ISL_BASIC_MAP_SORTED); |
2314 | |
2315 | return bmap; |
2316 | } |
2317 | |
2318 | static void constraint_drop_vars(isl_int *c, unsigned n, unsigned rem) |
2319 | { |
2320 | isl_seq_cpy(dst: c, src: c + n, len: rem); |
2321 | isl_seq_clr(p: c + rem, len: n); |
2322 | } |
2323 | |
2324 | /* Drop n dimensions starting at first. |
2325 | * |
2326 | * In principle, this frees up some extra variables as the number |
2327 | * of columns remains constant, but we would have to extend |
2328 | * the div array too as the number of rows in this array is assumed |
2329 | * to be equal to extra. |
2330 | */ |
2331 | __isl_give isl_basic_set *isl_basic_set_drop_dims( |
2332 | __isl_take isl_basic_set *bset, unsigned first, unsigned n) |
2333 | { |
2334 | return isl_basic_map_drop(bmap: bset_to_bmap(bset), type: isl_dim_set, first, n); |
2335 | } |
2336 | |
2337 | /* Move "n" divs starting at "first" to the end of the list of divs. |
2338 | */ |
2339 | static __isl_give isl_basic_map *move_divs_last(__isl_take isl_basic_map *bmap, |
2340 | unsigned first, unsigned n) |
2341 | { |
2342 | isl_int **div; |
2343 | int i; |
2344 | |
2345 | if (first + n == bmap->n_div) |
2346 | return bmap; |
2347 | |
2348 | div = isl_alloc_array(bmap->ctx, isl_int *, n); |
2349 | if (!div) |
2350 | goto error; |
2351 | for (i = 0; i < n; ++i) |
2352 | div[i] = bmap->div[first + i]; |
2353 | for (i = 0; i < bmap->n_div - first - n; ++i) |
2354 | bmap->div[first + i] = bmap->div[first + n + i]; |
2355 | for (i = 0; i < n; ++i) |
2356 | bmap->div[bmap->n_div - n + i] = div[i]; |
2357 | free(ptr: div); |
2358 | return bmap; |
2359 | error: |
2360 | isl_basic_map_free(bmap); |
2361 | return NULL; |
2362 | } |
2363 | |
2364 | #undef TYPE |
2365 | #define TYPE isl_map |
2366 | static |
2367 | #include "check_type_range_templ.c" |
2368 | |
2369 | /* Check that there are "n" dimensions of type "type" starting at "first" |
2370 | * in "set". |
2371 | */ |
2372 | isl_stat isl_set_check_range(__isl_keep isl_set *set, |
2373 | enum isl_dim_type type, unsigned first, unsigned n) |
2374 | { |
2375 | return isl_map_check_range(obj: set_to_map(set), type, first, n); |
2376 | } |
2377 | |
2378 | /* Drop "n" dimensions of type "type" starting at "first". |
2379 | * Perform the core computation, without cowing or |
2380 | * simplifying and finalizing the result. |
2381 | * |
2382 | * In principle, this frees up some extra variables as the number |
2383 | * of columns remains constant, but we would have to extend |
2384 | * the div array too as the number of rows in this array is assumed |
2385 | * to be equal to extra. |
2386 | */ |
2387 | __isl_give isl_basic_map *isl_basic_map_drop_core( |
2388 | __isl_take isl_basic_map *bmap, enum isl_dim_type type, |
2389 | unsigned first, unsigned n) |
2390 | { |
2391 | int i; |
2392 | unsigned offset; |
2393 | unsigned left; |
2394 | isl_size total; |
2395 | |
2396 | if (isl_basic_map_check_range(obj: bmap, type, first, n) < 0) |
2397 | return isl_basic_map_free(bmap); |
2398 | |
2399 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
2400 | if (total < 0) |
2401 | return isl_basic_map_free(bmap); |
2402 | |
2403 | offset = isl_basic_map_offset(bmap, type) + first; |
2404 | left = total - (offset - 1) - n; |
2405 | for (i = 0; i < bmap->n_eq; ++i) |
2406 | constraint_drop_vars(c: bmap->eq[i]+offset, n, rem: left); |
2407 | |
2408 | for (i = 0; i < bmap->n_ineq; ++i) |
2409 | constraint_drop_vars(c: bmap->ineq[i]+offset, n, rem: left); |
2410 | |
2411 | for (i = 0; i < bmap->n_div; ++i) |
2412 | constraint_drop_vars(c: bmap->div[i]+1+offset, n, rem: left); |
2413 | |
2414 | if (type == isl_dim_div) { |
2415 | bmap = move_divs_last(bmap, first, n); |
2416 | if (!bmap) |
2417 | return NULL; |
2418 | if (isl_basic_map_free_div(bmap, n) < 0) |
2419 | return isl_basic_map_free(bmap); |
2420 | } else |
2421 | bmap->dim = isl_space_drop_dims(space: bmap->dim, type, first, num: n); |
2422 | if (!bmap->dim) |
2423 | return isl_basic_map_free(bmap); |
2424 | |
2425 | ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT); |
2426 | ISL_F_CLR(bmap, ISL_BASIC_MAP_SORTED); |
2427 | return bmap; |
2428 | } |
2429 | |
2430 | /* Drop "n" dimensions of type "type" starting at "first". |
2431 | * |
2432 | * In principle, this frees up some extra variables as the number |
2433 | * of columns remains constant, but we would have to extend |
2434 | * the div array too as the number of rows in this array is assumed |
2435 | * to be equal to extra. |
2436 | */ |
2437 | __isl_give isl_basic_map *isl_basic_map_drop(__isl_take isl_basic_map *bmap, |
2438 | enum isl_dim_type type, unsigned first, unsigned n) |
2439 | { |
2440 | if (!bmap) |
2441 | return NULL; |
2442 | if (n == 0 && !isl_space_is_named_or_nested(space: bmap->dim, type)) |
2443 | return bmap; |
2444 | |
2445 | bmap = isl_basic_map_cow(bmap); |
2446 | if (!bmap) |
2447 | return NULL; |
2448 | |
2449 | bmap = isl_basic_map_drop_core(bmap, type, first, n); |
2450 | |
2451 | bmap = isl_basic_map_simplify(bmap); |
2452 | return isl_basic_map_finalize(bmap); |
2453 | } |
2454 | |
2455 | __isl_give isl_basic_set *isl_basic_set_drop(__isl_take isl_basic_set *bset, |
2456 | enum isl_dim_type type, unsigned first, unsigned n) |
2457 | { |
2458 | return bset_from_bmap(bmap: isl_basic_map_drop(bmap: bset_to_bmap(bset), |
2459 | type, first, n)); |
2460 | } |
2461 | |
2462 | /* No longer consider "map" to be normalized. |
2463 | */ |
2464 | static __isl_give isl_map *isl_map_unmark_normalized(__isl_take isl_map *map) |
2465 | { |
2466 | if (!map) |
2467 | return NULL; |
2468 | ISL_F_CLR(map, ISL_MAP_NORMALIZED); |
2469 | return map; |
2470 | } |
2471 | |
2472 | __isl_give isl_map *isl_map_drop(__isl_take isl_map *map, |
2473 | enum isl_dim_type type, unsigned first, unsigned n) |
2474 | { |
2475 | int i; |
2476 | isl_space *space; |
2477 | |
2478 | if (isl_map_check_range(obj: map, type, first, n) < 0) |
2479 | return isl_map_free(map); |
2480 | |
2481 | if (n == 0 && !isl_space_is_named_or_nested(space: map->dim, type)) |
2482 | return map; |
2483 | map = isl_map_cow(map); |
2484 | if (!map) |
2485 | goto error; |
2486 | |
2487 | for (i = 0; i < map->n; ++i) { |
2488 | map->p[i] = isl_basic_map_drop(bmap: map->p[i], type, first, n); |
2489 | if (!map->p[i]) |
2490 | goto error; |
2491 | } |
2492 | map = isl_map_unmark_normalized(map); |
2493 | |
2494 | space = isl_map_take_space(map); |
2495 | space = isl_space_drop_dims(space, type, first, num: n); |
2496 | map = isl_map_restore_space(map, space); |
2497 | |
2498 | return map; |
2499 | error: |
2500 | isl_map_free(map); |
2501 | return NULL; |
2502 | } |
2503 | |
2504 | __isl_give isl_set *isl_set_drop(__isl_take isl_set *set, |
2505 | enum isl_dim_type type, unsigned first, unsigned n) |
2506 | { |
2507 | return set_from_map(isl_map_drop(map: set_to_map(set), type, first, n)); |
2508 | } |
2509 | |
2510 | /* Drop the integer division at position "div", which is assumed |
2511 | * not to appear in any of the constraints or |
2512 | * in any of the other integer divisions. |
2513 | * |
2514 | * Since the integer division is redundant, there is no need to cow. |
2515 | */ |
2516 | __isl_give isl_basic_map *isl_basic_map_drop_div( |
2517 | __isl_take isl_basic_map *bmap, unsigned div) |
2518 | { |
2519 | return isl_basic_map_drop_core(bmap, type: isl_dim_div, first: div, n: 1); |
2520 | } |
2521 | |
2522 | /* Eliminate the specified n dimensions starting at first from the |
2523 | * constraints, without removing the dimensions from the space. |
2524 | * If the set is rational, the dimensions are eliminated using Fourier-Motzkin. |
2525 | */ |
2526 | __isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map, |
2527 | enum isl_dim_type type, unsigned first, unsigned n) |
2528 | { |
2529 | int i; |
2530 | |
2531 | if (n == 0) |
2532 | return map; |
2533 | |
2534 | if (isl_map_check_range(obj: map, type, first, n) < 0) |
2535 | return isl_map_free(map); |
2536 | |
2537 | map = isl_map_cow(map); |
2538 | if (!map) |
2539 | return NULL; |
2540 | |
2541 | for (i = 0; i < map->n; ++i) { |
2542 | map->p[i] = isl_basic_map_eliminate(bmap: map->p[i], type, first, n); |
2543 | if (!map->p[i]) |
2544 | goto error; |
2545 | } |
2546 | return map; |
2547 | error: |
2548 | isl_map_free(map); |
2549 | return NULL; |
2550 | } |
2551 | |
2552 | /* Eliminate the specified n dimensions starting at first from the |
2553 | * constraints, without removing the dimensions from the space. |
2554 | * If the set is rational, the dimensions are eliminated using Fourier-Motzkin. |
2555 | */ |
2556 | __isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set, |
2557 | enum isl_dim_type type, unsigned first, unsigned n) |
2558 | { |
2559 | return set_from_map(isl_map_eliminate(map: set_to_map(set), type, first, n)); |
2560 | } |
2561 | |
2562 | /* Eliminate the specified n dimensions starting at first from the |
2563 | * constraints, without removing the dimensions from the space. |
2564 | * If the set is rational, the dimensions are eliminated using Fourier-Motzkin. |
2565 | */ |
2566 | __isl_give isl_set *isl_set_eliminate_dims(__isl_take isl_set *set, |
2567 | unsigned first, unsigned n) |
2568 | { |
2569 | return isl_set_eliminate(set, type: isl_dim_set, first, n); |
2570 | } |
2571 | |
2572 | __isl_give isl_basic_map *isl_basic_map_remove_divs( |
2573 | __isl_take isl_basic_map *bmap) |
2574 | { |
2575 | isl_size v_div; |
2576 | |
2577 | v_div = isl_basic_map_var_offset(bmap, type: isl_dim_div); |
2578 | if (v_div < 0) |
2579 | return isl_basic_map_free(bmap); |
2580 | bmap = isl_basic_map_eliminate_vars(bmap, pos: v_div, n: bmap->n_div); |
2581 | if (!bmap) |
2582 | return NULL; |
2583 | bmap->n_div = 0; |
2584 | return isl_basic_map_finalize(bmap); |
2585 | } |
2586 | |
2587 | __isl_give isl_basic_set *isl_basic_set_remove_divs( |
2588 | __isl_take isl_basic_set *bset) |
2589 | { |
2590 | return bset_from_bmap(bmap: isl_basic_map_remove_divs(bmap: bset_to_bmap(bset))); |
2591 | } |
2592 | |
2593 | __isl_give isl_map *isl_map_remove_divs(__isl_take isl_map *map) |
2594 | { |
2595 | int i; |
2596 | |
2597 | if (!map) |
2598 | return NULL; |
2599 | if (map->n == 0) |
2600 | return map; |
2601 | |
2602 | map = isl_map_cow(map); |
2603 | if (!map) |
2604 | return NULL; |
2605 | |
2606 | for (i = 0; i < map->n; ++i) { |
2607 | map->p[i] = isl_basic_map_remove_divs(bmap: map->p[i]); |
2608 | if (!map->p[i]) |
2609 | goto error; |
2610 | } |
2611 | return map; |
2612 | error: |
2613 | isl_map_free(map); |
2614 | return NULL; |
2615 | } |
2616 | |
2617 | __isl_give isl_set *isl_set_remove_divs(__isl_take isl_set *set) |
2618 | { |
2619 | return isl_map_remove_divs(map: set); |
2620 | } |
2621 | |
2622 | __isl_give isl_basic_map *isl_basic_map_remove_dims( |
2623 | __isl_take isl_basic_map *bmap, enum isl_dim_type type, |
2624 | unsigned first, unsigned n) |
2625 | { |
2626 | if (isl_basic_map_check_range(obj: bmap, type, first, n) < 0) |
2627 | return isl_basic_map_free(bmap); |
2628 | if (n == 0 && !isl_space_is_named_or_nested(space: bmap->dim, type)) |
2629 | return bmap; |
2630 | bmap = isl_basic_map_eliminate_vars(bmap, |
2631 | pos: isl_basic_map_offset(bmap, type) - 1 + first, n); |
2632 | if (!bmap) |
2633 | return bmap; |
2634 | if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY) && type == isl_dim_div) |
2635 | return bmap; |
2636 | bmap = isl_basic_map_drop(bmap, type, first, n); |
2637 | return bmap; |
2638 | } |
2639 | |
2640 | /* Return true if the definition of the given div (recursively) involves |
2641 | * any of the given variables. |
2642 | */ |
2643 | static isl_bool div_involves_vars(__isl_keep isl_basic_map *bmap, int div, |
2644 | unsigned first, unsigned n) |
2645 | { |
2646 | int i; |
2647 | unsigned div_offset = isl_basic_map_offset(bmap, type: isl_dim_div); |
2648 | |
2649 | if (isl_int_is_zero(bmap->div[div][0])) |
2650 | return isl_bool_false; |
2651 | if (isl_seq_first_non_zero(p: bmap->div[div] + 1 + first, len: n) >= 0) |
2652 | return isl_bool_true; |
2653 | |
2654 | for (i = bmap->n_div - 1; i >= 0; --i) { |
2655 | isl_bool involves; |
2656 | |
2657 | if (isl_int_is_zero(bmap->div[div][1 + div_offset + i])) |
2658 | continue; |
2659 | involves = div_involves_vars(bmap, div: i, first, n); |
2660 | if (involves < 0 || involves) |
2661 | return involves; |
2662 | } |
2663 | |
2664 | return isl_bool_false; |
2665 | } |
2666 | |
2667 | /* Try and add a lower and/or upper bound on "div" to "bmap" |
2668 | * based on inequality "i". |
2669 | * "total" is the total number of variables (excluding the divs). |
2670 | * "v" is a temporary object that can be used during the calculations. |
2671 | * If "lb" is set, then a lower bound should be constructed. |
2672 | * If "ub" is set, then an upper bound should be constructed. |
2673 | * |
2674 | * The calling function has already checked that the inequality does not |
2675 | * reference "div", but we still need to check that the inequality is |
2676 | * of the right form. We'll consider the case where we want to construct |
2677 | * a lower bound. The construction of upper bounds is similar. |
2678 | * |
2679 | * Let "div" be of the form |
2680 | * |
2681 | * q = floor((a + f(x))/d) |
2682 | * |
2683 | * We essentially check if constraint "i" is of the form |
2684 | * |
2685 | * b + f(x) >= 0 |
2686 | * |
2687 | * so that we can use it to derive a lower bound on "div". |
2688 | * However, we allow a slightly more general form |
2689 | * |
2690 | * b + g(x) >= 0 |
2691 | * |
2692 | * with the condition that the coefficients of g(x) - f(x) are all |
2693 | * divisible by d. |
2694 | * Rewriting this constraint as |
2695 | * |
2696 | * 0 >= -b - g(x) |
2697 | * |
2698 | * adding a + f(x) to both sides and dividing by d, we obtain |
2699 | * |
2700 | * (a + f(x))/d >= (a-b)/d + (f(x)-g(x))/d |
2701 | * |
2702 | * Taking the floor on both sides, we obtain |
2703 | * |
2704 | * q >= floor((a-b)/d) + (f(x)-g(x))/d |
2705 | * |
2706 | * or |
2707 | * |
2708 | * (g(x)-f(x))/d + ceil((b-a)/d) + q >= 0 |
2709 | * |
2710 | * In the case of an upper bound, we construct the constraint |
2711 | * |
2712 | * (g(x)+f(x))/d + floor((b+a)/d) - q >= 0 |
2713 | * |
2714 | */ |
2715 | static __isl_give isl_basic_map *insert_bounds_on_div_from_ineq( |
2716 | __isl_take isl_basic_map *bmap, int div, int i, |
2717 | unsigned total, isl_int v, int lb, int ub) |
2718 | { |
2719 | int j; |
2720 | |
2721 | for (j = 0; (lb || ub) && j < total + bmap->n_div; ++j) { |
2722 | if (lb) { |
2723 | isl_int_sub(v, bmap->ineq[i][1 + j], |
2724 | bmap->div[div][1 + 1 + j]); |
2725 | lb = isl_int_is_divisible_by(v, bmap->div[div][0]); |
2726 | } |
2727 | if (ub) { |
2728 | isl_int_add(v, bmap->ineq[i][1 + j], |
2729 | bmap->div[div][1 + 1 + j]); |
2730 | ub = isl_int_is_divisible_by(v, bmap->div[div][0]); |
2731 | } |
2732 | } |
2733 | if (!lb && !ub) |
2734 | return bmap; |
2735 | |
2736 | bmap = isl_basic_map_cow(bmap); |
2737 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq: 0, n_ineq: lb + ub); |
2738 | if (lb) { |
2739 | int k = isl_basic_map_alloc_inequality(bmap); |
2740 | if (k < 0) |
2741 | goto error; |
2742 | for (j = 0; j < 1 + total + bmap->n_div; ++j) { |
2743 | isl_int_sub(bmap->ineq[k][j], bmap->ineq[i][j], |
2744 | bmap->div[div][1 + j]); |
2745 | isl_int_cdiv_q(bmap->ineq[k][j], |
2746 | bmap->ineq[k][j], bmap->div[div][0]); |
2747 | } |
2748 | isl_int_set_si(bmap->ineq[k][1 + total + div], 1); |
2749 | } |
2750 | if (ub) { |
2751 | int k = isl_basic_map_alloc_inequality(bmap); |
2752 | if (k < 0) |
2753 | goto error; |
2754 | for (j = 0; j < 1 + total + bmap->n_div; ++j) { |
2755 | isl_int_add(bmap->ineq[k][j], bmap->ineq[i][j], |
2756 | bmap->div[div][1 + j]); |
2757 | isl_int_fdiv_q(bmap->ineq[k][j], |
2758 | bmap->ineq[k][j], bmap->div[div][0]); |
2759 | } |
2760 | isl_int_set_si(bmap->ineq[k][1 + total + div], -1); |
2761 | } |
2762 | |
2763 | return bmap; |
2764 | error: |
2765 | isl_basic_map_free(bmap); |
2766 | return NULL; |
2767 | } |
2768 | |
2769 | /* This function is called right before "div" is eliminated from "bmap" |
2770 | * using Fourier-Motzkin. |
2771 | * Look through the constraints of "bmap" for constraints on the argument |
2772 | * of the integer division and use them to construct constraints on the |
2773 | * integer division itself. These constraints can then be combined |
2774 | * during the Fourier-Motzkin elimination. |
2775 | * Note that it is only useful to introduce lower bounds on "div" |
2776 | * if "bmap" already contains upper bounds on "div" as the newly |
2777 | * introduce lower bounds can then be combined with the pre-existing |
2778 | * upper bounds. Similarly for upper bounds. |
2779 | * We therefore first check if "bmap" contains any lower and/or upper bounds |
2780 | * on "div". |
2781 | * |
2782 | * It is interesting to note that the introduction of these constraints |
2783 | * can indeed lead to more accurate results, even when compared to |
2784 | * deriving constraints on the argument of "div" from constraints on "div". |
2785 | * Consider, for example, the set |
2786 | * |
2787 | * { [i,j,k] : 3 + i + 2j >= 0 and 2 * [(i+2j)/4] <= k } |
2788 | * |
2789 | * The second constraint can be rewritten as |
2790 | * |
2791 | * 2 * [(-i-2j+3)/4] + k >= 0 |
2792 | * |
2793 | * from which we can derive |
2794 | * |
2795 | * -i - 2j + 3 >= -2k |
2796 | * |
2797 | * or |
2798 | * |
2799 | * i + 2j <= 3 + 2k |
2800 | * |
2801 | * Combined with the first constraint, we obtain |
2802 | * |
2803 | * -3 <= 3 + 2k or k >= -3 |
2804 | * |
2805 | * If, on the other hand we derive a constraint on [(i+2j)/4] from |
2806 | * the first constraint, we obtain |
2807 | * |
2808 | * [(i + 2j)/4] >= [-3/4] = -1 |
2809 | * |
2810 | * Combining this constraint with the second constraint, we obtain |
2811 | * |
2812 | * k >= -2 |
2813 | */ |
2814 | static __isl_give isl_basic_map *insert_bounds_on_div( |
2815 | __isl_take isl_basic_map *bmap, int div) |
2816 | { |
2817 | int i; |
2818 | int check_lb, check_ub; |
2819 | isl_int v; |
2820 | isl_size v_div; |
2821 | |
2822 | if (!bmap) |
2823 | return NULL; |
2824 | |
2825 | if (isl_int_is_zero(bmap->div[div][0])) |
2826 | return bmap; |
2827 | |
2828 | v_div = isl_basic_map_var_offset(bmap, type: isl_dim_div); |
2829 | if (v_div < 0) |
2830 | return isl_basic_map_free(bmap); |
2831 | |
2832 | check_lb = 0; |
2833 | check_ub = 0; |
2834 | for (i = 0; (!check_lb || !check_ub) && i < bmap->n_ineq; ++i) { |
2835 | int s = isl_int_sgn(bmap->ineq[i][1 + v_div + div]); |
2836 | if (s > 0) |
2837 | check_ub = 1; |
2838 | if (s < 0) |
2839 | check_lb = 1; |
2840 | } |
2841 | |
2842 | if (!check_lb && !check_ub) |
2843 | return bmap; |
2844 | |
2845 | isl_int_init(v); |
2846 | |
2847 | for (i = 0; bmap && i < bmap->n_ineq; ++i) { |
2848 | if (!isl_int_is_zero(bmap->ineq[i][1 + v_div + div])) |
2849 | continue; |
2850 | |
2851 | bmap = insert_bounds_on_div_from_ineq(bmap, div, i, total: v_div, v, |
2852 | lb: check_lb, ub: check_ub); |
2853 | } |
2854 | |
2855 | isl_int_clear(v); |
2856 | |
2857 | return bmap; |
2858 | } |
2859 | |
2860 | /* Remove all divs (recursively) involving any of the given dimensions |
2861 | * in their definitions. |
2862 | */ |
2863 | __isl_give isl_basic_map *isl_basic_map_remove_divs_involving_dims( |
2864 | __isl_take isl_basic_map *bmap, |
2865 | enum isl_dim_type type, unsigned first, unsigned n) |
2866 | { |
2867 | int i; |
2868 | |
2869 | if (isl_basic_map_check_range(obj: bmap, type, first, n) < 0) |
2870 | return isl_basic_map_free(bmap); |
2871 | first += isl_basic_map_offset(bmap, type); |
2872 | |
2873 | for (i = bmap->n_div - 1; i >= 0; --i) { |
2874 | isl_bool involves; |
2875 | |
2876 | involves = div_involves_vars(bmap, div: i, first, n); |
2877 | if (involves < 0) |
2878 | return isl_basic_map_free(bmap); |
2879 | if (!involves) |
2880 | continue; |
2881 | bmap = insert_bounds_on_div(bmap, div: i); |
2882 | bmap = isl_basic_map_remove_dims(bmap, type: isl_dim_div, first: i, n: 1); |
2883 | if (!bmap) |
2884 | return NULL; |
2885 | i = bmap->n_div; |
2886 | } |
2887 | |
2888 | return bmap; |
2889 | } |
2890 | |
2891 | __isl_give isl_basic_set *isl_basic_set_remove_divs_involving_dims( |
2892 | __isl_take isl_basic_set *bset, |
2893 | enum isl_dim_type type, unsigned first, unsigned n) |
2894 | { |
2895 | return isl_basic_map_remove_divs_involving_dims(bmap: bset, type, first, n); |
2896 | } |
2897 | |
2898 | __isl_give isl_map *isl_map_remove_divs_involving_dims(__isl_take isl_map *map, |
2899 | enum isl_dim_type type, unsigned first, unsigned n) |
2900 | { |
2901 | int i; |
2902 | |
2903 | if (!map) |
2904 | return NULL; |
2905 | if (map->n == 0) |
2906 | return map; |
2907 | |
2908 | map = isl_map_cow(map); |
2909 | if (!map) |
2910 | return NULL; |
2911 | |
2912 | for (i = 0; i < map->n; ++i) { |
2913 | map->p[i] = isl_basic_map_remove_divs_involving_dims(bmap: map->p[i], |
2914 | type, first, n); |
2915 | if (!map->p[i]) |
2916 | goto error; |
2917 | } |
2918 | return map; |
2919 | error: |
2920 | isl_map_free(map); |
2921 | return NULL; |
2922 | } |
2923 | |
2924 | __isl_give isl_set *isl_set_remove_divs_involving_dims(__isl_take isl_set *set, |
2925 | enum isl_dim_type type, unsigned first, unsigned n) |
2926 | { |
2927 | return set_from_map(isl_map_remove_divs_involving_dims(map: set_to_map(set), |
2928 | type, first, n)); |
2929 | } |
2930 | |
2931 | /* Does the description of "bmap" depend on the specified dimensions? |
2932 | * We also check whether the dimensions appear in any of the div definitions. |
2933 | * In principle there is no need for this check. If the dimensions appear |
2934 | * in a div definition, they also appear in the defining constraints of that |
2935 | * div. |
2936 | */ |
2937 | isl_bool isl_basic_map_involves_dims(__isl_keep isl_basic_map *bmap, |
2938 | enum isl_dim_type type, unsigned first, unsigned n) |
2939 | { |
2940 | int i; |
2941 | |
2942 | if (isl_basic_map_check_range(obj: bmap, type, first, n) < 0) |
2943 | return isl_bool_error; |
2944 | |
2945 | first += isl_basic_map_offset(bmap, type); |
2946 | for (i = 0; i < bmap->n_eq; ++i) |
2947 | if (isl_seq_first_non_zero(p: bmap->eq[i] + first, len: n) >= 0) |
2948 | return isl_bool_true; |
2949 | for (i = 0; i < bmap->n_ineq; ++i) |
2950 | if (isl_seq_first_non_zero(p: bmap->ineq[i] + first, len: n) >= 0) |
2951 | return isl_bool_true; |
2952 | for (i = 0; i < bmap->n_div; ++i) { |
2953 | if (isl_int_is_zero(bmap->div[i][0])) |
2954 | continue; |
2955 | if (isl_seq_first_non_zero(p: bmap->div[i] + 1 + first, len: n) >= 0) |
2956 | return isl_bool_true; |
2957 | } |
2958 | |
2959 | return isl_bool_false; |
2960 | } |
2961 | |
2962 | isl_bool isl_map_involves_dims(__isl_keep isl_map *map, |
2963 | enum isl_dim_type type, unsigned first, unsigned n) |
2964 | { |
2965 | int i; |
2966 | |
2967 | if (isl_map_check_range(obj: map, type, first, n) < 0) |
2968 | return isl_bool_error; |
2969 | |
2970 | for (i = 0; i < map->n; ++i) { |
2971 | isl_bool involves = isl_basic_map_involves_dims(bmap: map->p[i], |
2972 | type, first, n); |
2973 | if (involves < 0 || involves) |
2974 | return involves; |
2975 | } |
2976 | |
2977 | return isl_bool_false; |
2978 | } |
2979 | |
2980 | isl_bool isl_basic_set_involves_dims(__isl_keep isl_basic_set *bset, |
2981 | enum isl_dim_type type, unsigned first, unsigned n) |
2982 | { |
2983 | return isl_basic_map_involves_dims(bmap: bset, type, first, n); |
2984 | } |
2985 | |
2986 | isl_bool isl_set_involves_dims(__isl_keep isl_set *set, |
2987 | enum isl_dim_type type, unsigned first, unsigned n) |
2988 | { |
2989 | return isl_map_involves_dims(map: set, type, first, n); |
2990 | } |
2991 | |
2992 | /* Does "bset" involve any local variables, i.e., integer divisions? |
2993 | */ |
2994 | static isl_bool isl_basic_set_involves_locals(__isl_keep isl_basic_set *bset) |
2995 | { |
2996 | isl_size n; |
2997 | |
2998 | n = isl_basic_set_dim(bset, type: isl_dim_div); |
2999 | if (n < 0) |
3000 | return isl_bool_error; |
3001 | return isl_bool_ok(b: n > 0); |
3002 | } |
3003 | |
3004 | /* isl_set_every_basic_set callback that checks whether "bset" |
3005 | * is free of local variables. |
3006 | */ |
3007 | static isl_bool basic_set_no_locals(__isl_keep isl_basic_set *bset, void *user) |
3008 | { |
3009 | return isl_bool_not(b: isl_basic_set_involves_locals(bset)); |
3010 | } |
3011 | |
3012 | /* Does "set" involve any local variables, i.e., integer divisions? |
3013 | */ |
3014 | isl_bool isl_set_involves_locals(__isl_keep isl_set *set) |
3015 | { |
3016 | isl_bool no_locals; |
3017 | |
3018 | no_locals = isl_set_every_basic_set(set, test: &basic_set_no_locals, NULL); |
3019 | return isl_bool_not(b: no_locals); |
3020 | } |
3021 | |
3022 | /* Drop all constraints in bmap that involve any of the dimensions |
3023 | * first to first+n-1. |
3024 | * This function only performs the actual removal of constraints. |
3025 | * |
3026 | * This function should not call finalize since it is used by |
3027 | * remove_redundant_divs, which in turn is called by isl_basic_map_finalize. |
3028 | */ |
3029 | __isl_give isl_basic_map *isl_basic_map_drop_constraints_involving( |
3030 | __isl_take isl_basic_map *bmap, unsigned first, unsigned n) |
3031 | { |
3032 | int i; |
3033 | |
3034 | if (n == 0) |
3035 | return bmap; |
3036 | |
3037 | bmap = isl_basic_map_cow(bmap); |
3038 | |
3039 | if (!bmap) |
3040 | return NULL; |
3041 | |
3042 | for (i = bmap->n_eq - 1; i >= 0; --i) { |
3043 | if (isl_seq_first_non_zero(p: bmap->eq[i] + 1 + first, len: n) == -1) |
3044 | continue; |
3045 | if (isl_basic_map_drop_equality(bmap, pos: i) < 0) |
3046 | return isl_basic_map_free(bmap); |
3047 | } |
3048 | |
3049 | for (i = bmap->n_ineq - 1; i >= 0; --i) { |
3050 | if (isl_seq_first_non_zero(p: bmap->ineq[i] + 1 + first, len: n) == -1) |
3051 | continue; |
3052 | if (isl_basic_map_drop_inequality(bmap, pos: i) < 0) |
3053 | return isl_basic_map_free(bmap); |
3054 | } |
3055 | |
3056 | return bmap; |
3057 | } |
3058 | |
3059 | /* Drop all constraints in bset that involve any of the dimensions |
3060 | * first to first+n-1. |
3061 | * This function only performs the actual removal of constraints. |
3062 | */ |
3063 | __isl_give isl_basic_set *isl_basic_set_drop_constraints_involving( |
3064 | __isl_take isl_basic_set *bset, unsigned first, unsigned n) |
3065 | { |
3066 | return isl_basic_map_drop_constraints_involving(bmap: bset, first, n); |
3067 | } |
3068 | |
3069 | /* Drop all constraints in bmap that do not involve any of the dimensions |
3070 | * first to first + n - 1 of the given type. |
3071 | */ |
3072 | __isl_give isl_basic_map *isl_basic_map_drop_constraints_not_involving_dims( |
3073 | __isl_take isl_basic_map *bmap, |
3074 | enum isl_dim_type type, unsigned first, unsigned n) |
3075 | { |
3076 | int i; |
3077 | |
3078 | if (n == 0) { |
3079 | isl_space *space = isl_basic_map_get_space(bmap); |
3080 | isl_basic_map_free(bmap); |
3081 | return isl_basic_map_universe(space); |
3082 | } |
3083 | bmap = isl_basic_map_cow(bmap); |
3084 | if (!bmap) |
3085 | return NULL; |
3086 | |
3087 | if (isl_basic_map_check_range(obj: bmap, type, first, n) < 0) |
3088 | return isl_basic_map_free(bmap); |
3089 | |
3090 | first += isl_basic_map_offset(bmap, type) - 1; |
3091 | |
3092 | for (i = bmap->n_eq - 1; i >= 0; --i) { |
3093 | if (isl_seq_first_non_zero(p: bmap->eq[i] + 1 + first, len: n) != -1) |
3094 | continue; |
3095 | if (isl_basic_map_drop_equality(bmap, pos: i) < 0) |
3096 | return isl_basic_map_free(bmap); |
3097 | } |
3098 | |
3099 | for (i = bmap->n_ineq - 1; i >= 0; --i) { |
3100 | if (isl_seq_first_non_zero(p: bmap->ineq[i] + 1 + first, len: n) != -1) |
3101 | continue; |
3102 | if (isl_basic_map_drop_inequality(bmap, pos: i) < 0) |
3103 | return isl_basic_map_free(bmap); |
3104 | } |
3105 | |
3106 | bmap = isl_basic_map_add_known_div_constraints(bmap); |
3107 | return bmap; |
3108 | } |
3109 | |
3110 | /* Drop all constraints in bset that do not involve any of the dimensions |
3111 | * first to first + n - 1 of the given type. |
3112 | */ |
3113 | __isl_give isl_basic_set *isl_basic_set_drop_constraints_not_involving_dims( |
3114 | __isl_take isl_basic_set *bset, |
3115 | enum isl_dim_type type, unsigned first, unsigned n) |
3116 | { |
3117 | return isl_basic_map_drop_constraints_not_involving_dims(bmap: bset, |
3118 | type, first, n); |
3119 | } |
3120 | |
3121 | /* Drop all constraints in bmap that involve any of the dimensions |
3122 | * first to first + n - 1 of the given type. |
3123 | */ |
3124 | __isl_give isl_basic_map *isl_basic_map_drop_constraints_involving_dims( |
3125 | __isl_take isl_basic_map *bmap, |
3126 | enum isl_dim_type type, unsigned first, unsigned n) |
3127 | { |
3128 | if (!bmap) |
3129 | return NULL; |
3130 | if (n == 0) |
3131 | return bmap; |
3132 | |
3133 | if (isl_basic_map_check_range(obj: bmap, type, first, n) < 0) |
3134 | return isl_basic_map_free(bmap); |
3135 | |
3136 | bmap = isl_basic_map_remove_divs_involving_dims(bmap, type, first, n); |
3137 | first += isl_basic_map_offset(bmap, type) - 1; |
3138 | bmap = isl_basic_map_drop_constraints_involving(bmap, first, n); |
3139 | bmap = isl_basic_map_add_known_div_constraints(bmap); |
3140 | return bmap; |
3141 | } |
3142 | |
3143 | /* Drop all constraints in bset that involve any of the dimensions |
3144 | * first to first + n - 1 of the given type. |
3145 | */ |
3146 | __isl_give isl_basic_set *isl_basic_set_drop_constraints_involving_dims( |
3147 | __isl_take isl_basic_set *bset, |
3148 | enum isl_dim_type type, unsigned first, unsigned n) |
3149 | { |
3150 | return isl_basic_map_drop_constraints_involving_dims(bmap: bset, |
3151 | type, first, n); |
3152 | } |
3153 | |
3154 | /* Drop constraints from "map" by applying "drop" to each basic map. |
3155 | */ |
3156 | static __isl_give isl_map *drop_constraints(__isl_take isl_map *map, |
3157 | enum isl_dim_type type, unsigned first, unsigned n, |
3158 | __isl_give isl_basic_map *(*drop)(__isl_take isl_basic_map *bmap, |
3159 | enum isl_dim_type type, unsigned first, unsigned n)) |
3160 | { |
3161 | int i; |
3162 | |
3163 | if (isl_map_check_range(obj: map, type, first, n) < 0) |
3164 | return isl_map_free(map); |
3165 | |
3166 | map = isl_map_cow(map); |
3167 | if (!map) |
3168 | return NULL; |
3169 | |
3170 | for (i = 0; i < map->n; ++i) { |
3171 | map->p[i] = drop(map->p[i], type, first, n); |
3172 | if (!map->p[i]) |
3173 | return isl_map_free(map); |
3174 | } |
3175 | |
3176 | if (map->n > 1) |
3177 | ISL_F_CLR(map, ISL_MAP_DISJOINT); |
3178 | |
3179 | return map; |
3180 | } |
3181 | |
3182 | /* Drop all constraints in map that involve any of the dimensions |
3183 | * first to first + n - 1 of the given type. |
3184 | */ |
3185 | __isl_give isl_map *isl_map_drop_constraints_involving_dims( |
3186 | __isl_take isl_map *map, |
3187 | enum isl_dim_type type, unsigned first, unsigned n) |
3188 | { |
3189 | if (n == 0) |
3190 | return map; |
3191 | return drop_constraints(map, type, first, n, |
3192 | drop: &isl_basic_map_drop_constraints_involving_dims); |
3193 | } |
3194 | |
3195 | /* Drop all constraints in "map" that do not involve any of the dimensions |
3196 | * first to first + n - 1 of the given type. |
3197 | */ |
3198 | __isl_give isl_map *isl_map_drop_constraints_not_involving_dims( |
3199 | __isl_take isl_map *map, |
3200 | enum isl_dim_type type, unsigned first, unsigned n) |
3201 | { |
3202 | if (n == 0) { |
3203 | isl_space *space = isl_map_get_space(map); |
3204 | isl_map_free(map); |
3205 | return isl_map_universe(space); |
3206 | } |
3207 | return drop_constraints(map, type, first, n, |
3208 | drop: &isl_basic_map_drop_constraints_not_involving_dims); |
3209 | } |
3210 | |
3211 | /* Drop all constraints in set that involve any of the dimensions |
3212 | * first to first + n - 1 of the given type. |
3213 | */ |
3214 | __isl_give isl_set *isl_set_drop_constraints_involving_dims( |
3215 | __isl_take isl_set *set, |
3216 | enum isl_dim_type type, unsigned first, unsigned n) |
3217 | { |
3218 | return isl_map_drop_constraints_involving_dims(map: set, type, first, n); |
3219 | } |
3220 | |
3221 | /* Drop all constraints in "set" that do not involve any of the dimensions |
3222 | * first to first + n - 1 of the given type. |
3223 | */ |
3224 | __isl_give isl_set *isl_set_drop_constraints_not_involving_dims( |
3225 | __isl_take isl_set *set, |
3226 | enum isl_dim_type type, unsigned first, unsigned n) |
3227 | { |
3228 | return isl_map_drop_constraints_not_involving_dims(map: set, type, first, n); |
3229 | } |
3230 | |
3231 | /* Does local variable "div" of "bmap" have a complete explicit representation? |
3232 | * Having a complete explicit representation requires not only |
3233 | * an explicit representation, but also that all local variables |
3234 | * that appear in this explicit representation in turn have |
3235 | * a complete explicit representation. |
3236 | */ |
3237 | isl_bool isl_basic_map_div_is_known(__isl_keep isl_basic_map *bmap, int div) |
3238 | { |
3239 | int i; |
3240 | unsigned div_offset = isl_basic_map_offset(bmap, type: isl_dim_div); |
3241 | isl_bool marked; |
3242 | |
3243 | marked = isl_basic_map_div_is_marked_unknown(bmap, div); |
3244 | if (marked < 0 || marked) |
3245 | return isl_bool_not(b: marked); |
3246 | |
3247 | for (i = bmap->n_div - 1; i >= 0; --i) { |
3248 | isl_bool known; |
3249 | |
3250 | if (isl_int_is_zero(bmap->div[div][1 + div_offset + i])) |
3251 | continue; |
3252 | known = isl_basic_map_div_is_known(bmap, div: i); |
3253 | if (known < 0 || !known) |
3254 | return known; |
3255 | } |
3256 | |
3257 | return isl_bool_true; |
3258 | } |
3259 | |
3260 | /* Remove all divs that are unknown or defined in terms of unknown divs. |
3261 | */ |
3262 | __isl_give isl_basic_map *isl_basic_map_remove_unknown_divs( |
3263 | __isl_take isl_basic_map *bmap) |
3264 | { |
3265 | int i; |
3266 | |
3267 | if (!bmap) |
3268 | return NULL; |
3269 | |
3270 | for (i = bmap->n_div - 1; i >= 0; --i) { |
3271 | if (isl_basic_map_div_is_known(bmap, div: i)) |
3272 | continue; |
3273 | bmap = isl_basic_map_remove_dims(bmap, type: isl_dim_div, first: i, n: 1); |
3274 | if (!bmap) |
3275 | return NULL; |
3276 | i = bmap->n_div; |
3277 | } |
3278 | |
3279 | return bmap; |
3280 | } |
3281 | |
3282 | /* Remove all divs that are unknown or defined in terms of unknown divs. |
3283 | */ |
3284 | __isl_give isl_basic_set *isl_basic_set_remove_unknown_divs( |
3285 | __isl_take isl_basic_set *bset) |
3286 | { |
3287 | return isl_basic_map_remove_unknown_divs(bmap: bset); |
3288 | } |
3289 | |
3290 | __isl_give isl_map *isl_map_remove_unknown_divs(__isl_take isl_map *map) |
3291 | { |
3292 | int i; |
3293 | |
3294 | if (!map) |
3295 | return NULL; |
3296 | if (map->n == 0) |
3297 | return map; |
3298 | |
3299 | map = isl_map_cow(map); |
3300 | if (!map) |
3301 | return NULL; |
3302 | |
3303 | for (i = 0; i < map->n; ++i) { |
3304 | map->p[i] = isl_basic_map_remove_unknown_divs(bmap: map->p[i]); |
3305 | if (!map->p[i]) |
3306 | goto error; |
3307 | } |
3308 | return map; |
3309 | error: |
3310 | isl_map_free(map); |
3311 | return NULL; |
3312 | } |
3313 | |
3314 | __isl_give isl_set *isl_set_remove_unknown_divs(__isl_take isl_set *set) |
3315 | { |
3316 | return set_from_map(isl_map_remove_unknown_divs(map: set_to_map(set))); |
3317 | } |
3318 | |
3319 | __isl_give isl_basic_set *isl_basic_set_remove_dims( |
3320 | __isl_take isl_basic_set *bset, |
3321 | enum isl_dim_type type, unsigned first, unsigned n) |
3322 | { |
3323 | isl_basic_map *bmap = bset_to_bmap(bset); |
3324 | bmap = isl_basic_map_remove_dims(bmap, type, first, n); |
3325 | return bset_from_bmap(bmap); |
3326 | } |
3327 | |
3328 | __isl_give isl_map *isl_map_remove_dims(__isl_take isl_map *map, |
3329 | enum isl_dim_type type, unsigned first, unsigned n) |
3330 | { |
3331 | int i; |
3332 | |
3333 | if (n == 0) |
3334 | return map; |
3335 | |
3336 | map = isl_map_cow(map); |
3337 | if (isl_map_check_range(obj: map, type, first, n) < 0) |
3338 | return isl_map_free(map); |
3339 | |
3340 | for (i = 0; i < map->n; ++i) { |
3341 | map->p[i] = isl_basic_map_eliminate_vars(bmap: map->p[i], |
3342 | pos: isl_basic_map_offset(bmap: map->p[i], type) - 1 + first, n); |
3343 | if (!map->p[i]) |
3344 | goto error; |
3345 | } |
3346 | map = isl_map_drop(map, type, first, n); |
3347 | return map; |
3348 | error: |
3349 | isl_map_free(map); |
3350 | return NULL; |
3351 | } |
3352 | |
3353 | __isl_give isl_set *isl_set_remove_dims(__isl_take isl_set *bset, |
3354 | enum isl_dim_type type, unsigned first, unsigned n) |
3355 | { |
3356 | return set_from_map(isl_map_remove_dims(map: set_to_map(bset), |
3357 | type, first, n)); |
3358 | } |
3359 | |
3360 | /* Project out n inputs starting at first using Fourier-Motzkin */ |
3361 | __isl_give isl_map *isl_map_remove_inputs(__isl_take isl_map *map, |
3362 | unsigned first, unsigned n) |
3363 | { |
3364 | return isl_map_remove_dims(map, type: isl_dim_in, first, n); |
3365 | } |
3366 | |
3367 | void isl_basic_set_print_internal(__isl_keep isl_basic_set *bset, |
3368 | FILE *out, int indent) |
3369 | { |
3370 | isl_printer *p; |
3371 | |
3372 | if (!bset) { |
3373 | fprintf(stream: out, format: "null basic set\n" ); |
3374 | return; |
3375 | } |
3376 | |
3377 | fprintf(stream: out, format: "%*s" , indent, "" ); |
3378 | fprintf(stream: out, format: "ref: %d, nparam: %d, dim: %d, extra: %d, flags: %x\n" , |
3379 | bset->ref, bset->dim->nparam, bset->dim->n_out, |
3380 | bset->extra, bset->flags); |
3381 | |
3382 | p = isl_printer_to_file(ctx: isl_basic_set_get_ctx(bset), file: out); |
3383 | p = isl_printer_set_dump(p, dump: 1); |
3384 | p = isl_printer_set_indent(p, indent); |
3385 | p = isl_printer_start_line(p); |
3386 | p = isl_printer_print_basic_set(printer: p, bset); |
3387 | p = isl_printer_end_line(p); |
3388 | isl_printer_free(printer: p); |
3389 | } |
3390 | |
3391 | void isl_basic_map_print_internal(__isl_keep isl_basic_map *bmap, |
3392 | FILE *out, int indent) |
3393 | { |
3394 | isl_printer *p; |
3395 | |
3396 | if (!bmap) { |
3397 | fprintf(stream: out, format: "null basic map\n" ); |
3398 | return; |
3399 | } |
3400 | |
3401 | fprintf(stream: out, format: "%*s" , indent, "" ); |
3402 | fprintf(stream: out, format: "ref: %d, nparam: %d, in: %d, out: %d, extra: %d, " |
3403 | "flags: %x, n_name: %d\n" , |
3404 | bmap->ref, |
3405 | bmap->dim->nparam, bmap->dim->n_in, bmap->dim->n_out, |
3406 | bmap->extra, bmap->flags, bmap->dim->n_id); |
3407 | |
3408 | p = isl_printer_to_file(ctx: isl_basic_map_get_ctx(bmap), file: out); |
3409 | p = isl_printer_set_dump(p, dump: 1); |
3410 | p = isl_printer_set_indent(p, indent); |
3411 | p = isl_printer_start_line(p); |
3412 | p = isl_printer_print_basic_map(printer: p, bmap); |
3413 | p = isl_printer_end_line(p); |
3414 | isl_printer_free(printer: p); |
3415 | } |
3416 | |
3417 | __isl_give isl_basic_map *isl_inequality_negate(__isl_take isl_basic_map *bmap, |
3418 | unsigned pos) |
3419 | { |
3420 | isl_size total; |
3421 | |
3422 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
3423 | if (total < 0) |
3424 | return isl_basic_map_free(bmap); |
3425 | if (pos >= bmap->n_ineq) |
3426 | isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, |
3427 | "invalid position" , return isl_basic_map_free(bmap)); |
3428 | isl_seq_neg(dst: bmap->ineq[pos], src: bmap->ineq[pos], len: 1 + total); |
3429 | isl_int_sub_ui(bmap->ineq[pos][0], bmap->ineq[pos][0], 1); |
3430 | ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT); |
3431 | ISL_F_CLR(bmap, ISL_BASIC_MAP_SORTED); |
3432 | return bmap; |
3433 | } |
3434 | |
3435 | __isl_give isl_set *isl_set_alloc_space(__isl_take isl_space *space, int n, |
3436 | unsigned flags) |
3437 | { |
3438 | if (isl_space_check_is_set(space) < 0) |
3439 | goto error; |
3440 | return isl_map_alloc_space(space, n, flags); |
3441 | error: |
3442 | isl_space_free(space); |
3443 | return NULL; |
3444 | } |
3445 | |
3446 | /* Make sure "map" has room for at least "n" more basic maps. |
3447 | */ |
3448 | __isl_give isl_map *isl_map_grow(__isl_take isl_map *map, int n) |
3449 | { |
3450 | int i; |
3451 | struct isl_map *grown = NULL; |
3452 | |
3453 | if (!map) |
3454 | return NULL; |
3455 | isl_assert(map->ctx, n >= 0, goto error); |
3456 | if (map->n + n <= map->size) |
3457 | return map; |
3458 | grown = isl_map_alloc_space(space: isl_map_get_space(map), n: map->n + n, flags: map->flags); |
3459 | if (!grown) |
3460 | goto error; |
3461 | for (i = 0; i < map->n; ++i) { |
3462 | grown->p[i] = isl_basic_map_copy(bmap: map->p[i]); |
3463 | if (!grown->p[i]) |
3464 | goto error; |
3465 | grown->n++; |
3466 | } |
3467 | isl_map_free(map); |
3468 | return grown; |
3469 | error: |
3470 | isl_map_free(map: grown); |
3471 | isl_map_free(map); |
3472 | return NULL; |
3473 | } |
3474 | |
3475 | /* Make sure "set" has room for at least "n" more basic sets. |
3476 | */ |
3477 | __isl_give isl_set *isl_set_grow(__isl_take isl_set *set, int n) |
3478 | { |
3479 | return set_from_map(isl_map_grow(map: set_to_map(set), n)); |
3480 | } |
3481 | |
3482 | __isl_give isl_set *isl_set_from_basic_set(__isl_take isl_basic_set *bset) |
3483 | { |
3484 | return isl_map_from_basic_map(bmap: bset); |
3485 | } |
3486 | |
3487 | /* This function performs the same operation as isl_set_from_basic_set, |
3488 | * but is considered as a function on an isl_basic_set when exported. |
3489 | */ |
3490 | __isl_give isl_set *isl_basic_set_to_set(__isl_take isl_basic_set *bset) |
3491 | { |
3492 | return isl_set_from_basic_set(bset); |
3493 | } |
3494 | |
3495 | __isl_give isl_map *isl_map_from_basic_map(__isl_take isl_basic_map *bmap) |
3496 | { |
3497 | struct isl_map *map; |
3498 | |
3499 | if (!bmap) |
3500 | return NULL; |
3501 | |
3502 | map = isl_map_alloc_space(space: isl_space_copy(space: bmap->dim), n: 1, ISL_MAP_DISJOINT); |
3503 | return isl_map_add_basic_map(map, bmap); |
3504 | } |
3505 | |
3506 | __isl_give isl_set *isl_set_add_basic_set(__isl_take isl_set *set, |
3507 | __isl_take isl_basic_set *bset) |
3508 | { |
3509 | return set_from_map(isl_map_add_basic_map(map: set_to_map(set), |
3510 | bmap: bset_to_bmap(bset))); |
3511 | } |
3512 | |
3513 | __isl_null isl_set *isl_set_free(__isl_take isl_set *set) |
3514 | { |
3515 | return isl_map_free(map: set); |
3516 | } |
3517 | |
3518 | void isl_set_print_internal(__isl_keep isl_set *set, FILE *out, int indent) |
3519 | { |
3520 | int i; |
3521 | |
3522 | if (!set) { |
3523 | fprintf(stream: out, format: "null set\n" ); |
3524 | return; |
3525 | } |
3526 | |
3527 | fprintf(stream: out, format: "%*s" , indent, "" ); |
3528 | fprintf(stream: out, format: "ref: %d, n: %d, nparam: %d, dim: %d, flags: %x\n" , |
3529 | set->ref, set->n, set->dim->nparam, set->dim->n_out, |
3530 | set->flags); |
3531 | for (i = 0; i < set->n; ++i) { |
3532 | fprintf(stream: out, format: "%*s" , indent, "" ); |
3533 | fprintf(stream: out, format: "basic set %d:\n" , i); |
3534 | isl_basic_set_print_internal(bset: set->p[i], out, indent: indent+4); |
3535 | } |
3536 | } |
3537 | |
3538 | void isl_map_print_internal(__isl_keep isl_map *map, FILE *out, int indent) |
3539 | { |
3540 | int i; |
3541 | |
3542 | if (!map) { |
3543 | fprintf(stream: out, format: "null map\n" ); |
3544 | return; |
3545 | } |
3546 | |
3547 | fprintf(stream: out, format: "%*s" , indent, "" ); |
3548 | fprintf(stream: out, format: "ref: %d, n: %d, nparam: %d, in: %d, out: %d, " |
3549 | "flags: %x, n_name: %d\n" , |
3550 | map->ref, map->n, map->dim->nparam, map->dim->n_in, |
3551 | map->dim->n_out, map->flags, map->dim->n_id); |
3552 | for (i = 0; i < map->n; ++i) { |
3553 | fprintf(stream: out, format: "%*s" , indent, "" ); |
3554 | fprintf(stream: out, format: "basic map %d:\n" , i); |
3555 | isl_basic_map_print_internal(bmap: map->p[i], out, indent: indent+4); |
3556 | } |
3557 | } |
3558 | |
3559 | /* Check that the space of "bset" is the same as that of the domain of "bmap". |
3560 | */ |
3561 | static isl_stat isl_basic_map_check_compatible_domain( |
3562 | __isl_keep isl_basic_map *bmap, __isl_keep isl_basic_set *bset) |
3563 | { |
3564 | isl_bool ok; |
3565 | |
3566 | ok = isl_basic_map_compatible_domain(bmap, bset); |
3567 | if (ok < 0) |
3568 | return isl_stat_error; |
3569 | if (!ok) |
3570 | isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid, |
3571 | "incompatible spaces" , return isl_stat_error); |
3572 | |
3573 | return isl_stat_ok; |
3574 | } |
3575 | |
3576 | __isl_give isl_basic_map *isl_basic_map_intersect_domain( |
3577 | __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *bset) |
3578 | { |
3579 | struct isl_basic_map *bmap_domain; |
3580 | isl_size dim; |
3581 | |
3582 | if (isl_basic_map_check_equal_params(bmap1: bmap, bmap2: bset_to_bmap(bset)) < 0) |
3583 | goto error; |
3584 | |
3585 | dim = isl_basic_set_dim(bset, type: isl_dim_set); |
3586 | if (dim < 0) |
3587 | goto error; |
3588 | if (dim != 0 && |
3589 | isl_basic_map_check_compatible_domain(bmap, bset) < 0) |
3590 | goto error; |
3591 | |
3592 | bmap = isl_basic_map_cow(bmap); |
3593 | if (!bmap) |
3594 | goto error; |
3595 | bmap = isl_basic_map_extend(base: bmap, |
3596 | extra: bset->n_div, n_eq: bset->n_eq, n_ineq: bset->n_ineq); |
3597 | bmap_domain = isl_basic_map_from_domain(bset); |
3598 | bmap = add_constraints(bmap1: bmap, bmap2: bmap_domain, i_pos: 0, o_pos: 0); |
3599 | |
3600 | bmap = isl_basic_map_simplify(bmap); |
3601 | return isl_basic_map_finalize(bmap); |
3602 | error: |
3603 | isl_basic_map_free(bmap); |
3604 | isl_basic_set_free(bset); |
3605 | return NULL; |
3606 | } |
3607 | |
3608 | /* Check that the space of "bset" is the same as that of the range of "bmap". |
3609 | */ |
3610 | static isl_stat isl_basic_map_check_compatible_range( |
3611 | __isl_keep isl_basic_map *bmap, __isl_keep isl_basic_set *bset) |
3612 | { |
3613 | isl_bool ok; |
3614 | |
3615 | ok = isl_basic_map_compatible_range(bmap, bset); |
3616 | if (ok < 0) |
3617 | return isl_stat_error; |
3618 | if (!ok) |
3619 | isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid, |
3620 | "incompatible spaces" , return isl_stat_error); |
3621 | |
3622 | return isl_stat_ok; |
3623 | } |
3624 | |
3625 | __isl_give isl_basic_map *isl_basic_map_intersect_range( |
3626 | __isl_take isl_basic_map *bmap, __isl_take isl_basic_set *bset) |
3627 | { |
3628 | struct isl_basic_map *bmap_range; |
3629 | isl_size dim; |
3630 | |
3631 | if (isl_basic_map_check_equal_params(bmap1: bmap, bmap2: bset_to_bmap(bset)) < 0) |
3632 | goto error; |
3633 | |
3634 | dim = isl_basic_set_dim(bset, type: isl_dim_set); |
3635 | if (dim < 0) |
3636 | goto error; |
3637 | if (dim != 0 && isl_basic_map_check_compatible_range(bmap, bset) < 0) |
3638 | goto error; |
3639 | |
3640 | if (isl_basic_set_plain_is_universe(bset)) { |
3641 | isl_basic_set_free(bset); |
3642 | return bmap; |
3643 | } |
3644 | |
3645 | bmap = isl_basic_map_cow(bmap); |
3646 | if (!bmap) |
3647 | goto error; |
3648 | bmap = isl_basic_map_extend(base: bmap, |
3649 | extra: bset->n_div, n_eq: bset->n_eq, n_ineq: bset->n_ineq); |
3650 | bmap_range = bset_to_bmap(bset); |
3651 | bmap = add_constraints(bmap1: bmap, bmap2: bmap_range, i_pos: 0, o_pos: 0); |
3652 | |
3653 | bmap = isl_basic_map_simplify(bmap); |
3654 | return isl_basic_map_finalize(bmap); |
3655 | error: |
3656 | isl_basic_map_free(bmap); |
3657 | isl_basic_set_free(bset); |
3658 | return NULL; |
3659 | } |
3660 | |
3661 | isl_bool isl_basic_map_contains(__isl_keep isl_basic_map *bmap, |
3662 | __isl_keep isl_vec *vec) |
3663 | { |
3664 | int i; |
3665 | isl_size total; |
3666 | isl_int s; |
3667 | |
3668 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
3669 | if (total < 0 || !vec) |
3670 | return isl_bool_error; |
3671 | |
3672 | if (1 + total != vec->size) |
3673 | return isl_bool_false; |
3674 | |
3675 | isl_int_init(s); |
3676 | |
3677 | for (i = 0; i < bmap->n_eq; ++i) { |
3678 | isl_seq_inner_product(p1: vec->el, p2: bmap->eq[i], len: 1 + total, prod: &s); |
3679 | if (!isl_int_is_zero(s)) { |
3680 | isl_int_clear(s); |
3681 | return isl_bool_false; |
3682 | } |
3683 | } |
3684 | |
3685 | for (i = 0; i < bmap->n_ineq; ++i) { |
3686 | isl_seq_inner_product(p1: vec->el, p2: bmap->ineq[i], len: 1 + total, prod: &s); |
3687 | if (isl_int_is_neg(s)) { |
3688 | isl_int_clear(s); |
3689 | return isl_bool_false; |
3690 | } |
3691 | } |
3692 | |
3693 | isl_int_clear(s); |
3694 | |
3695 | return isl_bool_true; |
3696 | } |
3697 | |
3698 | isl_bool isl_basic_set_contains(__isl_keep isl_basic_set *bset, |
3699 | __isl_keep isl_vec *vec) |
3700 | { |
3701 | return isl_basic_map_contains(bmap: bset_to_bmap(bset), vec); |
3702 | } |
3703 | |
3704 | __isl_give isl_basic_map *isl_basic_map_intersect( |
3705 | __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) |
3706 | { |
3707 | struct isl_vec *sample = NULL; |
3708 | isl_space *space1, *space2; |
3709 | isl_size dim1, dim2, nparam1, nparam2; |
3710 | |
3711 | if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0) |
3712 | goto error; |
3713 | space1 = isl_basic_map_peek_space(bmap: bmap1); |
3714 | space2 = isl_basic_map_peek_space(bmap: bmap2); |
3715 | dim1 = isl_space_dim(space: space1, type: isl_dim_all); |
3716 | dim2 = isl_space_dim(space: space2, type: isl_dim_all); |
3717 | nparam1 = isl_space_dim(space: space1, type: isl_dim_param); |
3718 | nparam2 = isl_space_dim(space: space2, type: isl_dim_param); |
3719 | if (dim1 < 0 || dim2 < 0 || nparam1 < 0 || nparam2 < 0) |
3720 | goto error; |
3721 | if (dim1 == nparam1 && dim2 != nparam2) |
3722 | return isl_basic_map_intersect(bmap1: bmap2, bmap2: bmap1); |
3723 | |
3724 | if (dim2 != nparam2 && |
3725 | isl_basic_map_check_equal_space(bmap1, bmap2) < 0) |
3726 | goto error; |
3727 | |
3728 | if (isl_basic_map_plain_is_empty(bmap: bmap1)) { |
3729 | isl_basic_map_free(bmap: bmap2); |
3730 | return bmap1; |
3731 | } |
3732 | if (isl_basic_map_plain_is_empty(bmap: bmap2)) { |
3733 | isl_basic_map_free(bmap: bmap1); |
3734 | return bmap2; |
3735 | } |
3736 | |
3737 | if (bmap1->sample && |
3738 | isl_basic_map_contains(bmap: bmap1, vec: bmap1->sample) > 0 && |
3739 | isl_basic_map_contains(bmap: bmap2, vec: bmap1->sample) > 0) |
3740 | sample = isl_vec_copy(vec: bmap1->sample); |
3741 | else if (bmap2->sample && |
3742 | isl_basic_map_contains(bmap: bmap1, vec: bmap2->sample) > 0 && |
3743 | isl_basic_map_contains(bmap: bmap2, vec: bmap2->sample) > 0) |
3744 | sample = isl_vec_copy(vec: bmap2->sample); |
3745 | |
3746 | bmap1 = isl_basic_map_cow(bmap: bmap1); |
3747 | if (!bmap1) |
3748 | goto error; |
3749 | bmap1 = isl_basic_map_extend(base: bmap1, |
3750 | extra: bmap2->n_div, n_eq: bmap2->n_eq, n_ineq: bmap2->n_ineq); |
3751 | bmap1 = add_constraints(bmap1, bmap2, i_pos: 0, o_pos: 0); |
3752 | |
3753 | if (!bmap1) |
3754 | isl_vec_free(vec: sample); |
3755 | else if (sample) { |
3756 | isl_vec_free(vec: bmap1->sample); |
3757 | bmap1->sample = sample; |
3758 | } |
3759 | |
3760 | bmap1 = isl_basic_map_simplify(bmap: bmap1); |
3761 | return isl_basic_map_finalize(bmap: bmap1); |
3762 | error: |
3763 | if (sample) |
3764 | isl_vec_free(vec: sample); |
3765 | isl_basic_map_free(bmap: bmap1); |
3766 | isl_basic_map_free(bmap: bmap2); |
3767 | return NULL; |
3768 | } |
3769 | |
3770 | __isl_give isl_basic_set *isl_basic_set_intersect( |
3771 | __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2) |
3772 | { |
3773 | return bset_from_bmap(bmap: isl_basic_map_intersect(bmap1: bset_to_bmap(bset: bset1), |
3774 | bmap2: bset_to_bmap(bset: bset2))); |
3775 | } |
3776 | |
3777 | __isl_give isl_basic_set *isl_basic_set_intersect_params( |
3778 | __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2) |
3779 | { |
3780 | return isl_basic_set_intersect(bset1, bset2); |
3781 | } |
3782 | |
3783 | /* Does "map" consist of a single disjunct, without any local variables? |
3784 | */ |
3785 | static isl_bool is_convex_no_locals(__isl_keep isl_map *map) |
3786 | { |
3787 | isl_size n_div; |
3788 | |
3789 | if (!map) |
3790 | return isl_bool_error; |
3791 | if (map->n != 1) |
3792 | return isl_bool_false; |
3793 | n_div = isl_basic_map_dim(bmap: map->p[0], type: isl_dim_div); |
3794 | if (n_div < 0) |
3795 | return isl_bool_error; |
3796 | if (n_div != 0) |
3797 | return isl_bool_false; |
3798 | return isl_bool_true; |
3799 | } |
3800 | |
3801 | /* Check that "map" consists of a single disjunct, without any local variables. |
3802 | */ |
3803 | static isl_stat check_convex_no_locals(__isl_keep isl_map *map) |
3804 | { |
3805 | isl_bool ok; |
3806 | |
3807 | ok = is_convex_no_locals(map); |
3808 | if (ok < 0) |
3809 | return isl_stat_error; |
3810 | if (ok) |
3811 | return isl_stat_ok; |
3812 | |
3813 | isl_die(isl_map_get_ctx(map), isl_error_internal, |
3814 | "unexpectedly not convex or involving local variables" , |
3815 | return isl_stat_error); |
3816 | } |
3817 | |
3818 | /* Special case of isl_map_intersect, where both map1 and map2 |
3819 | * are convex, without any divs and such that either map1 or map2 |
3820 | * contains a single constraint. This constraint is then simply |
3821 | * added to the other map. |
3822 | */ |
3823 | static __isl_give isl_map *map_intersect_add_constraint( |
3824 | __isl_take isl_map *map1, __isl_take isl_map *map2) |
3825 | { |
3826 | if (check_convex_no_locals(map: map1) < 0 || |
3827 | check_convex_no_locals(map: map2) < 0) |
3828 | goto error; |
3829 | |
3830 | if (map2->p[0]->n_eq + map2->p[0]->n_ineq != 1) |
3831 | return isl_map_intersect(map1: map2, map2: map1); |
3832 | |
3833 | map1 = isl_map_cow(map: map1); |
3834 | if (!map1) |
3835 | goto error; |
3836 | if (isl_map_plain_is_empty(map: map1)) { |
3837 | isl_map_free(map: map2); |
3838 | return map1; |
3839 | } |
3840 | if (map2->p[0]->n_eq == 1) |
3841 | map1->p[0] = isl_basic_map_add_eq(bmap: map1->p[0], eq: map2->p[0]->eq[0]); |
3842 | else |
3843 | map1->p[0] = isl_basic_map_add_ineq(bmap: map1->p[0], |
3844 | ineq: map2->p[0]->ineq[0]); |
3845 | |
3846 | map1->p[0] = isl_basic_map_simplify(bmap: map1->p[0]); |
3847 | map1->p[0] = isl_basic_map_finalize(bmap: map1->p[0]); |
3848 | if (!map1->p[0]) |
3849 | goto error; |
3850 | |
3851 | if (isl_basic_map_plain_is_empty(bmap: map1->p[0])) { |
3852 | isl_basic_map_free(bmap: map1->p[0]); |
3853 | map1->n = 0; |
3854 | } |
3855 | |
3856 | isl_map_free(map: map2); |
3857 | |
3858 | map1 = isl_map_unmark_normalized(map: map1); |
3859 | return map1; |
3860 | error: |
3861 | isl_map_free(map: map1); |
3862 | isl_map_free(map: map2); |
3863 | return NULL; |
3864 | } |
3865 | |
3866 | /* map2 may be either a parameter domain or a map living in the same |
3867 | * space as map1. |
3868 | */ |
3869 | static __isl_give isl_map *map_intersect_internal(__isl_take isl_map *map1, |
3870 | __isl_take isl_map *map2) |
3871 | { |
3872 | unsigned flags = 0; |
3873 | isl_bool equal; |
3874 | isl_map *result; |
3875 | int i, j; |
3876 | isl_size dim2, nparam2; |
3877 | |
3878 | if (!map1 || !map2) |
3879 | goto error; |
3880 | |
3881 | if ((isl_map_plain_is_empty(map: map1) || |
3882 | isl_map_plain_is_universe(map: map2)) && |
3883 | isl_space_is_equal(space1: map1->dim, space2: map2->dim)) { |
3884 | isl_map_free(map: map2); |
3885 | return map1; |
3886 | } |
3887 | if ((isl_map_plain_is_empty(map: map2) || |
3888 | isl_map_plain_is_universe(map: map1)) && |
3889 | isl_space_is_equal(space1: map1->dim, space2: map2->dim)) { |
3890 | isl_map_free(map: map1); |
3891 | return map2; |
3892 | } |
3893 | |
3894 | if (is_convex_no_locals(map: map1) == isl_bool_true && |
3895 | is_convex_no_locals(map: map2) == isl_bool_true && |
3896 | isl_space_is_equal(space1: map1->dim, space2: map2->dim) && |
3897 | (map1->p[0]->n_eq + map1->p[0]->n_ineq == 1 || |
3898 | map2->p[0]->n_eq + map2->p[0]->n_ineq == 1)) |
3899 | return map_intersect_add_constraint(map1, map2); |
3900 | |
3901 | equal = isl_map_plain_is_equal(map1, map2); |
3902 | if (equal < 0) |
3903 | goto error; |
3904 | if (equal) { |
3905 | isl_map_free(map: map2); |
3906 | return map1; |
3907 | } |
3908 | |
3909 | dim2 = isl_map_dim(map: map2, type: isl_dim_all); |
3910 | nparam2 = isl_map_dim(map: map2, type: isl_dim_param); |
3911 | if (dim2 < 0 || nparam2 < 0) |
3912 | goto error; |
3913 | if (dim2 != nparam2) |
3914 | isl_assert(map1->ctx, |
3915 | isl_space_is_equal(map1->dim, map2->dim), goto error); |
3916 | |
3917 | if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) && |
3918 | ISL_F_ISSET(map2, ISL_MAP_DISJOINT)) |
3919 | ISL_FL_SET(flags, ISL_MAP_DISJOINT); |
3920 | |
3921 | result = isl_map_alloc_space(space: isl_space_copy(space: map1->dim), |
3922 | n: map1->n * map2->n, flags); |
3923 | if (!result) |
3924 | goto error; |
3925 | for (i = 0; i < map1->n; ++i) |
3926 | for (j = 0; j < map2->n; ++j) { |
3927 | struct isl_basic_map *part; |
3928 | part = isl_basic_map_intersect( |
3929 | bmap1: isl_basic_map_copy(bmap: map1->p[i]), |
3930 | bmap2: isl_basic_map_copy(bmap: map2->p[j])); |
3931 | if (isl_basic_map_is_empty(bmap: part) < 0) |
3932 | part = isl_basic_map_free(bmap: part); |
3933 | result = isl_map_add_basic_map(map: result, bmap: part); |
3934 | if (!result) |
3935 | goto error; |
3936 | } |
3937 | isl_map_free(map: map1); |
3938 | isl_map_free(map: map2); |
3939 | return result; |
3940 | error: |
3941 | isl_map_free(map: map1); |
3942 | isl_map_free(map: map2); |
3943 | return NULL; |
3944 | } |
3945 | |
3946 | static __isl_give isl_map *map_intersect(__isl_take isl_map *map1, |
3947 | __isl_take isl_map *map2) |
3948 | { |
3949 | if (isl_map_check_equal_space(map1, map2) < 0) |
3950 | goto error; |
3951 | return map_intersect_internal(map1, map2); |
3952 | error: |
3953 | isl_map_free(map: map1); |
3954 | isl_map_free(map: map2); |
3955 | return NULL; |
3956 | } |
3957 | |
3958 | __isl_give isl_map *isl_map_intersect(__isl_take isl_map *map1, |
3959 | __isl_take isl_map *map2) |
3960 | { |
3961 | isl_map_align_params_bin(obj1: &map1, obj2: &map2); |
3962 | return map_intersect(map1, map2); |
3963 | } |
3964 | |
3965 | __isl_give isl_set *isl_set_intersect(__isl_take isl_set *set1, |
3966 | __isl_take isl_set *set2) |
3967 | { |
3968 | return set_from_map(isl_map_intersect(map1: set_to_map(set1), |
3969 | map2: set_to_map(set2))); |
3970 | } |
3971 | |
3972 | /* map_intersect_internal accepts intersections |
3973 | * with parameter domains, so we can just call that function. |
3974 | */ |
3975 | __isl_give isl_map *isl_map_intersect_params(__isl_take isl_map *map, |
3976 | __isl_take isl_set *params) |
3977 | { |
3978 | isl_map_align_params_set(obj1: &map, obj2: ¶ms); |
3979 | return map_intersect_internal(map1: map, map2: params); |
3980 | } |
3981 | |
3982 | __isl_give isl_set *isl_set_intersect_params(__isl_take isl_set *set, |
3983 | __isl_take isl_set *params) |
3984 | { |
3985 | return isl_map_intersect_params(map: set, params); |
3986 | } |
3987 | |
3988 | __isl_give isl_basic_map *isl_basic_map_reverse(__isl_take isl_basic_map *bmap) |
3989 | { |
3990 | isl_space *space; |
3991 | unsigned pos; |
3992 | isl_size n1, n2; |
3993 | |
3994 | if (!bmap) |
3995 | return NULL; |
3996 | bmap = isl_basic_map_cow(bmap); |
3997 | if (!bmap) |
3998 | return NULL; |
3999 | space = isl_space_reverse(space: isl_space_copy(space: bmap->dim)); |
4000 | pos = isl_basic_map_offset(bmap, type: isl_dim_in); |
4001 | n1 = isl_basic_map_dim(bmap, type: isl_dim_in); |
4002 | n2 = isl_basic_map_dim(bmap, type: isl_dim_out); |
4003 | if (n1 < 0 || n2 < 0) |
4004 | bmap = isl_basic_map_free(bmap); |
4005 | bmap = isl_basic_map_swap_vars(bmap, pos, n1, n2); |
4006 | return isl_basic_map_reset_space(bmap, space); |
4007 | } |
4008 | |
4009 | /* Given a basic map A -> (B -> C), return the corresponding basic map |
4010 | * A -> (C -> B). |
4011 | */ |
4012 | static __isl_give isl_basic_map *isl_basic_map_range_reverse( |
4013 | __isl_take isl_basic_map *bmap) |
4014 | { |
4015 | isl_space *space; |
4016 | isl_size offset, n1, n2; |
4017 | |
4018 | space = isl_basic_map_peek_space(bmap); |
4019 | if (isl_space_check_range_is_wrapping(space) < 0) |
4020 | return isl_basic_map_free(bmap); |
4021 | offset = isl_basic_map_var_offset(bmap, type: isl_dim_out); |
4022 | n1 = isl_space_wrapped_dim(space, outer: isl_dim_out, inner: isl_dim_in); |
4023 | n2 = isl_space_wrapped_dim(space, outer: isl_dim_out, inner: isl_dim_out); |
4024 | if (offset < 0 || n1 < 0 || n2 < 0) |
4025 | return isl_basic_map_free(bmap); |
4026 | |
4027 | bmap = isl_basic_map_swap_vars(bmap, pos: 1 + offset, n1, n2); |
4028 | |
4029 | space = isl_basic_map_take_space(bmap); |
4030 | space = isl_space_range_reverse(space); |
4031 | bmap = isl_basic_map_restore_space(bmap, space); |
4032 | |
4033 | return bmap; |
4034 | } |
4035 | |
4036 | static __isl_give isl_basic_map *basic_map_space_reset( |
4037 | __isl_take isl_basic_map *bmap, enum isl_dim_type type) |
4038 | { |
4039 | isl_space *space; |
4040 | |
4041 | if (!bmap) |
4042 | return NULL; |
4043 | if (!isl_space_is_named_or_nested(space: bmap->dim, type)) |
4044 | return bmap; |
4045 | |
4046 | space = isl_basic_map_get_space(bmap); |
4047 | space = isl_space_reset(space, type); |
4048 | bmap = isl_basic_map_reset_space(bmap, space); |
4049 | return bmap; |
4050 | } |
4051 | |
4052 | __isl_give isl_basic_map *isl_basic_map_insert_dims( |
4053 | __isl_take isl_basic_map *bmap, enum isl_dim_type type, |
4054 | unsigned pos, unsigned n) |
4055 | { |
4056 | isl_bool rational, is_empty; |
4057 | isl_space *res_space; |
4058 | struct isl_basic_map *res; |
4059 | struct isl_dim_map *dim_map; |
4060 | isl_size total; |
4061 | unsigned off; |
4062 | enum isl_dim_type t; |
4063 | |
4064 | if (n == 0) |
4065 | return basic_map_space_reset(bmap, type); |
4066 | |
4067 | is_empty = isl_basic_map_plain_is_empty(bmap); |
4068 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
4069 | if (is_empty < 0 || total < 0) |
4070 | return isl_basic_map_free(bmap); |
4071 | res_space = isl_space_insert_dims(space: isl_basic_map_get_space(bmap), |
4072 | type, pos, n); |
4073 | if (!res_space) |
4074 | return isl_basic_map_free(bmap); |
4075 | if (is_empty) { |
4076 | isl_basic_map_free(bmap); |
4077 | return isl_basic_map_empty(space: res_space); |
4078 | } |
4079 | |
4080 | dim_map = isl_dim_map_alloc(ctx: bmap->ctx, len: total + n); |
4081 | off = 0; |
4082 | for (t = isl_dim_param; t <= isl_dim_out; ++t) { |
4083 | isl_size dim; |
4084 | |
4085 | if (t != type) { |
4086 | isl_dim_map_dim(dim_map, space: bmap->dim, type: t, dst_pos: off); |
4087 | } else { |
4088 | isl_size size = isl_basic_map_dim(bmap, type: t); |
4089 | if (size < 0) |
4090 | dim_map = isl_dim_map_free(dim_map); |
4091 | isl_dim_map_dim_range(dim_map, space: bmap->dim, type: t, |
4092 | first: 0, n: pos, dst_pos: off); |
4093 | isl_dim_map_dim_range(dim_map, space: bmap->dim, type: t, |
4094 | first: pos, n: size - pos, dst_pos: off + pos + n); |
4095 | } |
4096 | dim = isl_space_dim(space: res_space, type: t); |
4097 | if (dim < 0) |
4098 | dim_map = isl_dim_map_free(dim_map); |
4099 | off += dim; |
4100 | } |
4101 | isl_dim_map_div(dim_map, bmap, dst_pos: off); |
4102 | |
4103 | res = isl_basic_map_alloc_space(space: res_space, |
4104 | extra: bmap->n_div, n_eq: bmap->n_eq, n_ineq: bmap->n_ineq); |
4105 | rational = isl_basic_map_is_rational(bmap); |
4106 | if (rational < 0) |
4107 | res = isl_basic_map_free(bmap: res); |
4108 | if (rational) |
4109 | res = isl_basic_map_set_rational(bmap: res); |
4110 | res = isl_basic_map_add_constraints_dim_map(dst: res, src: bmap, dim_map); |
4111 | return isl_basic_map_finalize(bmap: res); |
4112 | } |
4113 | |
4114 | __isl_give isl_basic_set *isl_basic_set_insert_dims( |
4115 | __isl_take isl_basic_set *bset, |
4116 | enum isl_dim_type type, unsigned pos, unsigned n) |
4117 | { |
4118 | return isl_basic_map_insert_dims(bmap: bset, type, pos, n); |
4119 | } |
4120 | |
4121 | __isl_give isl_basic_map *isl_basic_map_add_dims(__isl_take isl_basic_map *bmap, |
4122 | enum isl_dim_type type, unsigned n) |
4123 | { |
4124 | isl_size dim; |
4125 | |
4126 | dim = isl_basic_map_dim(bmap, type); |
4127 | if (dim < 0) |
4128 | return isl_basic_map_free(bmap); |
4129 | return isl_basic_map_insert_dims(bmap, type, pos: dim, n); |
4130 | } |
4131 | |
4132 | __isl_give isl_basic_set *isl_basic_set_add_dims(__isl_take isl_basic_set *bset, |
4133 | enum isl_dim_type type, unsigned n) |
4134 | { |
4135 | if (!bset) |
4136 | return NULL; |
4137 | isl_assert(bset->ctx, type != isl_dim_in, goto error); |
4138 | return isl_basic_map_add_dims(bmap: bset, type, n); |
4139 | error: |
4140 | isl_basic_set_free(bset); |
4141 | return NULL; |
4142 | } |
4143 | |
4144 | static __isl_give isl_map *map_space_reset(__isl_take isl_map *map, |
4145 | enum isl_dim_type type) |
4146 | { |
4147 | isl_space *space; |
4148 | |
4149 | if (!map || !isl_space_is_named_or_nested(space: map->dim, type)) |
4150 | return map; |
4151 | |
4152 | space = isl_map_get_space(map); |
4153 | space = isl_space_reset(space, type); |
4154 | map = isl_map_reset_space(map, space); |
4155 | return map; |
4156 | } |
4157 | |
4158 | __isl_give isl_map *isl_map_insert_dims(__isl_take isl_map *map, |
4159 | enum isl_dim_type type, unsigned pos, unsigned n) |
4160 | { |
4161 | int i; |
4162 | isl_space *space; |
4163 | |
4164 | if (n == 0) |
4165 | return map_space_reset(map, type); |
4166 | |
4167 | map = isl_map_cow(map); |
4168 | if (!map) |
4169 | return NULL; |
4170 | |
4171 | for (i = 0; i < map->n; ++i) { |
4172 | map->p[i] = isl_basic_map_insert_dims(bmap: map->p[i], type, pos, n); |
4173 | if (!map->p[i]) |
4174 | goto error; |
4175 | } |
4176 | |
4177 | space = isl_map_take_space(map); |
4178 | space = isl_space_insert_dims(space, type, pos, n); |
4179 | map = isl_map_restore_space(map, space); |
4180 | |
4181 | return map; |
4182 | error: |
4183 | isl_map_free(map); |
4184 | return NULL; |
4185 | } |
4186 | |
4187 | __isl_give isl_set *isl_set_insert_dims(__isl_take isl_set *set, |
4188 | enum isl_dim_type type, unsigned pos, unsigned n) |
4189 | { |
4190 | return isl_map_insert_dims(map: set, type, pos, n); |
4191 | } |
4192 | |
4193 | __isl_give isl_map *isl_map_add_dims(__isl_take isl_map *map, |
4194 | enum isl_dim_type type, unsigned n) |
4195 | { |
4196 | isl_size dim; |
4197 | |
4198 | dim = isl_map_dim(map, type); |
4199 | if (dim < 0) |
4200 | return isl_map_free(map); |
4201 | return isl_map_insert_dims(map, type, pos: dim, n); |
4202 | } |
4203 | |
4204 | __isl_give isl_set *isl_set_add_dims(__isl_take isl_set *set, |
4205 | enum isl_dim_type type, unsigned n) |
4206 | { |
4207 | if (!set) |
4208 | return NULL; |
4209 | isl_assert(set->ctx, type != isl_dim_in, goto error); |
4210 | return set_from_map(isl_map_add_dims(map: set_to_map(set), type, n)); |
4211 | error: |
4212 | isl_set_free(set); |
4213 | return NULL; |
4214 | } |
4215 | |
4216 | __isl_give isl_basic_map *isl_basic_map_move_dims( |
4217 | __isl_take isl_basic_map *bmap, |
4218 | enum isl_dim_type dst_type, unsigned dst_pos, |
4219 | enum isl_dim_type src_type, unsigned src_pos, unsigned n) |
4220 | { |
4221 | isl_space *space; |
4222 | struct isl_dim_map *dim_map; |
4223 | struct isl_basic_map *res; |
4224 | enum isl_dim_type t; |
4225 | isl_size total; |
4226 | unsigned off; |
4227 | |
4228 | if (!bmap) |
4229 | return NULL; |
4230 | if (n == 0) { |
4231 | bmap = isl_basic_map_reset(bmap, type: src_type); |
4232 | bmap = isl_basic_map_reset(bmap, type: dst_type); |
4233 | return bmap; |
4234 | } |
4235 | |
4236 | if (isl_basic_map_check_range(obj: bmap, type: src_type, first: src_pos, n) < 0) |
4237 | return isl_basic_map_free(bmap); |
4238 | |
4239 | if (dst_type == src_type && dst_pos == src_pos) |
4240 | return bmap; |
4241 | |
4242 | isl_assert(bmap->ctx, dst_type != src_type, goto error); |
4243 | |
4244 | if (pos(space: bmap->dim, type: dst_type) + dst_pos == |
4245 | pos(space: bmap->dim, type: src_type) + src_pos + |
4246 | ((src_type < dst_type) ? n : 0)) { |
4247 | space = isl_basic_map_take_space(bmap); |
4248 | space = isl_space_move_dims(space, dst_type, dst_pos, |
4249 | src_type, src_pos, n); |
4250 | bmap = isl_basic_map_restore_space(bmap, space); |
4251 | bmap = isl_basic_map_finalize(bmap); |
4252 | |
4253 | return bmap; |
4254 | } |
4255 | |
4256 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
4257 | if (total < 0) |
4258 | return isl_basic_map_free(bmap); |
4259 | dim_map = isl_dim_map_alloc(ctx: bmap->ctx, len: total); |
4260 | |
4261 | off = 0; |
4262 | space = isl_basic_map_peek_space(bmap); |
4263 | for (t = isl_dim_param; t <= isl_dim_out; ++t) { |
4264 | isl_size size = isl_space_dim(space, type: t); |
4265 | if (size < 0) |
4266 | dim_map = isl_dim_map_free(dim_map); |
4267 | if (t == dst_type) { |
4268 | isl_dim_map_dim_range(dim_map, space, type: t, |
4269 | first: 0, n: dst_pos, dst_pos: off); |
4270 | off += dst_pos; |
4271 | isl_dim_map_dim_range(dim_map, space, type: src_type, |
4272 | first: src_pos, n, dst_pos: off); |
4273 | off += n; |
4274 | isl_dim_map_dim_range(dim_map, space, type: t, |
4275 | first: dst_pos, n: size - dst_pos, dst_pos: off); |
4276 | off += size - dst_pos; |
4277 | } else if (t == src_type) { |
4278 | isl_dim_map_dim_range(dim_map, space, type: t, |
4279 | first: 0, n: src_pos, dst_pos: off); |
4280 | off += src_pos; |
4281 | isl_dim_map_dim_range(dim_map, space, type: t, |
4282 | first: src_pos + n, n: size - src_pos - n, dst_pos: off); |
4283 | off += size - src_pos - n; |
4284 | } else { |
4285 | isl_dim_map_dim(dim_map, space, type: t, dst_pos: off); |
4286 | off += size; |
4287 | } |
4288 | } |
4289 | isl_dim_map_div(dim_map, bmap, dst_pos: off); |
4290 | |
4291 | res = isl_basic_map_alloc_space(space: isl_basic_map_get_space(bmap), |
4292 | extra: bmap->n_div, n_eq: bmap->n_eq, n_ineq: bmap->n_ineq); |
4293 | bmap = isl_basic_map_add_constraints_dim_map(dst: res, src: bmap, dim_map); |
4294 | space = isl_basic_map_take_space(bmap); |
4295 | space = isl_space_move_dims(space, dst_type, dst_pos, |
4296 | src_type, src_pos, n); |
4297 | bmap = isl_basic_map_restore_space(bmap, space); |
4298 | if (!bmap) |
4299 | goto error; |
4300 | |
4301 | ISL_F_CLR(bmap, ISL_BASIC_MAP_SORTED); |
4302 | bmap = isl_basic_map_gauss(bmap, NULL); |
4303 | bmap = isl_basic_map_finalize(bmap); |
4304 | |
4305 | return bmap; |
4306 | error: |
4307 | isl_basic_map_free(bmap); |
4308 | return NULL; |
4309 | } |
4310 | |
4311 | __isl_give isl_basic_set *isl_basic_set_move_dims(__isl_take isl_basic_set *bset, |
4312 | enum isl_dim_type dst_type, unsigned dst_pos, |
4313 | enum isl_dim_type src_type, unsigned src_pos, unsigned n) |
4314 | { |
4315 | isl_basic_map *bmap = bset_to_bmap(bset); |
4316 | bmap = isl_basic_map_move_dims(bmap, dst_type, dst_pos, |
4317 | src_type, src_pos, n); |
4318 | return bset_from_bmap(bmap); |
4319 | } |
4320 | |
4321 | __isl_give isl_set *isl_set_move_dims(__isl_take isl_set *set, |
4322 | enum isl_dim_type dst_type, unsigned dst_pos, |
4323 | enum isl_dim_type src_type, unsigned src_pos, unsigned n) |
4324 | { |
4325 | if (!set) |
4326 | return NULL; |
4327 | isl_assert(set->ctx, dst_type != isl_dim_in, goto error); |
4328 | return set_from_map(isl_map_move_dims(map: set_to_map(set), |
4329 | dst_type, dst_pos, src_type, src_pos, n)); |
4330 | error: |
4331 | isl_set_free(set); |
4332 | return NULL; |
4333 | } |
4334 | |
4335 | __isl_give isl_map *isl_map_move_dims(__isl_take isl_map *map, |
4336 | enum isl_dim_type dst_type, unsigned dst_pos, |
4337 | enum isl_dim_type src_type, unsigned src_pos, unsigned n) |
4338 | { |
4339 | int i; |
4340 | isl_space *space; |
4341 | |
4342 | if (n == 0) { |
4343 | map = isl_map_reset(map, type: src_type); |
4344 | map = isl_map_reset(map, type: dst_type); |
4345 | return map; |
4346 | } |
4347 | |
4348 | if (isl_map_check_range(obj: map, type: src_type, first: src_pos, n)) |
4349 | return isl_map_free(map); |
4350 | |
4351 | if (dst_type == src_type && dst_pos == src_pos) |
4352 | return map; |
4353 | |
4354 | isl_assert(map->ctx, dst_type != src_type, goto error); |
4355 | |
4356 | map = isl_map_cow(map); |
4357 | if (!map) |
4358 | return NULL; |
4359 | |
4360 | for (i = 0; i < map->n; ++i) { |
4361 | map->p[i] = isl_basic_map_move_dims(bmap: map->p[i], |
4362 | dst_type, dst_pos, |
4363 | src_type, src_pos, n); |
4364 | if (!map->p[i]) |
4365 | goto error; |
4366 | } |
4367 | |
4368 | space = isl_map_take_space(map); |
4369 | space = isl_space_move_dims(space, dst_type, dst_pos, |
4370 | src_type, src_pos, n); |
4371 | map = isl_map_restore_space(map, space); |
4372 | |
4373 | return map; |
4374 | error: |
4375 | isl_map_free(map); |
4376 | return NULL; |
4377 | } |
4378 | |
4379 | /* Move the specified dimensions to the last columns right before |
4380 | * the divs. Don't change the dimension specification of bmap. |
4381 | * That's the responsibility of the caller. |
4382 | */ |
4383 | static __isl_give isl_basic_map *move_last(__isl_take isl_basic_map *bmap, |
4384 | enum isl_dim_type type, unsigned first, unsigned n) |
4385 | { |
4386 | isl_space *space; |
4387 | struct isl_dim_map *dim_map; |
4388 | struct isl_basic_map *res; |
4389 | enum isl_dim_type t; |
4390 | isl_size total; |
4391 | unsigned off; |
4392 | |
4393 | if (!bmap) |
4394 | return NULL; |
4395 | if (isl_basic_map_offset(bmap, type) + first + n == |
4396 | isl_basic_map_offset(bmap, type: isl_dim_div)) |
4397 | return bmap; |
4398 | |
4399 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
4400 | if (total < 0) |
4401 | return isl_basic_map_free(bmap); |
4402 | dim_map = isl_dim_map_alloc(ctx: bmap->ctx, len: total); |
4403 | |
4404 | off = 0; |
4405 | space = isl_basic_map_peek_space(bmap); |
4406 | for (t = isl_dim_param; t <= isl_dim_out; ++t) { |
4407 | isl_size size = isl_space_dim(space, type: t); |
4408 | if (size < 0) |
4409 | dim_map = isl_dim_map_free(dim_map); |
4410 | if (t == type) { |
4411 | isl_dim_map_dim_range(dim_map, space, type: t, |
4412 | first: 0, n: first, dst_pos: off); |
4413 | off += first; |
4414 | isl_dim_map_dim_range(dim_map, space, type: t, |
4415 | first, n, dst_pos: total - bmap->n_div - n); |
4416 | isl_dim_map_dim_range(dim_map, space, type: t, |
4417 | first: first + n, n: size - (first + n), dst_pos: off); |
4418 | off += size - (first + n); |
4419 | } else { |
4420 | isl_dim_map_dim(dim_map, space, type: t, dst_pos: off); |
4421 | off += size; |
4422 | } |
4423 | } |
4424 | isl_dim_map_div(dim_map, bmap, dst_pos: off + n); |
4425 | |
4426 | res = isl_basic_map_alloc_space(space: isl_basic_map_get_space(bmap), |
4427 | extra: bmap->n_div, n_eq: bmap->n_eq, n_ineq: bmap->n_ineq); |
4428 | res = isl_basic_map_add_constraints_dim_map(dst: res, src: bmap, dim_map); |
4429 | return res; |
4430 | } |
4431 | |
4432 | /* Insert "n" rows in the divs of "bmap". |
4433 | * |
4434 | * The number of columns is not changed, which means that the last |
4435 | * dimensions of "bmap" are being reintepreted as the new divs. |
4436 | * The space of "bmap" is not adjusted, however, which means |
4437 | * that "bmap" is left in an inconsistent state. Removing "n" dimensions |
4438 | * from the space of "bmap" is the responsibility of the caller. |
4439 | */ |
4440 | static __isl_give isl_basic_map *insert_div_rows(__isl_take isl_basic_map *bmap, |
4441 | int n) |
4442 | { |
4443 | int i; |
4444 | size_t row_size; |
4445 | isl_int **new_div; |
4446 | isl_int *old; |
4447 | |
4448 | bmap = isl_basic_map_cow(bmap); |
4449 | if (!bmap) |
4450 | return NULL; |
4451 | |
4452 | row_size = isl_basic_map_offset(bmap, type: isl_dim_div) + bmap->extra; |
4453 | old = bmap->block2.data; |
4454 | bmap->block2 = isl_blk_extend(ctx: bmap->ctx, block: bmap->block2, |
4455 | new_n: (bmap->extra + n) * (1 + row_size)); |
4456 | if (!bmap->block2.data) |
4457 | return isl_basic_map_free(bmap); |
4458 | new_div = isl_alloc_array(bmap->ctx, isl_int *, bmap->extra + n); |
4459 | if (!new_div) |
4460 | return isl_basic_map_free(bmap); |
4461 | for (i = 0; i < n; ++i) { |
4462 | new_div[i] = bmap->block2.data + |
4463 | (bmap->extra + i) * (1 + row_size); |
4464 | isl_seq_clr(p: new_div[i], len: 1 + row_size); |
4465 | } |
4466 | for (i = 0; i < bmap->extra; ++i) |
4467 | new_div[n + i] = bmap->block2.data + (bmap->div[i] - old); |
4468 | free(ptr: bmap->div); |
4469 | bmap->div = new_div; |
4470 | bmap->n_div += n; |
4471 | bmap->extra += n; |
4472 | |
4473 | return bmap; |
4474 | } |
4475 | |
4476 | /* Drop constraints from "bmap" that only involve the variables |
4477 | * of "type" in the range [first, first + n] that are not related |
4478 | * to any of the variables outside that interval. |
4479 | * These constraints cannot influence the values for the variables |
4480 | * outside the interval, except in case they cause "bmap" to be empty. |
4481 | * Only drop the constraints if "bmap" is known to be non-empty. |
4482 | */ |
4483 | static __isl_give isl_basic_map *drop_irrelevant_constraints( |
4484 | __isl_take isl_basic_map *bmap, enum isl_dim_type type, |
4485 | unsigned first, unsigned n) |
4486 | { |
4487 | int i; |
4488 | int *groups; |
4489 | isl_size dim, n_div; |
4490 | isl_bool non_empty; |
4491 | |
4492 | non_empty = isl_basic_map_plain_is_non_empty(bmap); |
4493 | if (non_empty < 0) |
4494 | return isl_basic_map_free(bmap); |
4495 | if (!non_empty) |
4496 | return bmap; |
4497 | |
4498 | dim = isl_basic_map_dim(bmap, type: isl_dim_all); |
4499 | n_div = isl_basic_map_dim(bmap, type: isl_dim_div); |
4500 | if (dim < 0 || n_div < 0) |
4501 | return isl_basic_map_free(bmap); |
4502 | groups = isl_calloc_array(isl_basic_map_get_ctx(bmap), int, dim); |
4503 | if (!groups) |
4504 | return isl_basic_map_free(bmap); |
4505 | first += isl_basic_map_offset(bmap, type) - 1; |
4506 | for (i = 0; i < first; ++i) |
4507 | groups[i] = -1; |
4508 | for (i = first + n; i < dim - n_div; ++i) |
4509 | groups[i] = -1; |
4510 | |
4511 | bmap = isl_basic_map_drop_unrelated_constraints(bmap, group: groups); |
4512 | |
4513 | return bmap; |
4514 | } |
4515 | |
4516 | /* Turn the n dimensions of type type, starting at first |
4517 | * into existentially quantified variables. |
4518 | * |
4519 | * If a subset of the projected out variables are unrelated |
4520 | * to any of the variables that remain, then the constraints |
4521 | * involving this subset are simply dropped first. |
4522 | */ |
4523 | __isl_give isl_basic_map *isl_basic_map_project_out( |
4524 | __isl_take isl_basic_map *bmap, |
4525 | enum isl_dim_type type, unsigned first, unsigned n) |
4526 | { |
4527 | isl_bool empty; |
4528 | isl_space *space; |
4529 | |
4530 | if (n == 0) |
4531 | return basic_map_space_reset(bmap, type); |
4532 | if (type == isl_dim_div) |
4533 | isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, |
4534 | "cannot project out existentially quantified variables" , |
4535 | return isl_basic_map_free(bmap)); |
4536 | |
4537 | empty = isl_basic_map_plain_is_empty(bmap); |
4538 | if (empty < 0) |
4539 | return isl_basic_map_free(bmap); |
4540 | if (empty) |
4541 | bmap = isl_basic_map_set_to_empty(bmap); |
4542 | |
4543 | bmap = drop_irrelevant_constraints(bmap, type, first, n); |
4544 | if (!bmap) |
4545 | return NULL; |
4546 | |
4547 | if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) |
4548 | return isl_basic_map_remove_dims(bmap, type, first, n); |
4549 | |
4550 | if (isl_basic_map_check_range(obj: bmap, type, first, n) < 0) |
4551 | return isl_basic_map_free(bmap); |
4552 | |
4553 | bmap = move_last(bmap, type, first, n); |
4554 | bmap = isl_basic_map_cow(bmap); |
4555 | bmap = insert_div_rows(bmap, n); |
4556 | |
4557 | space = isl_basic_map_take_space(bmap); |
4558 | space = isl_space_drop_dims(space, type, first, num: n); |
4559 | bmap = isl_basic_map_restore_space(bmap, space); |
4560 | bmap = isl_basic_map_simplify(bmap); |
4561 | bmap = isl_basic_map_drop_redundant_divs(bmap); |
4562 | return isl_basic_map_finalize(bmap); |
4563 | } |
4564 | |
4565 | /* Turn the n dimensions of type type, starting at first |
4566 | * into existentially quantified variables. |
4567 | */ |
4568 | __isl_give isl_basic_set *isl_basic_set_project_out( |
4569 | __isl_take isl_basic_set *bset, enum isl_dim_type type, |
4570 | unsigned first, unsigned n) |
4571 | { |
4572 | return bset_from_bmap(bmap: isl_basic_map_project_out(bmap: bset_to_bmap(bset), |
4573 | type, first, n)); |
4574 | } |
4575 | |
4576 | /* Turn the n dimensions of type type, starting at first |
4577 | * into existentially quantified variables. |
4578 | */ |
4579 | __isl_give isl_map *isl_map_project_out(__isl_take isl_map *map, |
4580 | enum isl_dim_type type, unsigned first, unsigned n) |
4581 | { |
4582 | int i; |
4583 | isl_space *space; |
4584 | |
4585 | if (n == 0) |
4586 | return map_space_reset(map, type); |
4587 | |
4588 | if (isl_map_check_range(obj: map, type, first, n) < 0) |
4589 | return isl_map_free(map); |
4590 | |
4591 | map = isl_map_cow(map); |
4592 | if (!map) |
4593 | return NULL; |
4594 | |
4595 | for (i = 0; i < map->n; ++i) { |
4596 | map->p[i] = isl_basic_map_project_out(bmap: map->p[i], type, first, n); |
4597 | if (!map->p[i]) |
4598 | goto error; |
4599 | } |
4600 | |
4601 | if (map->n > 1) |
4602 | ISL_F_CLR(map, ISL_MAP_DISJOINT); |
4603 | map = isl_map_unmark_normalized(map); |
4604 | |
4605 | space = isl_map_take_space(map); |
4606 | space = isl_space_drop_dims(space, type, first, num: n); |
4607 | map = isl_map_restore_space(map, space); |
4608 | |
4609 | return map; |
4610 | error: |
4611 | isl_map_free(map); |
4612 | return NULL; |
4613 | } |
4614 | |
4615 | #undef TYPE |
4616 | #define TYPE isl_map |
4617 | #include "isl_project_out_all_params_templ.c" |
4618 | #include "isl_project_out_param_templ.c" |
4619 | |
4620 | /* Turn all the dimensions of type "type", except the "n" starting at "first" |
4621 | * into existentially quantified variables. |
4622 | */ |
4623 | __isl_give isl_map *isl_map_project_onto(__isl_take isl_map *map, |
4624 | enum isl_dim_type type, unsigned first, unsigned n) |
4625 | { |
4626 | isl_size dim; |
4627 | |
4628 | dim = isl_map_dim(map, type); |
4629 | if (isl_map_check_range(obj: map, type, first, n) < 0 || dim < 0) |
4630 | return isl_map_free(map); |
4631 | map = isl_map_project_out(map, type, first: first + n, n: dim - (first + n)); |
4632 | map = isl_map_project_out(map, type, first: 0, n: first); |
4633 | return map; |
4634 | } |
4635 | |
4636 | /* Turn the n dimensions of type type, starting at first |
4637 | * into existentially quantified variables. |
4638 | */ |
4639 | __isl_give isl_set *isl_set_project_out(__isl_take isl_set *set, |
4640 | enum isl_dim_type type, unsigned first, unsigned n) |
4641 | { |
4642 | return set_from_map(isl_map_project_out(map: set_to_map(set), |
4643 | type, first, n)); |
4644 | } |
4645 | |
4646 | /* If "set" involves a parameter with identifier "id", |
4647 | * then turn it into an existentially quantified variable. |
4648 | */ |
4649 | __isl_give isl_set *isl_set_project_out_param_id(__isl_take isl_set *set, |
4650 | __isl_take isl_id *id) |
4651 | { |
4652 | return set_from_map(isl_map_project_out_param_id(obj: set_to_map(set), id)); |
4653 | } |
4654 | |
4655 | /* If "set" involves any of the parameters with identifiers in "list", |
4656 | * then turn them into existentially quantified variables. |
4657 | */ |
4658 | __isl_give isl_set *isl_set_project_out_param_id_list(__isl_take isl_set *set, |
4659 | __isl_take isl_id_list *list) |
4660 | { |
4661 | isl_map *map; |
4662 | |
4663 | map = set_to_map(set); |
4664 | map = isl_map_project_out_param_id_list(obj: map, list); |
4665 | return set_from_map(map); |
4666 | } |
4667 | |
4668 | /* Project out all parameters from "set" by existentially quantifying |
4669 | * over them. |
4670 | */ |
4671 | __isl_give isl_set *isl_set_project_out_all_params(__isl_take isl_set *set) |
4672 | { |
4673 | return set_from_map(isl_map_project_out_all_params(obj: set_to_map(set))); |
4674 | } |
4675 | |
4676 | /* Return a map that projects the elements in "set" onto their |
4677 | * "n" set dimensions starting at "first". |
4678 | * "type" should be equal to isl_dim_set. |
4679 | */ |
4680 | __isl_give isl_map *isl_set_project_onto_map(__isl_take isl_set *set, |
4681 | enum isl_dim_type type, unsigned first, unsigned n) |
4682 | { |
4683 | int i; |
4684 | isl_map *map; |
4685 | |
4686 | if (type != isl_dim_set) |
4687 | isl_die(isl_set_get_ctx(set), isl_error_invalid, |
4688 | "only set dimensions can be projected out" , goto error); |
4689 | if (isl_set_check_range(set, type, first, n) < 0) |
4690 | return isl_set_free(set); |
4691 | |
4692 | map = isl_map_from_domain(set); |
4693 | map = isl_map_add_dims(map, type: isl_dim_out, n); |
4694 | for (i = 0; i < n; ++i) |
4695 | map = isl_map_equate(map, type1: isl_dim_in, pos1: first + i, |
4696 | type2: isl_dim_out, pos2: i); |
4697 | return map; |
4698 | error: |
4699 | isl_set_free(set); |
4700 | return NULL; |
4701 | } |
4702 | |
4703 | static __isl_give isl_basic_map *add_divs(__isl_take isl_basic_map *bmap, |
4704 | unsigned n) |
4705 | { |
4706 | int i, j; |
4707 | isl_size total; |
4708 | |
4709 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
4710 | if (total < 0) |
4711 | return isl_basic_map_free(bmap); |
4712 | for (i = 0; i < n; ++i) { |
4713 | j = isl_basic_map_alloc_div(bmap); |
4714 | if (j < 0) |
4715 | goto error; |
4716 | isl_seq_clr(p: bmap->div[j], len: 1 + 1 + total); |
4717 | } |
4718 | return bmap; |
4719 | error: |
4720 | isl_basic_map_free(bmap); |
4721 | return NULL; |
4722 | } |
4723 | |
4724 | /* Does "bmap2" apply to the range of "bmap1" (ignoring parameters)? |
4725 | */ |
4726 | isl_bool isl_basic_map_applies_range(__isl_keep isl_basic_map *bmap1, |
4727 | __isl_keep isl_basic_map *bmap2) |
4728 | { |
4729 | isl_space *space1, *space2; |
4730 | |
4731 | space1 = isl_basic_map_peek_space(bmap: bmap1); |
4732 | space2 = isl_basic_map_peek_space(bmap: bmap2); |
4733 | return isl_space_tuple_is_equal(space1, type1: isl_dim_out, |
4734 | space2, type2: isl_dim_in); |
4735 | } |
4736 | |
4737 | /* Check that "bmap2" applies to the range of "bmap1" (ignoring parameters). |
4738 | */ |
4739 | static isl_stat isl_basic_map_check_applies_range( |
4740 | __isl_keep isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2) |
4741 | { |
4742 | isl_bool equal; |
4743 | |
4744 | equal = isl_basic_map_applies_range(bmap1, bmap2); |
4745 | if (equal < 0) |
4746 | return isl_stat_error; |
4747 | if (!equal) |
4748 | isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid, |
4749 | "spaces don't match" , return isl_stat_error); |
4750 | return isl_stat_ok; |
4751 | } |
4752 | |
4753 | __isl_give isl_basic_map *isl_basic_map_apply_range( |
4754 | __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) |
4755 | { |
4756 | isl_space *space_result = NULL; |
4757 | struct isl_basic_map *bmap; |
4758 | isl_size n_in, n_out, n, nparam; |
4759 | unsigned total, pos; |
4760 | struct isl_dim_map *dim_map1, *dim_map2; |
4761 | |
4762 | if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0) |
4763 | goto error; |
4764 | if (isl_basic_map_check_applies_range(bmap1, bmap2) < 0) |
4765 | goto error; |
4766 | |
4767 | n_in = isl_basic_map_dim(bmap: bmap1, type: isl_dim_in); |
4768 | n_out = isl_basic_map_dim(bmap: bmap2, type: isl_dim_out); |
4769 | n = isl_basic_map_dim(bmap: bmap1, type: isl_dim_out); |
4770 | nparam = isl_basic_map_dim(bmap: bmap1, type: isl_dim_param); |
4771 | if (n_in < 0 || n_out < 0 || n < 0 || nparam < 0) |
4772 | goto error; |
4773 | |
4774 | space_result = isl_space_join(left: isl_basic_map_get_space(bmap: bmap1), |
4775 | right: isl_basic_map_get_space(bmap: bmap2)); |
4776 | |
4777 | total = nparam + n_in + n_out + bmap1->n_div + bmap2->n_div + n; |
4778 | dim_map1 = isl_dim_map_alloc(ctx: bmap1->ctx, len: total); |
4779 | dim_map2 = isl_dim_map_alloc(ctx: bmap1->ctx, len: total); |
4780 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_param, dst_pos: pos = 0); |
4781 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_param, dst_pos: pos = 0); |
4782 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_in, dst_pos: pos += nparam); |
4783 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_out, dst_pos: pos += n_in); |
4784 | isl_dim_map_div(dim_map: dim_map1, bmap: bmap1, dst_pos: pos += n_out); |
4785 | isl_dim_map_div(dim_map: dim_map2, bmap: bmap2, dst_pos: pos += bmap1->n_div); |
4786 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_out, dst_pos: pos += bmap2->n_div); |
4787 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_in, dst_pos: pos); |
4788 | |
4789 | bmap = isl_basic_map_alloc_space(space: space_result, |
4790 | extra: bmap1->n_div + bmap2->n_div + n, |
4791 | n_eq: bmap1->n_eq + bmap2->n_eq, |
4792 | n_ineq: bmap1->n_ineq + bmap2->n_ineq); |
4793 | bmap = isl_basic_map_add_constraints_dim_map(dst: bmap, src: bmap1, dim_map: dim_map1); |
4794 | bmap = isl_basic_map_add_constraints_dim_map(dst: bmap, src: bmap2, dim_map: dim_map2); |
4795 | bmap = add_divs(bmap, n); |
4796 | bmap = isl_basic_map_simplify(bmap); |
4797 | bmap = isl_basic_map_drop_redundant_divs(bmap); |
4798 | return isl_basic_map_finalize(bmap); |
4799 | error: |
4800 | isl_basic_map_free(bmap: bmap1); |
4801 | isl_basic_map_free(bmap: bmap2); |
4802 | return NULL; |
4803 | } |
4804 | |
4805 | __isl_give isl_basic_set *isl_basic_set_apply(__isl_take isl_basic_set *bset, |
4806 | __isl_take isl_basic_map *bmap) |
4807 | { |
4808 | if (isl_basic_map_check_compatible_domain(bmap, bset) < 0) |
4809 | goto error; |
4810 | |
4811 | return bset_from_bmap(bmap: isl_basic_map_apply_range(bmap1: bset_to_bmap(bset), |
4812 | bmap2: bmap)); |
4813 | error: |
4814 | isl_basic_set_free(bset); |
4815 | isl_basic_map_free(bmap); |
4816 | return NULL; |
4817 | } |
4818 | |
4819 | __isl_give isl_basic_map *isl_basic_map_apply_domain( |
4820 | __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) |
4821 | { |
4822 | if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0) |
4823 | goto error; |
4824 | if (!isl_space_tuple_is_equal(space1: bmap1->dim, type1: isl_dim_in, |
4825 | space2: bmap2->dim, type2: isl_dim_in)) |
4826 | isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid, |
4827 | "spaces don't match" , goto error); |
4828 | |
4829 | bmap1 = isl_basic_map_reverse(bmap: bmap1); |
4830 | bmap1 = isl_basic_map_apply_range(bmap1, bmap2); |
4831 | return isl_basic_map_reverse(bmap: bmap1); |
4832 | error: |
4833 | isl_basic_map_free(bmap: bmap1); |
4834 | isl_basic_map_free(bmap: bmap2); |
4835 | return NULL; |
4836 | } |
4837 | |
4838 | /* Given two basic maps A -> f(A) and B -> g(B), construct a basic map |
4839 | * A \cap B -> f(A) + f(B) |
4840 | */ |
4841 | __isl_give isl_basic_map *isl_basic_map_sum(__isl_take isl_basic_map *bmap1, |
4842 | __isl_take isl_basic_map *bmap2) |
4843 | { |
4844 | isl_size n_in, n_out, nparam; |
4845 | unsigned total, pos; |
4846 | struct isl_basic_map *bmap = NULL; |
4847 | struct isl_dim_map *dim_map1, *dim_map2; |
4848 | int i; |
4849 | |
4850 | if (isl_basic_map_check_equal_space(bmap1, bmap2) < 0) |
4851 | goto error; |
4852 | |
4853 | nparam = isl_basic_map_dim(bmap: bmap1, type: isl_dim_param); |
4854 | n_in = isl_basic_map_dim(bmap: bmap1, type: isl_dim_in); |
4855 | n_out = isl_basic_map_dim(bmap: bmap1, type: isl_dim_out); |
4856 | if (nparam < 0 || n_in < 0 || n_out < 0) |
4857 | goto error; |
4858 | |
4859 | total = nparam + n_in + n_out + bmap1->n_div + bmap2->n_div + 2 * n_out; |
4860 | dim_map1 = isl_dim_map_alloc(ctx: bmap1->ctx, len: total); |
4861 | dim_map2 = isl_dim_map_alloc(ctx: bmap2->ctx, len: total); |
4862 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_param, dst_pos: pos = 0); |
4863 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_param, dst_pos: pos); |
4864 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_in, dst_pos: pos += nparam); |
4865 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_in, dst_pos: pos); |
4866 | isl_dim_map_div(dim_map: dim_map1, bmap: bmap1, dst_pos: pos += n_in + n_out); |
4867 | isl_dim_map_div(dim_map: dim_map2, bmap: bmap2, dst_pos: pos += bmap1->n_div); |
4868 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_out, dst_pos: pos += bmap2->n_div); |
4869 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_out, dst_pos: pos += n_out); |
4870 | |
4871 | bmap = isl_basic_map_alloc_space(space: isl_space_copy(space: bmap1->dim), |
4872 | extra: bmap1->n_div + bmap2->n_div + 2 * n_out, |
4873 | n_eq: bmap1->n_eq + bmap2->n_eq + n_out, |
4874 | n_ineq: bmap1->n_ineq + bmap2->n_ineq); |
4875 | for (i = 0; i < n_out; ++i) { |
4876 | int j = isl_basic_map_alloc_equality(bmap); |
4877 | if (j < 0) |
4878 | goto error; |
4879 | isl_seq_clr(p: bmap->eq[j], len: 1+total); |
4880 | isl_int_set_si(bmap->eq[j][1+nparam+n_in+i], -1); |
4881 | isl_int_set_si(bmap->eq[j][1+pos+i], 1); |
4882 | isl_int_set_si(bmap->eq[j][1+pos-n_out+i], 1); |
4883 | } |
4884 | bmap = isl_basic_map_add_constraints_dim_map(dst: bmap, src: bmap1, dim_map: dim_map1); |
4885 | bmap = isl_basic_map_add_constraints_dim_map(dst: bmap, src: bmap2, dim_map: dim_map2); |
4886 | bmap = add_divs(bmap, n: 2 * n_out); |
4887 | |
4888 | bmap = isl_basic_map_simplify(bmap); |
4889 | return isl_basic_map_finalize(bmap); |
4890 | error: |
4891 | isl_basic_map_free(bmap); |
4892 | isl_basic_map_free(bmap: bmap1); |
4893 | isl_basic_map_free(bmap: bmap2); |
4894 | return NULL; |
4895 | } |
4896 | |
4897 | /* Given two maps A -> f(A) and B -> g(B), construct a map |
4898 | * A \cap B -> f(A) + f(B) |
4899 | */ |
4900 | __isl_give isl_map *isl_map_sum(__isl_take isl_map *map1, |
4901 | __isl_take isl_map *map2) |
4902 | { |
4903 | struct isl_map *result; |
4904 | int i, j; |
4905 | |
4906 | if (isl_map_check_equal_space(map1, map2) < 0) |
4907 | goto error; |
4908 | |
4909 | result = isl_map_alloc_space(space: isl_space_copy(space: map1->dim), |
4910 | n: map1->n * map2->n, flags: 0); |
4911 | if (!result) |
4912 | goto error; |
4913 | for (i = 0; i < map1->n; ++i) |
4914 | for (j = 0; j < map2->n; ++j) { |
4915 | struct isl_basic_map *part; |
4916 | part = isl_basic_map_sum( |
4917 | bmap1: isl_basic_map_copy(bmap: map1->p[i]), |
4918 | bmap2: isl_basic_map_copy(bmap: map2->p[j])); |
4919 | if (isl_basic_map_is_empty(bmap: part)) |
4920 | isl_basic_map_free(bmap: part); |
4921 | else |
4922 | result = isl_map_add_basic_map(map: result, bmap: part); |
4923 | if (!result) |
4924 | goto error; |
4925 | } |
4926 | isl_map_free(map: map1); |
4927 | isl_map_free(map: map2); |
4928 | return result; |
4929 | error: |
4930 | isl_map_free(map: map1); |
4931 | isl_map_free(map: map2); |
4932 | return NULL; |
4933 | } |
4934 | |
4935 | __isl_give isl_set *isl_set_sum(__isl_take isl_set *set1, |
4936 | __isl_take isl_set *set2) |
4937 | { |
4938 | return set_from_map(isl_map_sum(map1: set_to_map(set1), map2: set_to_map(set2))); |
4939 | } |
4940 | |
4941 | /* Given a basic map A -> f(A), construct A -> -f(A). |
4942 | */ |
4943 | __isl_give isl_basic_map *isl_basic_map_neg(__isl_take isl_basic_map *bmap) |
4944 | { |
4945 | int i, j; |
4946 | unsigned off; |
4947 | isl_size n; |
4948 | |
4949 | bmap = isl_basic_map_cow(bmap); |
4950 | n = isl_basic_map_dim(bmap, type: isl_dim_out); |
4951 | if (n < 0) |
4952 | return isl_basic_map_free(bmap); |
4953 | |
4954 | off = isl_basic_map_offset(bmap, type: isl_dim_out); |
4955 | for (i = 0; i < bmap->n_eq; ++i) |
4956 | for (j = 0; j < n; ++j) |
4957 | isl_int_neg(bmap->eq[i][off+j], bmap->eq[i][off+j]); |
4958 | for (i = 0; i < bmap->n_ineq; ++i) |
4959 | for (j = 0; j < n; ++j) |
4960 | isl_int_neg(bmap->ineq[i][off+j], bmap->ineq[i][off+j]); |
4961 | for (i = 0; i < bmap->n_div; ++i) |
4962 | for (j = 0; j < n; ++j) |
4963 | isl_int_neg(bmap->div[i][1+off+j], bmap->div[i][1+off+j]); |
4964 | bmap = isl_basic_map_gauss(bmap, NULL); |
4965 | return isl_basic_map_finalize(bmap); |
4966 | } |
4967 | |
4968 | __isl_give isl_basic_set *isl_basic_set_neg(__isl_take isl_basic_set *bset) |
4969 | { |
4970 | return isl_basic_map_neg(bmap: bset); |
4971 | } |
4972 | |
4973 | /* Given a map A -> f(A), construct A -> -f(A). |
4974 | */ |
4975 | __isl_give isl_map *isl_map_neg(__isl_take isl_map *map) |
4976 | { |
4977 | int i; |
4978 | |
4979 | map = isl_map_cow(map); |
4980 | if (!map) |
4981 | return NULL; |
4982 | |
4983 | for (i = 0; i < map->n; ++i) { |
4984 | map->p[i] = isl_basic_map_neg(bmap: map->p[i]); |
4985 | if (!map->p[i]) |
4986 | goto error; |
4987 | } |
4988 | |
4989 | return map; |
4990 | error: |
4991 | isl_map_free(map); |
4992 | return NULL; |
4993 | } |
4994 | |
4995 | __isl_give isl_set *isl_set_neg(__isl_take isl_set *set) |
4996 | { |
4997 | return set_from_map(isl_map_neg(map: set_to_map(set))); |
4998 | } |
4999 | |
5000 | /* Given a basic map A -> f(A) and an integer d, construct a basic map |
5001 | * A -> floor(f(A)/d). |
5002 | */ |
5003 | __isl_give isl_basic_map *isl_basic_map_floordiv(__isl_take isl_basic_map *bmap, |
5004 | isl_int d) |
5005 | { |
5006 | isl_size n_in, n_out, nparam; |
5007 | unsigned total, pos; |
5008 | struct isl_basic_map *result = NULL; |
5009 | struct isl_dim_map *dim_map; |
5010 | int i; |
5011 | |
5012 | nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
5013 | n_in = isl_basic_map_dim(bmap, type: isl_dim_in); |
5014 | n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
5015 | if (nparam < 0 || n_in < 0 || n_out < 0) |
5016 | return isl_basic_map_free(bmap); |
5017 | |
5018 | total = nparam + n_in + n_out + bmap->n_div + n_out; |
5019 | dim_map = isl_dim_map_alloc(ctx: bmap->ctx, len: total); |
5020 | isl_dim_map_dim(dim_map, space: bmap->dim, type: isl_dim_param, dst_pos: pos = 0); |
5021 | isl_dim_map_dim(dim_map, space: bmap->dim, type: isl_dim_in, dst_pos: pos += nparam); |
5022 | isl_dim_map_div(dim_map, bmap, dst_pos: pos += n_in + n_out); |
5023 | isl_dim_map_dim(dim_map, space: bmap->dim, type: isl_dim_out, dst_pos: pos += bmap->n_div); |
5024 | |
5025 | result = isl_basic_map_alloc_space(space: isl_space_copy(space: bmap->dim), |
5026 | extra: bmap->n_div + n_out, |
5027 | n_eq: bmap->n_eq, n_ineq: bmap->n_ineq + 2 * n_out); |
5028 | result = isl_basic_map_add_constraints_dim_map(dst: result, src: bmap, dim_map); |
5029 | result = add_divs(bmap: result, n: n_out); |
5030 | for (i = 0; i < n_out; ++i) { |
5031 | int j; |
5032 | j = isl_basic_map_alloc_inequality(bmap: result); |
5033 | if (j < 0) |
5034 | goto error; |
5035 | isl_seq_clr(p: result->ineq[j], len: 1+total); |
5036 | isl_int_neg(result->ineq[j][1+nparam+n_in+i], d); |
5037 | isl_int_set_si(result->ineq[j][1+pos+i], 1); |
5038 | j = isl_basic_map_alloc_inequality(bmap: result); |
5039 | if (j < 0) |
5040 | goto error; |
5041 | isl_seq_clr(p: result->ineq[j], len: 1+total); |
5042 | isl_int_set(result->ineq[j][1+nparam+n_in+i], d); |
5043 | isl_int_set_si(result->ineq[j][1+pos+i], -1); |
5044 | isl_int_sub_ui(result->ineq[j][0], d, 1); |
5045 | } |
5046 | |
5047 | result = isl_basic_map_simplify(bmap: result); |
5048 | return isl_basic_map_finalize(bmap: result); |
5049 | error: |
5050 | isl_basic_map_free(bmap: result); |
5051 | return NULL; |
5052 | } |
5053 | |
5054 | /* Given a map A -> f(A) and an integer d, construct a map |
5055 | * A -> floor(f(A)/d). |
5056 | */ |
5057 | __isl_give isl_map *isl_map_floordiv(__isl_take isl_map *map, isl_int d) |
5058 | { |
5059 | int i; |
5060 | |
5061 | map = isl_map_cow(map); |
5062 | if (!map) |
5063 | return NULL; |
5064 | |
5065 | ISL_F_CLR(map, ISL_MAP_DISJOINT); |
5066 | for (i = 0; i < map->n; ++i) { |
5067 | map->p[i] = isl_basic_map_floordiv(bmap: map->p[i], d); |
5068 | if (!map->p[i]) |
5069 | goto error; |
5070 | } |
5071 | map = isl_map_unmark_normalized(map); |
5072 | |
5073 | return map; |
5074 | error: |
5075 | isl_map_free(map); |
5076 | return NULL; |
5077 | } |
5078 | |
5079 | /* Given a map A -> f(A) and an integer d, construct a map |
5080 | * A -> floor(f(A)/d). |
5081 | */ |
5082 | __isl_give isl_map *isl_map_floordiv_val(__isl_take isl_map *map, |
5083 | __isl_take isl_val *d) |
5084 | { |
5085 | if (!map || !d) |
5086 | goto error; |
5087 | if (!isl_val_is_int(v: d)) |
5088 | isl_die(isl_val_get_ctx(d), isl_error_invalid, |
5089 | "expecting integer denominator" , goto error); |
5090 | map = isl_map_floordiv(map, d: d->n); |
5091 | isl_val_free(v: d); |
5092 | return map; |
5093 | error: |
5094 | isl_map_free(map); |
5095 | isl_val_free(v: d); |
5096 | return NULL; |
5097 | } |
5098 | |
5099 | static __isl_give isl_basic_map *var_equal(__isl_take isl_basic_map *bmap, |
5100 | unsigned pos) |
5101 | { |
5102 | int i; |
5103 | isl_size nparam; |
5104 | isl_size n_in; |
5105 | isl_size total; |
5106 | |
5107 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
5108 | nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
5109 | n_in = isl_basic_map_dim(bmap, type: isl_dim_in); |
5110 | if (total < 0 || nparam < 0 || n_in < 0) |
5111 | return isl_basic_map_free(bmap); |
5112 | i = isl_basic_map_alloc_equality(bmap); |
5113 | if (i < 0) |
5114 | goto error; |
5115 | isl_seq_clr(p: bmap->eq[i], len: 1 + total); |
5116 | isl_int_set_si(bmap->eq[i][1+nparam+pos], -1); |
5117 | isl_int_set_si(bmap->eq[i][1+nparam+n_in+pos], 1); |
5118 | return isl_basic_map_finalize(bmap); |
5119 | error: |
5120 | isl_basic_map_free(bmap); |
5121 | return NULL; |
5122 | } |
5123 | |
5124 | /* Add a constraint to "bmap" expressing i_pos < o_pos |
5125 | */ |
5126 | static __isl_give isl_basic_map *var_less(__isl_take isl_basic_map *bmap, |
5127 | unsigned pos) |
5128 | { |
5129 | int i; |
5130 | isl_size nparam; |
5131 | isl_size n_in; |
5132 | isl_size total; |
5133 | |
5134 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
5135 | nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
5136 | n_in = isl_basic_map_dim(bmap, type: isl_dim_in); |
5137 | if (total < 0 || nparam < 0 || n_in < 0) |
5138 | return isl_basic_map_free(bmap); |
5139 | i = isl_basic_map_alloc_inequality(bmap); |
5140 | if (i < 0) |
5141 | goto error; |
5142 | isl_seq_clr(p: bmap->ineq[i], len: 1 + total); |
5143 | isl_int_set_si(bmap->ineq[i][0], -1); |
5144 | isl_int_set_si(bmap->ineq[i][1+nparam+pos], -1); |
5145 | isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], 1); |
5146 | return isl_basic_map_finalize(bmap); |
5147 | error: |
5148 | isl_basic_map_free(bmap); |
5149 | return NULL; |
5150 | } |
5151 | |
5152 | /* Add a constraint to "bmap" expressing i_pos <= o_pos |
5153 | */ |
5154 | static __isl_give isl_basic_map *var_less_or_equal( |
5155 | __isl_take isl_basic_map *bmap, unsigned pos) |
5156 | { |
5157 | int i; |
5158 | isl_size nparam; |
5159 | isl_size n_in; |
5160 | isl_size total; |
5161 | |
5162 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
5163 | nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
5164 | n_in = isl_basic_map_dim(bmap, type: isl_dim_in); |
5165 | if (total < 0 || nparam < 0 || n_in < 0) |
5166 | return isl_basic_map_free(bmap); |
5167 | i = isl_basic_map_alloc_inequality(bmap); |
5168 | if (i < 0) |
5169 | goto error; |
5170 | isl_seq_clr(p: bmap->ineq[i], len: 1 + total); |
5171 | isl_int_set_si(bmap->ineq[i][1+nparam+pos], -1); |
5172 | isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], 1); |
5173 | return isl_basic_map_finalize(bmap); |
5174 | error: |
5175 | isl_basic_map_free(bmap); |
5176 | return NULL; |
5177 | } |
5178 | |
5179 | /* Add a constraint to "bmap" expressing i_pos > o_pos |
5180 | */ |
5181 | static __isl_give isl_basic_map *var_more(__isl_take isl_basic_map *bmap, |
5182 | unsigned pos) |
5183 | { |
5184 | int i; |
5185 | isl_size nparam; |
5186 | isl_size n_in; |
5187 | isl_size total; |
5188 | |
5189 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
5190 | nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
5191 | n_in = isl_basic_map_dim(bmap, type: isl_dim_in); |
5192 | if (total < 0 || nparam < 0 || n_in < 0) |
5193 | return isl_basic_map_free(bmap); |
5194 | i = isl_basic_map_alloc_inequality(bmap); |
5195 | if (i < 0) |
5196 | goto error; |
5197 | isl_seq_clr(p: bmap->ineq[i], len: 1 + total); |
5198 | isl_int_set_si(bmap->ineq[i][0], -1); |
5199 | isl_int_set_si(bmap->ineq[i][1+nparam+pos], 1); |
5200 | isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], -1); |
5201 | return isl_basic_map_finalize(bmap); |
5202 | error: |
5203 | isl_basic_map_free(bmap); |
5204 | return NULL; |
5205 | } |
5206 | |
5207 | /* Add a constraint to "bmap" expressing i_pos >= o_pos |
5208 | */ |
5209 | static __isl_give isl_basic_map *var_more_or_equal( |
5210 | __isl_take isl_basic_map *bmap, unsigned pos) |
5211 | { |
5212 | int i; |
5213 | isl_size nparam; |
5214 | isl_size n_in; |
5215 | isl_size total; |
5216 | |
5217 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
5218 | nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
5219 | n_in = isl_basic_map_dim(bmap, type: isl_dim_in); |
5220 | if (total < 0 || nparam < 0 || n_in < 0) |
5221 | return isl_basic_map_free(bmap); |
5222 | i = isl_basic_map_alloc_inequality(bmap); |
5223 | if (i < 0) |
5224 | goto error; |
5225 | isl_seq_clr(p: bmap->ineq[i], len: 1 + total); |
5226 | isl_int_set_si(bmap->ineq[i][1+nparam+pos], 1); |
5227 | isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], -1); |
5228 | return isl_basic_map_finalize(bmap); |
5229 | error: |
5230 | isl_basic_map_free(bmap); |
5231 | return NULL; |
5232 | } |
5233 | |
5234 | __isl_give isl_basic_map *isl_basic_map_equal( |
5235 | __isl_take isl_space *space, unsigned n_equal) |
5236 | { |
5237 | int i; |
5238 | struct isl_basic_map *bmap; |
5239 | bmap = isl_basic_map_alloc_space(space, extra: 0, n_eq: n_equal, n_ineq: 0); |
5240 | if (!bmap) |
5241 | return NULL; |
5242 | for (i = 0; i < n_equal && bmap; ++i) |
5243 | bmap = var_equal(bmap, pos: i); |
5244 | return isl_basic_map_finalize(bmap); |
5245 | } |
5246 | |
5247 | /* Return a relation on of dimension "space" expressing i_[0..pos] << o_[0..pos] |
5248 | */ |
5249 | __isl_give isl_basic_map *isl_basic_map_less_at(__isl_take isl_space *space, |
5250 | unsigned pos) |
5251 | { |
5252 | int i; |
5253 | struct isl_basic_map *bmap; |
5254 | bmap = isl_basic_map_alloc_space(space, extra: 0, n_eq: pos, n_ineq: 1); |
5255 | if (!bmap) |
5256 | return NULL; |
5257 | for (i = 0; i < pos && bmap; ++i) |
5258 | bmap = var_equal(bmap, pos: i); |
5259 | if (bmap) |
5260 | bmap = var_less(bmap, pos); |
5261 | return isl_basic_map_finalize(bmap); |
5262 | } |
5263 | |
5264 | /* Return a relation on "space" expressing i_[0..pos] <<= o_[0..pos] |
5265 | */ |
5266 | __isl_give isl_basic_map *isl_basic_map_less_or_equal_at( |
5267 | __isl_take isl_space *space, unsigned pos) |
5268 | { |
5269 | int i; |
5270 | isl_basic_map *bmap; |
5271 | |
5272 | bmap = isl_basic_map_alloc_space(space, extra: 0, n_eq: pos, n_ineq: 1); |
5273 | for (i = 0; i < pos; ++i) |
5274 | bmap = var_equal(bmap, pos: i); |
5275 | bmap = var_less_or_equal(bmap, pos); |
5276 | return isl_basic_map_finalize(bmap); |
5277 | } |
5278 | |
5279 | /* Return a relation on "space" expressing i_pos > o_pos |
5280 | */ |
5281 | __isl_give isl_basic_map *isl_basic_map_more_at(__isl_take isl_space *space, |
5282 | unsigned pos) |
5283 | { |
5284 | int i; |
5285 | struct isl_basic_map *bmap; |
5286 | bmap = isl_basic_map_alloc_space(space, extra: 0, n_eq: pos, n_ineq: 1); |
5287 | if (!bmap) |
5288 | return NULL; |
5289 | for (i = 0; i < pos && bmap; ++i) |
5290 | bmap = var_equal(bmap, pos: i); |
5291 | if (bmap) |
5292 | bmap = var_more(bmap, pos); |
5293 | return isl_basic_map_finalize(bmap); |
5294 | } |
5295 | |
5296 | /* Return a relation on "space" expressing i_[0..pos] >>= o_[0..pos] |
5297 | */ |
5298 | __isl_give isl_basic_map *isl_basic_map_more_or_equal_at( |
5299 | __isl_take isl_space *space, unsigned pos) |
5300 | { |
5301 | int i; |
5302 | isl_basic_map *bmap; |
5303 | |
5304 | bmap = isl_basic_map_alloc_space(space, extra: 0, n_eq: pos, n_ineq: 1); |
5305 | for (i = 0; i < pos; ++i) |
5306 | bmap = var_equal(bmap, pos: i); |
5307 | bmap = var_more_or_equal(bmap, pos); |
5308 | return isl_basic_map_finalize(bmap); |
5309 | } |
5310 | |
5311 | static __isl_give isl_map *map_lex_lte_first(__isl_take isl_space *space, |
5312 | unsigned n, int equal) |
5313 | { |
5314 | struct isl_map *map; |
5315 | int i; |
5316 | |
5317 | if (n == 0 && equal) |
5318 | return isl_map_universe(space); |
5319 | |
5320 | map = isl_map_alloc_space(space: isl_space_copy(space), n, ISL_MAP_DISJOINT); |
5321 | |
5322 | for (i = 0; i + 1 < n; ++i) |
5323 | map = isl_map_add_basic_map(map, |
5324 | bmap: isl_basic_map_less_at(space: isl_space_copy(space), pos: i)); |
5325 | if (n > 0) { |
5326 | if (equal) |
5327 | map = isl_map_add_basic_map(map, |
5328 | bmap: isl_basic_map_less_or_equal_at(space, pos: n - 1)); |
5329 | else |
5330 | map = isl_map_add_basic_map(map, |
5331 | bmap: isl_basic_map_less_at(space, pos: n - 1)); |
5332 | } else |
5333 | isl_space_free(space); |
5334 | |
5335 | return map; |
5336 | } |
5337 | |
5338 | static __isl_give isl_map *map_lex_lte(__isl_take isl_space *space, int equal) |
5339 | { |
5340 | if (!space) |
5341 | return NULL; |
5342 | return map_lex_lte_first(space, n: space->n_out, equal); |
5343 | } |
5344 | |
5345 | __isl_give isl_map *isl_map_lex_lt_first(__isl_take isl_space *space, |
5346 | unsigned n) |
5347 | { |
5348 | return map_lex_lte_first(space, n, equal: 0); |
5349 | } |
5350 | |
5351 | __isl_give isl_map *isl_map_lex_le_first(__isl_take isl_space *space, |
5352 | unsigned n) |
5353 | { |
5354 | return map_lex_lte_first(space, n, equal: 1); |
5355 | } |
5356 | |
5357 | __isl_give isl_map *isl_map_lex_lt(__isl_take isl_space *set_space) |
5358 | { |
5359 | return map_lex_lte(space: isl_space_map_from_set(space: set_space), equal: 0); |
5360 | } |
5361 | |
5362 | __isl_give isl_map *isl_map_lex_le(__isl_take isl_space *set_space) |
5363 | { |
5364 | return map_lex_lte(space: isl_space_map_from_set(space: set_space), equal: 1); |
5365 | } |
5366 | |
5367 | static __isl_give isl_map *map_lex_gte_first(__isl_take isl_space *space, |
5368 | unsigned n, int equal) |
5369 | { |
5370 | struct isl_map *map; |
5371 | int i; |
5372 | |
5373 | if (n == 0 && equal) |
5374 | return isl_map_universe(space); |
5375 | |
5376 | map = isl_map_alloc_space(space: isl_space_copy(space), n, ISL_MAP_DISJOINT); |
5377 | |
5378 | for (i = 0; i + 1 < n; ++i) |
5379 | map = isl_map_add_basic_map(map, |
5380 | bmap: isl_basic_map_more_at(space: isl_space_copy(space), pos: i)); |
5381 | if (n > 0) { |
5382 | if (equal) |
5383 | map = isl_map_add_basic_map(map, |
5384 | bmap: isl_basic_map_more_or_equal_at(space, pos: n - 1)); |
5385 | else |
5386 | map = isl_map_add_basic_map(map, |
5387 | bmap: isl_basic_map_more_at(space, pos: n - 1)); |
5388 | } else |
5389 | isl_space_free(space); |
5390 | |
5391 | return map; |
5392 | } |
5393 | |
5394 | static __isl_give isl_map *map_lex_gte(__isl_take isl_space *space, int equal) |
5395 | { |
5396 | if (!space) |
5397 | return NULL; |
5398 | return map_lex_gte_first(space, n: space->n_out, equal); |
5399 | } |
5400 | |
5401 | __isl_give isl_map *isl_map_lex_gt_first(__isl_take isl_space *space, |
5402 | unsigned n) |
5403 | { |
5404 | return map_lex_gte_first(space, n, equal: 0); |
5405 | } |
5406 | |
5407 | __isl_give isl_map *isl_map_lex_ge_first(__isl_take isl_space *space, |
5408 | unsigned n) |
5409 | { |
5410 | return map_lex_gte_first(space, n, equal: 1); |
5411 | } |
5412 | |
5413 | __isl_give isl_map *isl_map_lex_gt(__isl_take isl_space *set_space) |
5414 | { |
5415 | return map_lex_gte(space: isl_space_map_from_set(space: set_space), equal: 0); |
5416 | } |
5417 | |
5418 | __isl_give isl_map *isl_map_lex_ge(__isl_take isl_space *set_space) |
5419 | { |
5420 | return map_lex_gte(space: isl_space_map_from_set(space: set_space), equal: 1); |
5421 | } |
5422 | |
5423 | __isl_give isl_map *isl_set_lex_le_set(__isl_take isl_set *set1, |
5424 | __isl_take isl_set *set2) |
5425 | { |
5426 | isl_map *map; |
5427 | map = isl_map_lex_le(set_space: isl_set_get_space(set: set1)); |
5428 | map = isl_map_intersect_domain(map, set: set1); |
5429 | map = isl_map_intersect_range(map, set: set2); |
5430 | return map; |
5431 | } |
5432 | |
5433 | __isl_give isl_map *isl_set_lex_lt_set(__isl_take isl_set *set1, |
5434 | __isl_take isl_set *set2) |
5435 | { |
5436 | isl_map *map; |
5437 | map = isl_map_lex_lt(set_space: isl_set_get_space(set: set1)); |
5438 | map = isl_map_intersect_domain(map, set: set1); |
5439 | map = isl_map_intersect_range(map, set: set2); |
5440 | return map; |
5441 | } |
5442 | |
5443 | __isl_give isl_map *isl_set_lex_ge_set(__isl_take isl_set *set1, |
5444 | __isl_take isl_set *set2) |
5445 | { |
5446 | isl_map *map; |
5447 | map = isl_map_lex_ge(set_space: isl_set_get_space(set: set1)); |
5448 | map = isl_map_intersect_domain(map, set: set1); |
5449 | map = isl_map_intersect_range(map, set: set2); |
5450 | return map; |
5451 | } |
5452 | |
5453 | __isl_give isl_map *isl_set_lex_gt_set(__isl_take isl_set *set1, |
5454 | __isl_take isl_set *set2) |
5455 | { |
5456 | isl_map *map; |
5457 | map = isl_map_lex_gt(set_space: isl_set_get_space(set: set1)); |
5458 | map = isl_map_intersect_domain(map, set: set1); |
5459 | map = isl_map_intersect_range(map, set: set2); |
5460 | return map; |
5461 | } |
5462 | |
5463 | __isl_give isl_map *isl_map_lex_le_map(__isl_take isl_map *map1, |
5464 | __isl_take isl_map *map2) |
5465 | { |
5466 | isl_map *map; |
5467 | map = isl_map_lex_le(set_space: isl_space_range(space: isl_map_get_space(map: map1))); |
5468 | map = isl_map_apply_domain(map1: map, map2: isl_map_reverse(map: map1)); |
5469 | map = isl_map_apply_range(map1: map, map2: isl_map_reverse(map: map2)); |
5470 | return map; |
5471 | } |
5472 | |
5473 | __isl_give isl_map *isl_map_lex_lt_map(__isl_take isl_map *map1, |
5474 | __isl_take isl_map *map2) |
5475 | { |
5476 | isl_map *map; |
5477 | map = isl_map_lex_lt(set_space: isl_space_range(space: isl_map_get_space(map: map1))); |
5478 | map = isl_map_apply_domain(map1: map, map2: isl_map_reverse(map: map1)); |
5479 | map = isl_map_apply_range(map1: map, map2: isl_map_reverse(map: map2)); |
5480 | return map; |
5481 | } |
5482 | |
5483 | __isl_give isl_map *isl_map_lex_ge_map(__isl_take isl_map *map1, |
5484 | __isl_take isl_map *map2) |
5485 | { |
5486 | isl_map *map; |
5487 | map = isl_map_lex_ge(set_space: isl_space_range(space: isl_map_get_space(map: map1))); |
5488 | map = isl_map_apply_domain(map1: map, map2: isl_map_reverse(map: map1)); |
5489 | map = isl_map_apply_range(map1: map, map2: isl_map_reverse(map: map2)); |
5490 | return map; |
5491 | } |
5492 | |
5493 | __isl_give isl_map *isl_map_lex_gt_map(__isl_take isl_map *map1, |
5494 | __isl_take isl_map *map2) |
5495 | { |
5496 | isl_map *map; |
5497 | map = isl_map_lex_gt(set_space: isl_space_range(space: isl_map_get_space(map: map1))); |
5498 | map = isl_map_apply_domain(map1: map, map2: isl_map_reverse(map: map1)); |
5499 | map = isl_map_apply_range(map1: map, map2: isl_map_reverse(map: map2)); |
5500 | return map; |
5501 | } |
5502 | |
5503 | /* For the div d = floor(f/m) at position "div", add the constraint |
5504 | * |
5505 | * f - m d >= 0 |
5506 | */ |
5507 | static __isl_give isl_basic_map *add_upper_div_constraint( |
5508 | __isl_take isl_basic_map *bmap, unsigned div) |
5509 | { |
5510 | int i; |
5511 | isl_size v_div = isl_basic_map_var_offset(bmap, type: isl_dim_div); |
5512 | isl_size n_div; |
5513 | unsigned pos; |
5514 | |
5515 | n_div = isl_basic_map_dim(bmap, type: isl_dim_div); |
5516 | if (v_div < 0 || n_div < 0) |
5517 | return isl_basic_map_free(bmap); |
5518 | pos = v_div + div; |
5519 | i = isl_basic_map_alloc_inequality(bmap); |
5520 | if (i < 0) |
5521 | return isl_basic_map_free(bmap); |
5522 | isl_seq_cpy(dst: bmap->ineq[i], src: bmap->div[div] + 1, len: 1 + v_div + n_div); |
5523 | isl_int_neg(bmap->ineq[i][1 + pos], bmap->div[div][0]); |
5524 | |
5525 | return bmap; |
5526 | } |
5527 | |
5528 | /* For the div d = floor(f/m) at position "div", add the constraint |
5529 | * |
5530 | * -(f-(m-1)) + m d >= 0 |
5531 | */ |
5532 | static __isl_give isl_basic_map *add_lower_div_constraint( |
5533 | __isl_take isl_basic_map *bmap, unsigned div) |
5534 | { |
5535 | int i; |
5536 | isl_size v_div = isl_basic_map_var_offset(bmap, type: isl_dim_div); |
5537 | isl_size n_div; |
5538 | unsigned pos; |
5539 | |
5540 | n_div = isl_basic_map_dim(bmap, type: isl_dim_div); |
5541 | if (v_div < 0 || n_div < 0) |
5542 | return isl_basic_map_free(bmap); |
5543 | pos = v_div + div; |
5544 | i = isl_basic_map_alloc_inequality(bmap); |
5545 | if (i < 0) |
5546 | return isl_basic_map_free(bmap); |
5547 | isl_seq_neg(dst: bmap->ineq[i], src: bmap->div[div] + 1, len: 1 + v_div + n_div); |
5548 | isl_int_set(bmap->ineq[i][1 + pos], bmap->div[div][0]); |
5549 | isl_int_add(bmap->ineq[i][0], bmap->ineq[i][0], bmap->ineq[i][1 + pos]); |
5550 | isl_int_sub_ui(bmap->ineq[i][0], bmap->ineq[i][0], 1); |
5551 | |
5552 | return bmap; |
5553 | } |
5554 | |
5555 | /* For the div d = floor(f/m) at position "pos", add the constraints |
5556 | * |
5557 | * f - m d >= 0 |
5558 | * -(f-(m-1)) + m d >= 0 |
5559 | * |
5560 | * Note that the second constraint is the negation of |
5561 | * |
5562 | * f - m d >= m |
5563 | */ |
5564 | __isl_give isl_basic_map *isl_basic_map_add_div_constraints( |
5565 | __isl_take isl_basic_map *bmap, unsigned pos) |
5566 | { |
5567 | bmap = add_upper_div_constraint(bmap, div: pos); |
5568 | bmap = add_lower_div_constraint(bmap, div: pos); |
5569 | return bmap; |
5570 | } |
5571 | |
5572 | /* For each known div d = floor(f/m), add the constraints |
5573 | * |
5574 | * f - m d >= 0 |
5575 | * -(f-(m-1)) + m d >= 0 |
5576 | * |
5577 | * Remove duplicate constraints in case of some these div constraints |
5578 | * already appear in "bmap". |
5579 | */ |
5580 | __isl_give isl_basic_map *isl_basic_map_add_known_div_constraints( |
5581 | __isl_take isl_basic_map *bmap) |
5582 | { |
5583 | isl_size n_div; |
5584 | |
5585 | n_div = isl_basic_map_dim(bmap, type: isl_dim_div); |
5586 | if (n_div < 0) |
5587 | return isl_basic_map_free(bmap); |
5588 | if (n_div == 0) |
5589 | return bmap; |
5590 | |
5591 | bmap = add_known_div_constraints(bmap); |
5592 | bmap = isl_basic_map_remove_duplicate_constraints(bmap, NULL, detect_divs: 0); |
5593 | bmap = isl_basic_map_finalize(bmap); |
5594 | return bmap; |
5595 | } |
5596 | |
5597 | /* Add the div constraint of sign "sign" for div "div" of "bmap". |
5598 | * |
5599 | * In particular, if this div is of the form d = floor(f/m), |
5600 | * then add the constraint |
5601 | * |
5602 | * f - m d >= 0 |
5603 | * |
5604 | * if sign < 0 or the constraint |
5605 | * |
5606 | * -(f-(m-1)) + m d >= 0 |
5607 | * |
5608 | * if sign > 0. |
5609 | */ |
5610 | __isl_give isl_basic_map *isl_basic_map_add_div_constraint( |
5611 | __isl_take isl_basic_map *bmap, unsigned div, int sign) |
5612 | { |
5613 | if (sign < 0) |
5614 | return add_upper_div_constraint(bmap, div); |
5615 | else |
5616 | return add_lower_div_constraint(bmap, div); |
5617 | } |
5618 | |
5619 | __isl_give isl_basic_set *isl_basic_map_underlying_set( |
5620 | __isl_take isl_basic_map *bmap) |
5621 | { |
5622 | isl_space *space; |
5623 | |
5624 | if (!bmap) |
5625 | goto error; |
5626 | if (bmap->dim->nparam == 0 && bmap->dim->n_in == 0 && |
5627 | bmap->n_div == 0 && |
5628 | !isl_space_is_named_or_nested(space: bmap->dim, type: isl_dim_in) && |
5629 | !isl_space_is_named_or_nested(space: bmap->dim, type: isl_dim_out)) |
5630 | return bset_from_bmap(bmap); |
5631 | bmap = isl_basic_map_cow(bmap); |
5632 | if (!bmap) |
5633 | return NULL; |
5634 | space = isl_basic_map_take_space(bmap); |
5635 | space = isl_space_underlying(space, n_div: bmap->n_div); |
5636 | bmap = isl_basic_map_restore_space(bmap, space); |
5637 | if (!bmap) |
5638 | return NULL; |
5639 | bmap->extra -= bmap->n_div; |
5640 | bmap->n_div = 0; |
5641 | bmap = isl_basic_map_finalize(bmap); |
5642 | return bset_from_bmap(bmap); |
5643 | error: |
5644 | isl_basic_map_free(bmap); |
5645 | return NULL; |
5646 | } |
5647 | |
5648 | __isl_give isl_basic_set *isl_basic_set_underlying_set( |
5649 | __isl_take isl_basic_set *bset) |
5650 | { |
5651 | return isl_basic_map_underlying_set(bmap: bset_to_bmap(bset)); |
5652 | } |
5653 | |
5654 | /* Replace each element in "list" by the result of applying |
5655 | * isl_basic_map_underlying_set to the element. |
5656 | */ |
5657 | __isl_give isl_basic_set_list *isl_basic_map_list_underlying_set( |
5658 | __isl_take isl_basic_map_list *list) |
5659 | { |
5660 | int i; |
5661 | isl_size n; |
5662 | |
5663 | n = isl_basic_map_list_n_basic_map(list); |
5664 | if (n < 0) |
5665 | goto error; |
5666 | |
5667 | for (i = 0; i < n; ++i) { |
5668 | isl_basic_map *bmap; |
5669 | isl_basic_set *bset; |
5670 | |
5671 | bmap = isl_basic_map_list_get_basic_map(list, index: i); |
5672 | bset = isl_basic_set_underlying_set(bset: bmap); |
5673 | list = isl_basic_set_list_set_basic_set(list, index: i, el: bset); |
5674 | } |
5675 | |
5676 | return list; |
5677 | error: |
5678 | isl_basic_map_list_free(list); |
5679 | return NULL; |
5680 | } |
5681 | |
5682 | __isl_give isl_basic_map *isl_basic_map_overlying_set( |
5683 | __isl_take isl_basic_set *bset, __isl_take isl_basic_map *like) |
5684 | { |
5685 | struct isl_basic_map *bmap; |
5686 | struct isl_ctx *ctx; |
5687 | isl_size dim, bmap_total; |
5688 | unsigned total; |
5689 | int i; |
5690 | |
5691 | if (!bset || !like) |
5692 | goto error; |
5693 | ctx = bset->ctx; |
5694 | if (isl_basic_set_check_no_params(bset) < 0 || |
5695 | isl_basic_set_check_no_locals(bset) < 0) |
5696 | goto error; |
5697 | dim = isl_basic_set_dim(bset, type: isl_dim_set); |
5698 | bmap_total = isl_basic_map_dim(bmap: like, type: isl_dim_all); |
5699 | if (dim < 0 || bmap_total < 0) |
5700 | goto error; |
5701 | isl_assert(ctx, dim == bmap_total, goto error); |
5702 | if (like->n_div == 0) { |
5703 | isl_space *space = isl_basic_map_get_space(bmap: like); |
5704 | isl_basic_map_free(bmap: like); |
5705 | return isl_basic_map_reset_space(bmap: bset, space); |
5706 | } |
5707 | bset = isl_basic_set_cow(bset); |
5708 | if (!bset) |
5709 | goto error; |
5710 | total = dim + bset->extra; |
5711 | bmap = bset_to_bmap(bset); |
5712 | isl_space_free(space: isl_basic_map_take_space(bmap)); |
5713 | bmap = isl_basic_map_restore_space(bmap, space: isl_basic_map_get_space(bmap: like)); |
5714 | if (!bmap) |
5715 | goto error; |
5716 | bmap->n_div = like->n_div; |
5717 | bmap->extra += like->n_div; |
5718 | if (bmap->extra) { |
5719 | unsigned ltotal; |
5720 | isl_int **div; |
5721 | ltotal = total - bmap->extra + like->extra; |
5722 | if (ltotal > total) |
5723 | ltotal = total; |
5724 | bmap->block2 = isl_blk_extend(ctx, block: bmap->block2, |
5725 | new_n: bmap->extra * (1 + 1 + total)); |
5726 | if (isl_blk_is_error(block: bmap->block2)) |
5727 | goto error; |
5728 | div = isl_realloc_array(ctx, bmap->div, isl_int *, bmap->extra); |
5729 | if (!div) |
5730 | goto error; |
5731 | bmap->div = div; |
5732 | for (i = 0; i < bmap->extra; ++i) |
5733 | bmap->div[i] = bmap->block2.data + i * (1 + 1 + total); |
5734 | for (i = 0; i < like->n_div; ++i) { |
5735 | isl_seq_cpy(dst: bmap->div[i], src: like->div[i], len: 1 + 1 + ltotal); |
5736 | isl_seq_clr(p: bmap->div[i]+1+1+ltotal, len: total - ltotal); |
5737 | } |
5738 | bmap = isl_basic_map_add_known_div_constraints(bmap); |
5739 | } |
5740 | isl_basic_map_free(bmap: like); |
5741 | bmap = isl_basic_map_simplify(bmap); |
5742 | bmap = isl_basic_map_finalize(bmap); |
5743 | return bmap; |
5744 | error: |
5745 | isl_basic_map_free(bmap: like); |
5746 | isl_basic_set_free(bset); |
5747 | return NULL; |
5748 | } |
5749 | |
5750 | __isl_give isl_basic_set *isl_basic_set_from_underlying_set( |
5751 | __isl_take isl_basic_set *bset, __isl_take isl_basic_set *like) |
5752 | { |
5753 | return bset_from_bmap(bmap: isl_basic_map_overlying_set(bset, |
5754 | like: bset_to_bmap(bset: like))); |
5755 | } |
5756 | |
5757 | __isl_give isl_set *isl_map_underlying_set(__isl_take isl_map *map) |
5758 | { |
5759 | int i; |
5760 | |
5761 | map = isl_map_cow(map); |
5762 | if (!map) |
5763 | return NULL; |
5764 | map->dim = isl_space_cow(space: map->dim); |
5765 | if (!map->dim) |
5766 | goto error; |
5767 | |
5768 | for (i = 1; i < map->n; ++i) |
5769 | isl_assert(map->ctx, map->p[0]->n_div == map->p[i]->n_div, |
5770 | goto error); |
5771 | for (i = 0; i < map->n; ++i) { |
5772 | map->p[i] = bset_to_bmap( |
5773 | bset: isl_basic_map_underlying_set(bmap: map->p[i])); |
5774 | if (!map->p[i]) |
5775 | goto error; |
5776 | } |
5777 | if (map->n == 0) |
5778 | map->dim = isl_space_underlying(space: map->dim, n_div: 0); |
5779 | else { |
5780 | isl_space_free(space: map->dim); |
5781 | map->dim = isl_space_copy(space: map->p[0]->dim); |
5782 | } |
5783 | if (!map->dim) |
5784 | goto error; |
5785 | return set_from_map(map); |
5786 | error: |
5787 | isl_map_free(map); |
5788 | return NULL; |
5789 | } |
5790 | |
5791 | /* Replace the space of "bmap" by "space". |
5792 | * |
5793 | * If the space of "bmap" is identical to "space" (including the identifiers |
5794 | * of the input and output dimensions), then simply return the original input. |
5795 | */ |
5796 | __isl_give isl_basic_map *isl_basic_map_reset_space( |
5797 | __isl_take isl_basic_map *bmap, __isl_take isl_space *space) |
5798 | { |
5799 | isl_bool equal; |
5800 | isl_space *bmap_space; |
5801 | |
5802 | bmap_space = isl_basic_map_peek_space(bmap); |
5803 | equal = isl_space_is_equal(space1: bmap_space, space2: space); |
5804 | if (equal >= 0 && equal) |
5805 | equal = isl_space_has_equal_ids(space1: bmap_space, space2: space); |
5806 | if (equal < 0) |
5807 | goto error; |
5808 | if (equal) { |
5809 | isl_space_free(space); |
5810 | return bmap; |
5811 | } |
5812 | isl_space_free(space: isl_basic_map_take_space(bmap)); |
5813 | bmap = isl_basic_map_restore_space(bmap, space); |
5814 | |
5815 | bmap = isl_basic_map_finalize(bmap); |
5816 | |
5817 | return bmap; |
5818 | error: |
5819 | isl_basic_map_free(bmap); |
5820 | isl_space_free(space); |
5821 | return NULL; |
5822 | } |
5823 | |
5824 | __isl_give isl_basic_set *isl_basic_set_reset_space( |
5825 | __isl_take isl_basic_set *bset, __isl_take isl_space *space) |
5826 | { |
5827 | return bset_from_bmap(bmap: isl_basic_map_reset_space(bmap: bset_to_bmap(bset), |
5828 | space)); |
5829 | } |
5830 | |
5831 | /* Check that the total dimensions of "map" and "space" are the same. |
5832 | */ |
5833 | static isl_stat check_map_space_equal_total_dim(__isl_keep isl_map *map, |
5834 | __isl_keep isl_space *space) |
5835 | { |
5836 | isl_size dim1, dim2; |
5837 | |
5838 | dim1 = isl_map_dim(map, type: isl_dim_all); |
5839 | dim2 = isl_space_dim(space, type: isl_dim_all); |
5840 | if (dim1 < 0 || dim2 < 0) |
5841 | return isl_stat_error; |
5842 | if (dim1 == dim2) |
5843 | return isl_stat_ok; |
5844 | isl_die(isl_map_get_ctx(map), isl_error_invalid, |
5845 | "total dimensions do not match" , return isl_stat_error); |
5846 | } |
5847 | |
5848 | __isl_give isl_map *isl_map_reset_space(__isl_take isl_map *map, |
5849 | __isl_take isl_space *space) |
5850 | { |
5851 | int i; |
5852 | |
5853 | map = isl_map_cow(map); |
5854 | if (!map || !space) |
5855 | goto error; |
5856 | |
5857 | for (i = 0; i < map->n; ++i) { |
5858 | map->p[i] = isl_basic_map_reset_space(bmap: map->p[i], |
5859 | space: isl_space_copy(space)); |
5860 | if (!map->p[i]) |
5861 | goto error; |
5862 | } |
5863 | isl_space_free(space: isl_map_take_space(map)); |
5864 | map = isl_map_restore_space(map, space); |
5865 | |
5866 | return map; |
5867 | error: |
5868 | isl_map_free(map); |
5869 | isl_space_free(space); |
5870 | return NULL; |
5871 | } |
5872 | |
5873 | /* Replace the space of "map" by "space", without modifying |
5874 | * the dimension of "map". |
5875 | * |
5876 | * If the space of "map" is identical to "space" (including the identifiers |
5877 | * of the input and output dimensions), then simply return the original input. |
5878 | */ |
5879 | __isl_give isl_map *isl_map_reset_equal_dim_space(__isl_take isl_map *map, |
5880 | __isl_take isl_space *space) |
5881 | { |
5882 | isl_bool equal; |
5883 | isl_space *map_space; |
5884 | |
5885 | map_space = isl_map_peek_space(map); |
5886 | equal = isl_space_is_equal(space1: map_space, space2: space); |
5887 | if (equal >= 0 && equal) |
5888 | equal = isl_space_has_equal_ids(space1: map_space, space2: space); |
5889 | if (equal < 0) |
5890 | goto error; |
5891 | if (equal) { |
5892 | isl_space_free(space); |
5893 | return map; |
5894 | } |
5895 | if (check_map_space_equal_total_dim(map, space) < 0) |
5896 | goto error; |
5897 | return isl_map_reset_space(map, space); |
5898 | error: |
5899 | isl_map_free(map); |
5900 | isl_space_free(space); |
5901 | return NULL; |
5902 | } |
5903 | |
5904 | __isl_give isl_set *isl_set_reset_space(__isl_take isl_set *set, |
5905 | __isl_take isl_space *space) |
5906 | { |
5907 | return set_from_map(isl_map_reset_space(map: set_to_map(set), space)); |
5908 | } |
5909 | |
5910 | /* Compute the parameter domain of the given basic set. |
5911 | */ |
5912 | __isl_give isl_basic_set *isl_basic_set_params(__isl_take isl_basic_set *bset) |
5913 | { |
5914 | isl_bool is_params; |
5915 | isl_space *space; |
5916 | isl_size n; |
5917 | |
5918 | is_params = isl_basic_set_is_params(bset); |
5919 | if (is_params < 0) |
5920 | return isl_basic_set_free(bset); |
5921 | if (is_params) |
5922 | return bset; |
5923 | |
5924 | n = isl_basic_set_dim(bset, type: isl_dim_set); |
5925 | if (n < 0) |
5926 | return isl_basic_set_free(bset); |
5927 | bset = isl_basic_set_project_out(bset, type: isl_dim_set, first: 0, n); |
5928 | space = isl_basic_set_get_space(bset); |
5929 | space = isl_space_params(space); |
5930 | bset = isl_basic_set_reset_space(bset, space); |
5931 | return bset; |
5932 | } |
5933 | |
5934 | /* Construct a zero-dimensional basic set with the given parameter domain. |
5935 | */ |
5936 | __isl_give isl_basic_set *isl_basic_set_from_params( |
5937 | __isl_take isl_basic_set *bset) |
5938 | { |
5939 | isl_space *space; |
5940 | space = isl_basic_set_get_space(bset); |
5941 | space = isl_space_set_from_params(space); |
5942 | bset = isl_basic_set_reset_space(bset, space); |
5943 | return bset; |
5944 | } |
5945 | |
5946 | /* Compute the parameter domain of the given set. |
5947 | */ |
5948 | __isl_give isl_set *isl_set_params(__isl_take isl_set *set) |
5949 | { |
5950 | return isl_map_params(map: set_to_map(set)); |
5951 | } |
5952 | |
5953 | /* Construct a zero-dimensional set with the given parameter domain. |
5954 | */ |
5955 | __isl_give isl_set *isl_set_from_params(__isl_take isl_set *set) |
5956 | { |
5957 | isl_space *space; |
5958 | space = isl_set_get_space(set); |
5959 | space = isl_space_set_from_params(space); |
5960 | set = isl_set_reset_space(set, space); |
5961 | return set; |
5962 | } |
5963 | |
5964 | /* Compute the parameter domain of the given map. |
5965 | */ |
5966 | __isl_give isl_set *isl_map_params(__isl_take isl_map *map) |
5967 | { |
5968 | isl_space *space; |
5969 | isl_size n_in, n_out; |
5970 | |
5971 | n_in = isl_map_dim(map, type: isl_dim_in); |
5972 | n_out = isl_map_dim(map, type: isl_dim_out); |
5973 | if (n_in < 0 || n_out < 0) |
5974 | return isl_map_free(map); |
5975 | map = isl_map_project_out(map, type: isl_dim_in, first: 0, n: n_in); |
5976 | map = isl_map_project_out(map, type: isl_dim_out, first: 0, n: n_out); |
5977 | space = isl_map_get_space(map); |
5978 | space = isl_space_params(space); |
5979 | map = isl_map_reset_space(map, space); |
5980 | return map; |
5981 | } |
5982 | |
5983 | __isl_give isl_basic_set *isl_basic_map_domain(__isl_take isl_basic_map *bmap) |
5984 | { |
5985 | isl_space *space; |
5986 | isl_size n_out; |
5987 | |
5988 | n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
5989 | if (n_out < 0) |
5990 | return isl_basic_map_free(bmap); |
5991 | space = isl_space_domain(space: isl_basic_map_get_space(bmap)); |
5992 | |
5993 | bmap = isl_basic_map_project_out(bmap, type: isl_dim_out, first: 0, n: n_out); |
5994 | |
5995 | return isl_basic_map_reset_space(bmap, space); |
5996 | } |
5997 | |
5998 | isl_bool isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap) |
5999 | { |
6000 | if (!bmap) |
6001 | return isl_bool_error; |
6002 | return isl_space_may_be_set(space: bmap->dim); |
6003 | } |
6004 | |
6005 | /* Is this basic map actually a set? |
6006 | * Users should never call this function. Outside of isl, |
6007 | * the type should indicate whether something is a set or a map. |
6008 | */ |
6009 | isl_bool isl_basic_map_is_set(__isl_keep isl_basic_map *bmap) |
6010 | { |
6011 | if (!bmap) |
6012 | return isl_bool_error; |
6013 | return isl_space_is_set(space: bmap->dim); |
6014 | } |
6015 | |
6016 | __isl_give isl_basic_set *isl_basic_map_range(__isl_take isl_basic_map *bmap) |
6017 | { |
6018 | isl_bool is_set; |
6019 | |
6020 | is_set = isl_basic_map_is_set(bmap); |
6021 | if (is_set < 0) |
6022 | goto error; |
6023 | if (is_set) |
6024 | return bmap; |
6025 | return isl_basic_map_domain(bmap: isl_basic_map_reverse(bmap)); |
6026 | error: |
6027 | isl_basic_map_free(bmap); |
6028 | return NULL; |
6029 | } |
6030 | |
6031 | __isl_give isl_basic_map *isl_basic_map_domain_map( |
6032 | __isl_take isl_basic_map *bmap) |
6033 | { |
6034 | int i; |
6035 | isl_space *space; |
6036 | isl_basic_map *domain; |
6037 | isl_size nparam, n_in, n_out; |
6038 | |
6039 | nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
6040 | n_in = isl_basic_map_dim(bmap, type: isl_dim_in); |
6041 | n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
6042 | if (nparam < 0 || n_in < 0 || n_out < 0) |
6043 | return isl_basic_map_free(bmap); |
6044 | |
6045 | space = isl_basic_map_get_space(bmap); |
6046 | space = isl_space_from_range(space: isl_space_domain(space)); |
6047 | domain = isl_basic_map_universe(space); |
6048 | |
6049 | bmap = isl_basic_map_from_domain(bset: isl_basic_map_wrap(bmap)); |
6050 | bmap = isl_basic_map_apply_range(bmap1: bmap, bmap2: domain); |
6051 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq: n_in, n_ineq: 0); |
6052 | |
6053 | for (i = 0; i < n_in; ++i) |
6054 | bmap = isl_basic_map_equate(bmap, type1: isl_dim_in, pos1: i, |
6055 | type2: isl_dim_out, pos2: i); |
6056 | |
6057 | bmap = isl_basic_map_gauss(bmap, NULL); |
6058 | return isl_basic_map_finalize(bmap); |
6059 | } |
6060 | |
6061 | __isl_give isl_basic_map *isl_basic_map_range_map( |
6062 | __isl_take isl_basic_map *bmap) |
6063 | { |
6064 | int i; |
6065 | isl_space *space; |
6066 | isl_basic_map *range; |
6067 | isl_size nparam, n_in, n_out; |
6068 | |
6069 | nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
6070 | n_in = isl_basic_map_dim(bmap, type: isl_dim_in); |
6071 | n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
6072 | if (nparam < 0 || n_in < 0 || n_out < 0) |
6073 | return isl_basic_map_free(bmap); |
6074 | |
6075 | space = isl_basic_map_get_space(bmap); |
6076 | space = isl_space_from_range(space: isl_space_range(space)); |
6077 | range = isl_basic_map_universe(space); |
6078 | |
6079 | bmap = isl_basic_map_from_domain(bset: isl_basic_map_wrap(bmap)); |
6080 | bmap = isl_basic_map_apply_range(bmap1: bmap, bmap2: range); |
6081 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq: n_out, n_ineq: 0); |
6082 | |
6083 | for (i = 0; i < n_out; ++i) |
6084 | bmap = isl_basic_map_equate(bmap, type1: isl_dim_in, pos1: n_in + i, |
6085 | type2: isl_dim_out, pos2: i); |
6086 | |
6087 | bmap = isl_basic_map_gauss(bmap, NULL); |
6088 | return isl_basic_map_finalize(bmap); |
6089 | } |
6090 | |
6091 | int isl_map_may_be_set(__isl_keep isl_map *map) |
6092 | { |
6093 | if (!map) |
6094 | return -1; |
6095 | return isl_space_may_be_set(space: map->dim); |
6096 | } |
6097 | |
6098 | /* Is this map actually a set? |
6099 | * Users should never call this function. Outside of isl, |
6100 | * the type should indicate whether something is a set or a map. |
6101 | */ |
6102 | isl_bool isl_map_is_set(__isl_keep isl_map *map) |
6103 | { |
6104 | if (!map) |
6105 | return isl_bool_error; |
6106 | return isl_space_is_set(space: map->dim); |
6107 | } |
6108 | |
6109 | __isl_give isl_set *isl_map_range(__isl_take isl_map *map) |
6110 | { |
6111 | isl_space *space; |
6112 | isl_size n_in; |
6113 | |
6114 | n_in = isl_map_dim(map, type: isl_dim_in); |
6115 | if (n_in < 0) |
6116 | return set_from_map(isl_map_free(map)); |
6117 | space = isl_space_range(space: isl_map_get_space(map)); |
6118 | |
6119 | map = isl_map_project_out(map, type: isl_dim_in, first: 0, n: n_in); |
6120 | |
6121 | return set_from_map(isl_map_reset_space(map, space)); |
6122 | } |
6123 | |
6124 | /* Transform "map" by applying "fn_space" to its space and "fn_bmap" |
6125 | * to each of its basic maps. |
6126 | */ |
6127 | static __isl_give isl_map *isl_map_transform(__isl_take isl_map *map, |
6128 | __isl_give isl_space *(*fn_space)(__isl_take isl_space *space), |
6129 | __isl_give isl_basic_map *(*fn_bmap)(__isl_take isl_basic_map *bmap)) |
6130 | { |
6131 | int i; |
6132 | isl_space *space; |
6133 | |
6134 | map = isl_map_cow(map); |
6135 | if (!map) |
6136 | return NULL; |
6137 | |
6138 | for (i = 0; i < map->n; ++i) { |
6139 | map->p[i] = fn_bmap(map->p[i]); |
6140 | if (!map->p[i]) |
6141 | return isl_map_free(map); |
6142 | } |
6143 | map = isl_map_unmark_normalized(map); |
6144 | |
6145 | space = isl_map_take_space(map); |
6146 | space = fn_space(space); |
6147 | map = isl_map_restore_space(map, space); |
6148 | |
6149 | return map; |
6150 | } |
6151 | |
6152 | __isl_give isl_map *isl_map_domain_map(__isl_take isl_map *map) |
6153 | { |
6154 | return isl_map_transform(map, fn_space: &isl_space_domain_map, |
6155 | fn_bmap: &isl_basic_map_domain_map); |
6156 | } |
6157 | |
6158 | __isl_give isl_map *isl_map_range_map(__isl_take isl_map *map) |
6159 | { |
6160 | return isl_map_transform(map, fn_space: &isl_space_range_map, |
6161 | fn_bmap: &isl_basic_map_range_map); |
6162 | } |
6163 | |
6164 | /* Given a wrapped map of the form A[B -> C], |
6165 | * return the map A[B -> C] -> B. |
6166 | */ |
6167 | __isl_give isl_map *isl_set_wrapped_domain_map(__isl_take isl_set *set) |
6168 | { |
6169 | isl_id *id; |
6170 | isl_map *map; |
6171 | |
6172 | if (!set) |
6173 | return NULL; |
6174 | if (!isl_set_has_tuple_id(set)) |
6175 | return isl_map_domain_map(map: isl_set_unwrap(set)); |
6176 | |
6177 | id = isl_set_get_tuple_id(set); |
6178 | map = isl_map_domain_map(map: isl_set_unwrap(set)); |
6179 | map = isl_map_set_tuple_id(map, type: isl_dim_in, id); |
6180 | |
6181 | return map; |
6182 | } |
6183 | |
6184 | __isl_give isl_basic_map *isl_basic_map_from_domain( |
6185 | __isl_take isl_basic_set *bset) |
6186 | { |
6187 | return isl_basic_map_reverse(bmap: isl_basic_map_from_range(bset)); |
6188 | } |
6189 | |
6190 | __isl_give isl_basic_map *isl_basic_map_from_range( |
6191 | __isl_take isl_basic_set *bset) |
6192 | { |
6193 | isl_space *space; |
6194 | space = isl_basic_set_get_space(bset); |
6195 | space = isl_space_from_range(space); |
6196 | bset = isl_basic_set_reset_space(bset, space); |
6197 | return bset_to_bmap(bset); |
6198 | } |
6199 | |
6200 | /* Create a relation with the given set as range. |
6201 | * The domain of the created relation is a zero-dimensional |
6202 | * flat anonymous space. |
6203 | */ |
6204 | __isl_give isl_map *isl_map_from_range(__isl_take isl_set *set) |
6205 | { |
6206 | isl_space *space; |
6207 | space = isl_set_get_space(set); |
6208 | space = isl_space_from_range(space); |
6209 | set = isl_set_reset_space(set, space); |
6210 | return set_to_map(set); |
6211 | } |
6212 | |
6213 | /* Create a relation with the given set as domain. |
6214 | * The range of the created relation is a zero-dimensional |
6215 | * flat anonymous space. |
6216 | */ |
6217 | __isl_give isl_map *isl_map_from_domain(__isl_take isl_set *set) |
6218 | { |
6219 | return isl_map_reverse(map: isl_map_from_range(set)); |
6220 | } |
6221 | |
6222 | __isl_give isl_basic_map *isl_basic_map_from_domain_and_range( |
6223 | __isl_take isl_basic_set *domain, __isl_take isl_basic_set *range) |
6224 | { |
6225 | return isl_basic_map_apply_range(bmap1: isl_basic_map_reverse(bmap: domain), bmap2: range); |
6226 | } |
6227 | |
6228 | __isl_give isl_map *isl_map_from_domain_and_range(__isl_take isl_set *domain, |
6229 | __isl_take isl_set *range) |
6230 | { |
6231 | return isl_map_apply_range(map1: isl_map_reverse(map: domain), map2: range); |
6232 | } |
6233 | |
6234 | /* Return a newly allocated isl_map with given space and flags and |
6235 | * room for "n" basic maps. |
6236 | * Make sure that all cached information is cleared. |
6237 | */ |
6238 | __isl_give isl_map *isl_map_alloc_space(__isl_take isl_space *space, int n, |
6239 | unsigned flags) |
6240 | { |
6241 | struct isl_map *map; |
6242 | |
6243 | if (!space) |
6244 | return NULL; |
6245 | if (n < 0) |
6246 | isl_die(space->ctx, isl_error_internal, |
6247 | "negative number of basic maps" , goto error); |
6248 | map = isl_calloc(space->ctx, struct isl_map, |
6249 | sizeof(struct isl_map) + |
6250 | (n - 1) * sizeof(struct isl_basic_map *)); |
6251 | if (!map) |
6252 | goto error; |
6253 | |
6254 | map->ctx = space->ctx; |
6255 | isl_ctx_ref(ctx: map->ctx); |
6256 | map->ref = 1; |
6257 | map->size = n; |
6258 | map->n = 0; |
6259 | map->dim = space; |
6260 | map->flags = flags; |
6261 | return map; |
6262 | error: |
6263 | isl_space_free(space); |
6264 | return NULL; |
6265 | } |
6266 | |
6267 | __isl_give isl_basic_map *isl_basic_map_empty(__isl_take isl_space *space) |
6268 | { |
6269 | struct isl_basic_map *bmap; |
6270 | bmap = isl_basic_map_alloc_space(space, extra: 0, n_eq: 1, n_ineq: 0); |
6271 | bmap = isl_basic_map_set_to_empty(bmap); |
6272 | return bmap; |
6273 | } |
6274 | |
6275 | __isl_give isl_basic_set *isl_basic_set_empty(__isl_take isl_space *space) |
6276 | { |
6277 | struct isl_basic_set *bset; |
6278 | bset = isl_basic_set_alloc_space(space, extra: 0, n_eq: 1, n_ineq: 0); |
6279 | bset = isl_basic_set_set_to_empty(bset); |
6280 | return bset; |
6281 | } |
6282 | |
6283 | __isl_give isl_basic_map *isl_basic_map_universe(__isl_take isl_space *space) |
6284 | { |
6285 | struct isl_basic_map *bmap; |
6286 | bmap = isl_basic_map_alloc_space(space, extra: 0, n_eq: 0, n_ineq: 0); |
6287 | bmap = isl_basic_map_finalize(bmap); |
6288 | return bmap; |
6289 | } |
6290 | |
6291 | __isl_give isl_basic_set *isl_basic_set_universe(__isl_take isl_space *space) |
6292 | { |
6293 | struct isl_basic_set *bset; |
6294 | bset = isl_basic_set_alloc_space(space, extra: 0, n_eq: 0, n_ineq: 0); |
6295 | bset = isl_basic_set_finalize(bset); |
6296 | return bset; |
6297 | } |
6298 | |
6299 | __isl_give isl_basic_map *isl_basic_map_nat_universe( |
6300 | __isl_take isl_space *space) |
6301 | { |
6302 | int i; |
6303 | isl_size total = isl_space_dim(space, type: isl_dim_all); |
6304 | isl_basic_map *bmap; |
6305 | |
6306 | if (total < 0) |
6307 | space = isl_space_free(space); |
6308 | bmap = isl_basic_map_alloc_space(space, extra: 0, n_eq: 0, n_ineq: total); |
6309 | for (i = 0; i < total; ++i) { |
6310 | int k = isl_basic_map_alloc_inequality(bmap); |
6311 | if (k < 0) |
6312 | goto error; |
6313 | isl_seq_clr(p: bmap->ineq[k], len: 1 + total); |
6314 | isl_int_set_si(bmap->ineq[k][1 + i], 1); |
6315 | } |
6316 | return bmap; |
6317 | error: |
6318 | isl_basic_map_free(bmap); |
6319 | return NULL; |
6320 | } |
6321 | |
6322 | __isl_give isl_basic_set *isl_basic_set_nat_universe( |
6323 | __isl_take isl_space *space) |
6324 | { |
6325 | return isl_basic_map_nat_universe(space); |
6326 | } |
6327 | |
6328 | __isl_give isl_map *isl_map_nat_universe(__isl_take isl_space *space) |
6329 | { |
6330 | return isl_map_from_basic_map(bmap: isl_basic_map_nat_universe(space)); |
6331 | } |
6332 | |
6333 | __isl_give isl_set *isl_set_nat_universe(__isl_take isl_space *space) |
6334 | { |
6335 | return isl_map_nat_universe(space); |
6336 | } |
6337 | |
6338 | __isl_give isl_map *isl_map_empty(__isl_take isl_space *space) |
6339 | { |
6340 | return isl_map_alloc_space(space, n: 0, ISL_MAP_DISJOINT); |
6341 | } |
6342 | |
6343 | __isl_give isl_set *isl_set_empty(__isl_take isl_space *space) |
6344 | { |
6345 | return isl_set_alloc_space(space, n: 0, ISL_MAP_DISJOINT); |
6346 | } |
6347 | |
6348 | __isl_give isl_map *isl_map_universe(__isl_take isl_space *space) |
6349 | { |
6350 | struct isl_map *map; |
6351 | if (!space) |
6352 | return NULL; |
6353 | map = isl_map_alloc_space(space: isl_space_copy(space), n: 1, ISL_MAP_DISJOINT); |
6354 | map = isl_map_add_basic_map(map, bmap: isl_basic_map_universe(space)); |
6355 | return map; |
6356 | } |
6357 | |
6358 | /* This function performs the same operation as isl_map_universe, |
6359 | * but is considered as a function on an isl_space when exported. |
6360 | */ |
6361 | __isl_give isl_map *isl_space_universe_map(__isl_take isl_space *space) |
6362 | { |
6363 | return isl_map_universe(space); |
6364 | } |
6365 | |
6366 | __isl_give isl_set *isl_set_universe(__isl_take isl_space *space) |
6367 | { |
6368 | struct isl_set *set; |
6369 | if (!space) |
6370 | return NULL; |
6371 | set = isl_set_alloc_space(space: isl_space_copy(space), n: 1, ISL_MAP_DISJOINT); |
6372 | set = isl_set_add_basic_set(set, bset: isl_basic_set_universe(space)); |
6373 | return set; |
6374 | } |
6375 | |
6376 | /* This function performs the same operation as isl_set_universe, |
6377 | * but is considered as a function on an isl_space when exported. |
6378 | */ |
6379 | __isl_give isl_set *isl_space_universe_set(__isl_take isl_space *space) |
6380 | { |
6381 | return isl_set_universe(space); |
6382 | } |
6383 | |
6384 | __isl_give isl_map *isl_map_dup(__isl_keep isl_map *map) |
6385 | { |
6386 | int i; |
6387 | struct isl_map *dup; |
6388 | |
6389 | if (!map) |
6390 | return NULL; |
6391 | dup = isl_map_alloc_space(space: isl_space_copy(space: map->dim), n: map->n, flags: map->flags); |
6392 | for (i = 0; i < map->n; ++i) |
6393 | dup = isl_map_add_basic_map(map: dup, bmap: isl_basic_map_copy(bmap: map->p[i])); |
6394 | return dup; |
6395 | } |
6396 | |
6397 | __isl_give isl_map *isl_map_add_basic_map(__isl_take isl_map *map, |
6398 | __isl_take isl_basic_map *bmap) |
6399 | { |
6400 | if (!bmap || !map) |
6401 | goto error; |
6402 | if (isl_basic_map_plain_is_empty(bmap)) { |
6403 | isl_basic_map_free(bmap); |
6404 | return map; |
6405 | } |
6406 | if (isl_map_basic_map_check_equal_space(map, bmap) < 0) |
6407 | goto error; |
6408 | isl_assert(map->ctx, map->n < map->size, goto error); |
6409 | map->p[map->n] = bmap; |
6410 | map->n++; |
6411 | map = isl_map_unmark_normalized(map); |
6412 | return map; |
6413 | error: |
6414 | if (map) |
6415 | isl_map_free(map); |
6416 | if (bmap) |
6417 | isl_basic_map_free(bmap); |
6418 | return NULL; |
6419 | } |
6420 | |
6421 | __isl_null isl_map *isl_map_free(__isl_take isl_map *map) |
6422 | { |
6423 | int i; |
6424 | |
6425 | if (!map) |
6426 | return NULL; |
6427 | |
6428 | if (--map->ref > 0) |
6429 | return NULL; |
6430 | |
6431 | clear_caches(map); |
6432 | isl_ctx_deref(ctx: map->ctx); |
6433 | for (i = 0; i < map->n; ++i) |
6434 | isl_basic_map_free(bmap: map->p[i]); |
6435 | isl_space_free(space: map->dim); |
6436 | free(ptr: map); |
6437 | |
6438 | return NULL; |
6439 | } |
6440 | |
6441 | static __isl_give isl_basic_map *isl_basic_map_fix_pos_si( |
6442 | __isl_take isl_basic_map *bmap, unsigned pos, int value) |
6443 | { |
6444 | int j; |
6445 | isl_size total; |
6446 | |
6447 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
6448 | if (total < 0) |
6449 | return isl_basic_map_free(bmap); |
6450 | |
6451 | bmap = isl_basic_map_cow(bmap); |
6452 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq: 1, n_ineq: 0); |
6453 | j = isl_basic_map_alloc_equality(bmap); |
6454 | if (j < 0) |
6455 | goto error; |
6456 | isl_seq_clr(p: bmap->eq[j] + 1, len: total); |
6457 | isl_int_set_si(bmap->eq[j][pos], -1); |
6458 | isl_int_set_si(bmap->eq[j][0], value); |
6459 | bmap = isl_basic_map_simplify(bmap); |
6460 | return isl_basic_map_finalize(bmap); |
6461 | error: |
6462 | isl_basic_map_free(bmap); |
6463 | return NULL; |
6464 | } |
6465 | |
6466 | static __isl_give isl_basic_map *isl_basic_map_fix_pos( |
6467 | __isl_take isl_basic_map *bmap, unsigned pos, isl_int value) |
6468 | { |
6469 | int j; |
6470 | isl_size total; |
6471 | |
6472 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
6473 | if (total < 0) |
6474 | return isl_basic_map_free(bmap); |
6475 | |
6476 | bmap = isl_basic_map_cow(bmap); |
6477 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq: 1, n_ineq: 0); |
6478 | j = isl_basic_map_alloc_equality(bmap); |
6479 | if (j < 0) |
6480 | goto error; |
6481 | isl_seq_clr(p: bmap->eq[j] + 1, len: total); |
6482 | isl_int_set_si(bmap->eq[j][pos], -1); |
6483 | isl_int_set(bmap->eq[j][0], value); |
6484 | bmap = isl_basic_map_simplify(bmap); |
6485 | return isl_basic_map_finalize(bmap); |
6486 | error: |
6487 | isl_basic_map_free(bmap); |
6488 | return NULL; |
6489 | } |
6490 | |
6491 | __isl_give isl_basic_map *isl_basic_map_fix_si(__isl_take isl_basic_map *bmap, |
6492 | enum isl_dim_type type, unsigned pos, int value) |
6493 | { |
6494 | if (isl_basic_map_check_range(obj: bmap, type, first: pos, n: 1) < 0) |
6495 | return isl_basic_map_free(bmap); |
6496 | return isl_basic_map_fix_pos_si(bmap, |
6497 | pos: isl_basic_map_offset(bmap, type) + pos, value); |
6498 | } |
6499 | |
6500 | __isl_give isl_basic_map *isl_basic_map_fix(__isl_take isl_basic_map *bmap, |
6501 | enum isl_dim_type type, unsigned pos, isl_int value) |
6502 | { |
6503 | if (isl_basic_map_check_range(obj: bmap, type, first: pos, n: 1) < 0) |
6504 | return isl_basic_map_free(bmap); |
6505 | return isl_basic_map_fix_pos(bmap, |
6506 | pos: isl_basic_map_offset(bmap, type) + pos, value); |
6507 | } |
6508 | |
6509 | /* Fix the value of the variable at position "pos" of type "type" of "bmap" |
6510 | * to be equal to "v". |
6511 | */ |
6512 | __isl_give isl_basic_map *isl_basic_map_fix_val(__isl_take isl_basic_map *bmap, |
6513 | enum isl_dim_type type, unsigned pos, __isl_take isl_val *v) |
6514 | { |
6515 | if (!bmap || !v) |
6516 | goto error; |
6517 | if (!isl_val_is_int(v)) |
6518 | isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, |
6519 | "expecting integer value" , goto error); |
6520 | if (isl_basic_map_check_range(obj: bmap, type, first: pos, n: 1) < 0) |
6521 | goto error; |
6522 | pos += isl_basic_map_offset(bmap, type); |
6523 | bmap = isl_basic_map_fix_pos(bmap, pos, value: v->n); |
6524 | isl_val_free(v); |
6525 | return bmap; |
6526 | error: |
6527 | isl_basic_map_free(bmap); |
6528 | isl_val_free(v); |
6529 | return NULL; |
6530 | } |
6531 | |
6532 | /* Fix the value of the variable at position "pos" of type "type" of "bset" |
6533 | * to be equal to "v". |
6534 | */ |
6535 | __isl_give isl_basic_set *isl_basic_set_fix_val(__isl_take isl_basic_set *bset, |
6536 | enum isl_dim_type type, unsigned pos, __isl_take isl_val *v) |
6537 | { |
6538 | return isl_basic_map_fix_val(bmap: bset, type, pos, v); |
6539 | } |
6540 | |
6541 | __isl_give isl_basic_set *isl_basic_set_fix_si(__isl_take isl_basic_set *bset, |
6542 | enum isl_dim_type type, unsigned pos, int value) |
6543 | { |
6544 | return bset_from_bmap(bmap: isl_basic_map_fix_si(bmap: bset_to_bmap(bset), |
6545 | type, pos, value)); |
6546 | } |
6547 | |
6548 | __isl_give isl_basic_set *isl_basic_set_fix(__isl_take isl_basic_set *bset, |
6549 | enum isl_dim_type type, unsigned pos, isl_int value) |
6550 | { |
6551 | return bset_from_bmap(bmap: isl_basic_map_fix(bmap: bset_to_bmap(bset), |
6552 | type, pos, value)); |
6553 | } |
6554 | |
6555 | /* Remove the basic map at position "i" from "map" if this basic map |
6556 | * is (obviously) empty. |
6557 | */ |
6558 | static __isl_give isl_map *remove_if_empty(__isl_take isl_map *map, int i) |
6559 | { |
6560 | isl_bool empty; |
6561 | |
6562 | if (!map) |
6563 | return NULL; |
6564 | |
6565 | empty = isl_basic_map_plain_is_empty(bmap: map->p[i]); |
6566 | if (empty < 0) |
6567 | return isl_map_free(map); |
6568 | if (!empty) |
6569 | return map; |
6570 | |
6571 | isl_basic_map_free(bmap: map->p[i]); |
6572 | map->n--; |
6573 | if (i != map->n) { |
6574 | map->p[i] = map->p[map->n]; |
6575 | map = isl_map_unmark_normalized(map); |
6576 | |
6577 | } |
6578 | |
6579 | return map; |
6580 | } |
6581 | |
6582 | /* Perform "fn" on each basic map of "map", where we may not be holding |
6583 | * the only reference to "map". |
6584 | * In particular, "fn" should be a semantics preserving operation |
6585 | * that we want to apply to all copies of "map". We therefore need |
6586 | * to be careful not to modify "map" in a way that breaks "map" |
6587 | * in case anything goes wrong. |
6588 | */ |
6589 | __isl_give isl_map *isl_map_inline_foreach_basic_map(__isl_take isl_map *map, |
6590 | __isl_give isl_basic_map *(*fn)(__isl_take isl_basic_map *bmap)) |
6591 | { |
6592 | struct isl_basic_map *bmap; |
6593 | int i; |
6594 | |
6595 | if (!map) |
6596 | return NULL; |
6597 | |
6598 | for (i = map->n - 1; i >= 0; --i) { |
6599 | bmap = isl_basic_map_copy(bmap: map->p[i]); |
6600 | bmap = fn(bmap); |
6601 | if (!bmap) |
6602 | goto error; |
6603 | isl_basic_map_free(bmap: map->p[i]); |
6604 | map->p[i] = bmap; |
6605 | map = remove_if_empty(map, i); |
6606 | if (!map) |
6607 | return NULL; |
6608 | } |
6609 | |
6610 | return map; |
6611 | error: |
6612 | isl_map_free(map); |
6613 | return NULL; |
6614 | } |
6615 | |
6616 | __isl_give isl_map *isl_map_fix_si(__isl_take isl_map *map, |
6617 | enum isl_dim_type type, unsigned pos, int value) |
6618 | { |
6619 | int i; |
6620 | |
6621 | map = isl_map_cow(map); |
6622 | if (isl_map_check_range(obj: map, type, first: pos, n: 1) < 0) |
6623 | return isl_map_free(map); |
6624 | for (i = map->n - 1; i >= 0; --i) { |
6625 | map->p[i] = isl_basic_map_fix_si(bmap: map->p[i], type, pos, value); |
6626 | map = remove_if_empty(map, i); |
6627 | if (!map) |
6628 | return NULL; |
6629 | } |
6630 | map = isl_map_unmark_normalized(map); |
6631 | return map; |
6632 | } |
6633 | |
6634 | __isl_give isl_set *isl_set_fix_si(__isl_take isl_set *set, |
6635 | enum isl_dim_type type, unsigned pos, int value) |
6636 | { |
6637 | return set_from_map(isl_map_fix_si(map: set_to_map(set), type, pos, value)); |
6638 | } |
6639 | |
6640 | __isl_give isl_map *isl_map_fix(__isl_take isl_map *map, |
6641 | enum isl_dim_type type, unsigned pos, isl_int value) |
6642 | { |
6643 | int i; |
6644 | |
6645 | map = isl_map_cow(map); |
6646 | if (isl_map_check_range(obj: map, type, first: pos, n: 1) < 0) |
6647 | return isl_map_free(map); |
6648 | for (i = 0; i < map->n; ++i) { |
6649 | map->p[i] = isl_basic_map_fix(bmap: map->p[i], type, pos, value); |
6650 | if (!map->p[i]) |
6651 | goto error; |
6652 | } |
6653 | map = isl_map_unmark_normalized(map); |
6654 | return map; |
6655 | error: |
6656 | isl_map_free(map); |
6657 | return NULL; |
6658 | } |
6659 | |
6660 | __isl_give isl_set *isl_set_fix(__isl_take isl_set *set, |
6661 | enum isl_dim_type type, unsigned pos, isl_int value) |
6662 | { |
6663 | return set_from_map(isl_map_fix(map: set_to_map(set), type, pos, value)); |
6664 | } |
6665 | |
6666 | /* Fix the value of the variable at position "pos" of type "type" of "map" |
6667 | * to be equal to "v". |
6668 | */ |
6669 | __isl_give isl_map *isl_map_fix_val(__isl_take isl_map *map, |
6670 | enum isl_dim_type type, unsigned pos, __isl_take isl_val *v) |
6671 | { |
6672 | int i; |
6673 | |
6674 | map = isl_map_cow(map); |
6675 | if (!map || !v) |
6676 | goto error; |
6677 | |
6678 | if (!isl_val_is_int(v)) |
6679 | isl_die(isl_map_get_ctx(map), isl_error_invalid, |
6680 | "expecting integer value" , goto error); |
6681 | if (isl_map_check_range(obj: map, type, first: pos, n: 1) < 0) |
6682 | goto error; |
6683 | for (i = map->n - 1; i >= 0; --i) { |
6684 | map->p[i] = isl_basic_map_fix_val(bmap: map->p[i], type, pos, |
6685 | v: isl_val_copy(v)); |
6686 | map = remove_if_empty(map, i); |
6687 | if (!map) |
6688 | goto error; |
6689 | } |
6690 | map = isl_map_unmark_normalized(map); |
6691 | isl_val_free(v); |
6692 | return map; |
6693 | error: |
6694 | isl_map_free(map); |
6695 | isl_val_free(v); |
6696 | return NULL; |
6697 | } |
6698 | |
6699 | /* Fix the value of the variable at position "pos" of type "type" of "set" |
6700 | * to be equal to "v". |
6701 | */ |
6702 | __isl_give isl_set *isl_set_fix_val(__isl_take isl_set *set, |
6703 | enum isl_dim_type type, unsigned pos, __isl_take isl_val *v) |
6704 | { |
6705 | return isl_map_fix_val(map: set, type, pos, v); |
6706 | } |
6707 | |
6708 | __isl_give isl_map *isl_map_fix_input_si(__isl_take isl_map *map, |
6709 | unsigned input, int value) |
6710 | { |
6711 | return isl_map_fix_si(map, type: isl_dim_in, pos: input, value); |
6712 | } |
6713 | |
6714 | __isl_give isl_set *isl_set_fix_dim_si(__isl_take isl_set *set, unsigned dim, |
6715 | int value) |
6716 | { |
6717 | return set_from_map(isl_map_fix_si(map: set_to_map(set), |
6718 | type: isl_dim_set, pos: dim, value)); |
6719 | } |
6720 | |
6721 | static __isl_give isl_basic_map *basic_map_bound_si( |
6722 | __isl_take isl_basic_map *bmap, |
6723 | enum isl_dim_type type, unsigned pos, int value, int upper) |
6724 | { |
6725 | int j; |
6726 | isl_size total; |
6727 | |
6728 | if (isl_basic_map_check_range(obj: bmap, type, first: pos, n: 1) < 0) |
6729 | return isl_basic_map_free(bmap); |
6730 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
6731 | if (total < 0) |
6732 | return isl_basic_map_free(bmap); |
6733 | pos += isl_basic_map_offset(bmap, type); |
6734 | bmap = isl_basic_map_cow(bmap); |
6735 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq: 0, n_ineq: 1); |
6736 | j = isl_basic_map_alloc_inequality(bmap); |
6737 | if (j < 0) |
6738 | goto error; |
6739 | isl_seq_clr(p: bmap->ineq[j], len: 1 + total); |
6740 | if (upper) { |
6741 | isl_int_set_si(bmap->ineq[j][pos], -1); |
6742 | isl_int_set_si(bmap->ineq[j][0], value); |
6743 | } else { |
6744 | isl_int_set_si(bmap->ineq[j][pos], 1); |
6745 | isl_int_set_si(bmap->ineq[j][0], -value); |
6746 | } |
6747 | bmap = isl_basic_map_simplify(bmap); |
6748 | return isl_basic_map_finalize(bmap); |
6749 | error: |
6750 | isl_basic_map_free(bmap); |
6751 | return NULL; |
6752 | } |
6753 | |
6754 | __isl_give isl_basic_map *isl_basic_map_lower_bound_si( |
6755 | __isl_take isl_basic_map *bmap, |
6756 | enum isl_dim_type type, unsigned pos, int value) |
6757 | { |
6758 | return basic_map_bound_si(bmap, type, pos, value, upper: 0); |
6759 | } |
6760 | |
6761 | /* Constrain the values of the given dimension to be no greater than "value". |
6762 | */ |
6763 | __isl_give isl_basic_map *isl_basic_map_upper_bound_si( |
6764 | __isl_take isl_basic_map *bmap, |
6765 | enum isl_dim_type type, unsigned pos, int value) |
6766 | { |
6767 | return basic_map_bound_si(bmap, type, pos, value, upper: 1); |
6768 | } |
6769 | |
6770 | static __isl_give isl_map *map_bound_si(__isl_take isl_map *map, |
6771 | enum isl_dim_type type, unsigned pos, int value, int upper) |
6772 | { |
6773 | int i; |
6774 | |
6775 | map = isl_map_cow(map); |
6776 | if (isl_map_check_range(obj: map, type, first: pos, n: 1) < 0) |
6777 | return isl_map_free(map); |
6778 | for (i = 0; i < map->n; ++i) { |
6779 | map->p[i] = basic_map_bound_si(bmap: map->p[i], |
6780 | type, pos, value, upper); |
6781 | if (!map->p[i]) |
6782 | goto error; |
6783 | } |
6784 | map = isl_map_unmark_normalized(map); |
6785 | return map; |
6786 | error: |
6787 | isl_map_free(map); |
6788 | return NULL; |
6789 | } |
6790 | |
6791 | __isl_give isl_map *isl_map_lower_bound_si(__isl_take isl_map *map, |
6792 | enum isl_dim_type type, unsigned pos, int value) |
6793 | { |
6794 | return map_bound_si(map, type, pos, value, upper: 0); |
6795 | } |
6796 | |
6797 | __isl_give isl_map *isl_map_upper_bound_si(__isl_take isl_map *map, |
6798 | enum isl_dim_type type, unsigned pos, int value) |
6799 | { |
6800 | return map_bound_si(map, type, pos, value, upper: 1); |
6801 | } |
6802 | |
6803 | __isl_give isl_set *isl_set_lower_bound_si(__isl_take isl_set *set, |
6804 | enum isl_dim_type type, unsigned pos, int value) |
6805 | { |
6806 | return set_from_map(isl_map_lower_bound_si(map: set_to_map(set), |
6807 | type, pos, value)); |
6808 | } |
6809 | |
6810 | __isl_give isl_set *isl_set_upper_bound_si(__isl_take isl_set *set, |
6811 | enum isl_dim_type type, unsigned pos, int value) |
6812 | { |
6813 | return isl_map_upper_bound_si(map: set, type, pos, value); |
6814 | } |
6815 | |
6816 | /* Bound the given variable of "bmap" from below (or above is "upper" |
6817 | * is set) to "value". |
6818 | */ |
6819 | static __isl_give isl_basic_map *basic_map_bound( |
6820 | __isl_take isl_basic_map *bmap, |
6821 | enum isl_dim_type type, unsigned pos, isl_int value, int upper) |
6822 | { |
6823 | int j; |
6824 | isl_size total; |
6825 | |
6826 | if (isl_basic_map_check_range(obj: bmap, type, first: pos, n: 1) < 0) |
6827 | return isl_basic_map_free(bmap); |
6828 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
6829 | if (total < 0) |
6830 | return isl_basic_map_free(bmap); |
6831 | pos += isl_basic_map_offset(bmap, type); |
6832 | bmap = isl_basic_map_cow(bmap); |
6833 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq: 0, n_ineq: 1); |
6834 | j = isl_basic_map_alloc_inequality(bmap); |
6835 | if (j < 0) |
6836 | goto error; |
6837 | isl_seq_clr(p: bmap->ineq[j], len: 1 + total); |
6838 | if (upper) { |
6839 | isl_int_set_si(bmap->ineq[j][pos], -1); |
6840 | isl_int_set(bmap->ineq[j][0], value); |
6841 | } else { |
6842 | isl_int_set_si(bmap->ineq[j][pos], 1); |
6843 | isl_int_neg(bmap->ineq[j][0], value); |
6844 | } |
6845 | bmap = isl_basic_map_simplify(bmap); |
6846 | return isl_basic_map_finalize(bmap); |
6847 | error: |
6848 | isl_basic_map_free(bmap); |
6849 | return NULL; |
6850 | } |
6851 | |
6852 | /* Bound the given variable of "map" from below (or above is "upper" |
6853 | * is set) to "value". |
6854 | */ |
6855 | static __isl_give isl_map *map_bound(__isl_take isl_map *map, |
6856 | enum isl_dim_type type, unsigned pos, isl_int value, int upper) |
6857 | { |
6858 | int i; |
6859 | |
6860 | map = isl_map_cow(map); |
6861 | if (isl_map_check_range(obj: map, type, first: pos, n: 1) < 0) |
6862 | return isl_map_free(map); |
6863 | for (i = map->n - 1; i >= 0; --i) { |
6864 | map->p[i] = basic_map_bound(bmap: map->p[i], type, pos, value, upper); |
6865 | map = remove_if_empty(map, i); |
6866 | if (!map) |
6867 | return NULL; |
6868 | } |
6869 | map = isl_map_unmark_normalized(map); |
6870 | return map; |
6871 | } |
6872 | |
6873 | __isl_give isl_map *isl_map_lower_bound(__isl_take isl_map *map, |
6874 | enum isl_dim_type type, unsigned pos, isl_int value) |
6875 | { |
6876 | return map_bound(map, type, pos, value, upper: 0); |
6877 | } |
6878 | |
6879 | __isl_give isl_map *isl_map_upper_bound(__isl_take isl_map *map, |
6880 | enum isl_dim_type type, unsigned pos, isl_int value) |
6881 | { |
6882 | return map_bound(map, type, pos, value, upper: 1); |
6883 | } |
6884 | |
6885 | __isl_give isl_set *isl_set_lower_bound(__isl_take isl_set *set, |
6886 | enum isl_dim_type type, unsigned pos, isl_int value) |
6887 | { |
6888 | return isl_map_lower_bound(map: set, type, pos, value); |
6889 | } |
6890 | |
6891 | __isl_give isl_set *isl_set_upper_bound(__isl_take isl_set *set, |
6892 | enum isl_dim_type type, unsigned pos, isl_int value) |
6893 | { |
6894 | return isl_map_upper_bound(map: set, type, pos, value); |
6895 | } |
6896 | |
6897 | /* Force the values of the variable at position "pos" of type "type" of "map" |
6898 | * to be no smaller than "value". |
6899 | */ |
6900 | __isl_give isl_map *isl_map_lower_bound_val(__isl_take isl_map *map, |
6901 | enum isl_dim_type type, unsigned pos, __isl_take isl_val *value) |
6902 | { |
6903 | if (!value) |
6904 | goto error; |
6905 | if (!isl_val_is_int(v: value)) |
6906 | isl_die(isl_map_get_ctx(map), isl_error_invalid, |
6907 | "expecting integer value" , goto error); |
6908 | map = isl_map_lower_bound(map, type, pos, value: value->n); |
6909 | isl_val_free(v: value); |
6910 | return map; |
6911 | error: |
6912 | isl_val_free(v: value); |
6913 | isl_map_free(map); |
6914 | return NULL; |
6915 | } |
6916 | |
6917 | /* Force the values of the variable at position "pos" of type "type" of "set" |
6918 | * to be no smaller than "value". |
6919 | */ |
6920 | __isl_give isl_set *isl_set_lower_bound_val(__isl_take isl_set *set, |
6921 | enum isl_dim_type type, unsigned pos, __isl_take isl_val *value) |
6922 | { |
6923 | isl_map *map; |
6924 | |
6925 | map = set_to_map(set); |
6926 | return set_from_map(isl_map_lower_bound_val(map, type, pos, value)); |
6927 | } |
6928 | |
6929 | /* Force the values of the variable at position "pos" of type "type" of "map" |
6930 | * to be no greater than "value". |
6931 | */ |
6932 | __isl_give isl_map *isl_map_upper_bound_val(__isl_take isl_map *map, |
6933 | enum isl_dim_type type, unsigned pos, __isl_take isl_val *value) |
6934 | { |
6935 | if (!value) |
6936 | goto error; |
6937 | if (!isl_val_is_int(v: value)) |
6938 | isl_die(isl_map_get_ctx(map), isl_error_invalid, |
6939 | "expecting integer value" , goto error); |
6940 | map = isl_map_upper_bound(map, type, pos, value: value->n); |
6941 | isl_val_free(v: value); |
6942 | return map; |
6943 | error: |
6944 | isl_val_free(v: value); |
6945 | isl_map_free(map); |
6946 | return NULL; |
6947 | } |
6948 | |
6949 | /* Force the values of the variable at position "pos" of type "type" of "set" |
6950 | * to be no greater than "value". |
6951 | */ |
6952 | __isl_give isl_set *isl_set_upper_bound_val(__isl_take isl_set *set, |
6953 | enum isl_dim_type type, unsigned pos, __isl_take isl_val *value) |
6954 | { |
6955 | isl_map *map; |
6956 | |
6957 | map = set_to_map(set); |
6958 | return set_from_map(isl_map_upper_bound_val(map, type, pos, value)); |
6959 | } |
6960 | |
6961 | /* If "mv" has an explicit domain, then intersect the domain of "map" |
6962 | * with this explicit domain. |
6963 | * |
6964 | * An isl_multi_val object never has an explicit domain, |
6965 | * so simply return "map". |
6966 | */ |
6967 | static __isl_give isl_map *isl_map_intersect_multi_val_explicit_domain( |
6968 | __isl_take isl_map *map, __isl_keep isl_multi_val *mv) |
6969 | { |
6970 | return map; |
6971 | } |
6972 | |
6973 | #undef BASE |
6974 | #define BASE val |
6975 | #include "isl_map_bound_templ.c" |
6976 | |
6977 | /* Apply "map_bound" to "set" with the corresponding value in "bound" |
6978 | * for each set dimension, by treating the set as a map. |
6979 | */ |
6980 | static __isl_give isl_set *set_bound_multi_val(__isl_take isl_set *set, |
6981 | __isl_take isl_multi_val *bound, |
6982 | __isl_give isl_map *map_bound(__isl_take isl_map *map, |
6983 | unsigned pos, __isl_take isl_val *value)) |
6984 | { |
6985 | isl_map *map; |
6986 | |
6987 | map = set_to_map(set); |
6988 | return set_from_map(map_bound_multi_val(map, bound, map_bound)); |
6989 | } |
6990 | |
6991 | #undef BASE |
6992 | #define BASE pw_aff |
6993 | #include "isl_map_bound_templ.c" |
6994 | |
6995 | /* Apply "map_bound" to "set" with the corresponding value in "bound" |
6996 | * for each set dimension, by converting the set and the bound |
6997 | * to objects living in a map space. |
6998 | */ |
6999 | static __isl_give isl_set *set_bound_multi_pw_aff(__isl_take isl_set *set, |
7000 | __isl_take isl_multi_pw_aff *bound, |
7001 | __isl_give isl_map *set_bound(__isl_take isl_map *map, |
7002 | unsigned pos, __isl_take TYPE *value)) |
7003 | { |
7004 | isl_map *map; |
7005 | |
7006 | map = isl_map_from_range(set); |
7007 | bound = isl_multi_pw_aff_from_range(multi: bound); |
7008 | map = map_bound_multi_pw_aff(map, bound, map_bound: set_bound); |
7009 | return isl_map_range(map); |
7010 | } |
7011 | |
7012 | /* Wrapper around isl_map_lower_bound_val for use in map_bound_multi_val, |
7013 | * setting a bound on the given output dimension. |
7014 | */ |
7015 | static __isl_give isl_map *map_lower_bound_val(__isl_take isl_map *map, |
7016 | unsigned pos, __isl_take isl_val *v) |
7017 | { |
7018 | return isl_map_lower_bound_val(map, type: isl_dim_out, pos, value: v); |
7019 | } |
7020 | |
7021 | /* Force the values of the set dimensions of "set" |
7022 | * to be no smaller than the corresponding values in "lower". |
7023 | */ |
7024 | __isl_give isl_set *isl_set_lower_bound_multi_val(__isl_take isl_set *set, |
7025 | __isl_take isl_multi_val *lower) |
7026 | { |
7027 | return set_bound_multi_val(set, bound: lower, map_bound: &map_lower_bound_val); |
7028 | } |
7029 | |
7030 | /* Wrapper around isl_map_upper_bound_val for use in map_bound_multi_val, |
7031 | * setting a bound on the given output dimension. |
7032 | */ |
7033 | static __isl_give isl_map *map_upper_bound_val(__isl_take isl_map *map, |
7034 | unsigned pos, __isl_take isl_val *v) |
7035 | { |
7036 | return isl_map_upper_bound_val(map, type: isl_dim_out, pos, value: v); |
7037 | } |
7038 | |
7039 | /* Force the values of the set dimensions of "set" |
7040 | * to be no greater than the corresponding values in "upper". |
7041 | */ |
7042 | __isl_give isl_set *isl_set_upper_bound_multi_val(__isl_take isl_set *set, |
7043 | __isl_take isl_multi_val *upper) |
7044 | { |
7045 | return set_bound_multi_val(set, bound: upper, map_bound: &map_upper_bound_val); |
7046 | } |
7047 | |
7048 | /* Force the symbolic constant expression "bound" |
7049 | * to satisfy the relation "order" with respect to |
7050 | * the output variable at position "pos" of "map". |
7051 | * |
7052 | * Create an affine expression representing the output variable |
7053 | * in terms of the range and |
7054 | * compare it using "order" to "bound" (defined on the domain). |
7055 | * The result is a relation between elements in domain and range that |
7056 | * can be intersected with "map". |
7057 | */ |
7058 | static __isl_give isl_map *map_bound_pw_aff(__isl_take isl_map *map, |
7059 | unsigned pos, __isl_take isl_pw_aff *bound, |
7060 | __isl_give isl_map *(*order)(__isl_take isl_pw_aff *pa1, |
7061 | __isl_take isl_pw_aff *pa2)) |
7062 | { |
7063 | isl_space *space; |
7064 | isl_local_space *ls; |
7065 | isl_pw_aff *var; |
7066 | |
7067 | space = isl_space_range(space: isl_map_get_space(map)); |
7068 | ls = isl_local_space_from_space(space); |
7069 | var = isl_pw_aff_var_on_domain(ls, type: isl_dim_set, pos); |
7070 | map = isl_map_intersect(map1: map, map2: order(bound, var)); |
7071 | return map; |
7072 | } |
7073 | |
7074 | /* Force the values of the output variable at position "pos" of "map" |
7075 | * to be no smaller than the symbolic constant expression "lower". |
7076 | */ |
7077 | static __isl_give isl_map *map_lower_bound_pw_aff(__isl_take isl_map *map, |
7078 | unsigned pos, __isl_take isl_pw_aff *lower) |
7079 | { |
7080 | return map_bound_pw_aff(map, pos, bound: lower, order: &isl_pw_aff_le_map); |
7081 | } |
7082 | |
7083 | /* Force the values of the output variable at position "pos" of "map" |
7084 | * to be no greater than the symbolic constant expression "upper". |
7085 | */ |
7086 | static __isl_give isl_map *map_upper_bound_pw_aff(__isl_take isl_map *map, |
7087 | unsigned pos, __isl_take isl_pw_aff *upper) |
7088 | { |
7089 | return map_bound_pw_aff(map, pos, bound: upper, order: &isl_pw_aff_ge_map); |
7090 | } |
7091 | |
7092 | /* Force the values of the set dimensions of "set" |
7093 | * to be no smaller than the corresponding constant symbolic expressions |
7094 | * in "lower". |
7095 | */ |
7096 | __isl_give isl_set *isl_set_lower_bound_multi_pw_aff(__isl_take isl_set *set, |
7097 | __isl_take isl_multi_pw_aff *lower) |
7098 | { |
7099 | return set_bound_multi_pw_aff(set, bound: lower, set_bound: &map_lower_bound_pw_aff); |
7100 | } |
7101 | |
7102 | /* Force the values of the set dimensions of "set" |
7103 | * to be no greater than the corresponding constant symbolic expressions |
7104 | * in "upper". |
7105 | */ |
7106 | __isl_give isl_set *isl_set_upper_bound_multi_pw_aff(__isl_take isl_set *set, |
7107 | __isl_take isl_multi_pw_aff *upper) |
7108 | { |
7109 | return set_bound_multi_pw_aff(set, bound: upper, set_bound: &map_upper_bound_pw_aff); |
7110 | } |
7111 | |
7112 | /* Force the values of the output dimensions of "map" |
7113 | * to be no smaller than the corresponding constant symbolic expressions |
7114 | * in "lower". |
7115 | */ |
7116 | __isl_give isl_map *isl_map_lower_bound_multi_pw_aff(__isl_take isl_map *map, |
7117 | __isl_take isl_multi_pw_aff *lower) |
7118 | { |
7119 | return map_bound_multi_pw_aff(map, bound: lower, map_bound: &map_lower_bound_pw_aff); |
7120 | } |
7121 | |
7122 | /* Force the values of the output dimensions of "map" |
7123 | * to be no greater than the corresponding constant symbolic expressions |
7124 | * in "upper". |
7125 | */ |
7126 | __isl_give isl_map *isl_map_upper_bound_multi_pw_aff(__isl_take isl_map *map, |
7127 | __isl_take isl_multi_pw_aff *upper) |
7128 | { |
7129 | return map_bound_multi_pw_aff(map, bound: upper, map_bound: &map_upper_bound_pw_aff); |
7130 | } |
7131 | |
7132 | /* Bound the given variable of "bset" from below (or above is "upper" |
7133 | * is set) to "value". |
7134 | */ |
7135 | static __isl_give isl_basic_set *isl_basic_set_bound( |
7136 | __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos, |
7137 | isl_int value, int upper) |
7138 | { |
7139 | return bset_from_bmap(bmap: basic_map_bound(bmap: bset_to_bmap(bset), |
7140 | type, pos, value, upper)); |
7141 | } |
7142 | |
7143 | /* Bound the given variable of "bset" from below (or above is "upper" |
7144 | * is set) to "value". |
7145 | */ |
7146 | static __isl_give isl_basic_set *isl_basic_set_bound_val( |
7147 | __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos, |
7148 | __isl_take isl_val *value, int upper) |
7149 | { |
7150 | if (!value) |
7151 | goto error; |
7152 | if (!isl_val_is_int(v: value)) |
7153 | isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid, |
7154 | "expecting integer value" , goto error); |
7155 | bset = isl_basic_set_bound(bset, type, pos, value: value->n, upper); |
7156 | isl_val_free(v: value); |
7157 | return bset; |
7158 | error: |
7159 | isl_val_free(v: value); |
7160 | isl_basic_set_free(bset); |
7161 | return NULL; |
7162 | } |
7163 | |
7164 | /* Bound the given variable of "bset" from below to "value". |
7165 | */ |
7166 | __isl_give isl_basic_set *isl_basic_set_lower_bound_val( |
7167 | __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos, |
7168 | __isl_take isl_val *value) |
7169 | { |
7170 | return isl_basic_set_bound_val(bset, type, pos, value, upper: 0); |
7171 | } |
7172 | |
7173 | /* Bound the given variable of "bset" from above to "value". |
7174 | */ |
7175 | __isl_give isl_basic_set *isl_basic_set_upper_bound_val( |
7176 | __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos, |
7177 | __isl_take isl_val *value) |
7178 | { |
7179 | return isl_basic_set_bound_val(bset, type, pos, value, upper: 1); |
7180 | } |
7181 | |
7182 | __isl_give isl_map *isl_map_reverse(__isl_take isl_map *map) |
7183 | { |
7184 | return isl_map_transform(map, fn_space: &isl_space_reverse, |
7185 | fn_bmap: &isl_basic_map_reverse); |
7186 | } |
7187 | |
7188 | /* Given a map A -> (B -> C), return the corresponding map A -> (C -> B). |
7189 | */ |
7190 | __isl_give isl_map *isl_map_range_reverse(__isl_take isl_map *map) |
7191 | { |
7192 | return isl_map_transform(map, fn_space: &isl_space_range_reverse, |
7193 | fn_bmap: &isl_basic_map_range_reverse); |
7194 | } |
7195 | |
7196 | #undef TYPE |
7197 | #define TYPE isl_pw_multi_aff |
7198 | #undef SUFFIX |
7199 | #define SUFFIX _pw_multi_aff |
7200 | #undef EMPTY |
7201 | #define EMPTY isl_pw_multi_aff_empty |
7202 | #undef ADD |
7203 | #define ADD isl_pw_multi_aff_union_add |
7204 | #include "isl_map_lexopt_templ.c" |
7205 | |
7206 | /* Given a map "map", compute the lexicographically minimal |
7207 | * (or maximal) image element for each domain element in dom, |
7208 | * in the form of an isl_pw_multi_aff. |
7209 | * If "empty" is not NULL, then set *empty to those elements in dom that |
7210 | * do not have an image element. |
7211 | * If "flags" includes ISL_OPT_FULL, then "dom" is NULL and the optimum |
7212 | * should be computed over the domain of "map". "empty" is also NULL |
7213 | * in this case. |
7214 | * |
7215 | * We first compute the lexicographically minimal or maximal element |
7216 | * in the first basic map. This results in a partial solution "res" |
7217 | * and a subset "todo" of dom that still need to be handled. |
7218 | * We then consider each of the remaining maps in "map" and successively |
7219 | * update both "res" and "todo". |
7220 | * If "empty" is NULL, then the todo sets are not needed and therefore |
7221 | * also not computed. |
7222 | */ |
7223 | static __isl_give isl_pw_multi_aff *isl_map_partial_lexopt_aligned_pw_multi_aff( |
7224 | __isl_take isl_map *map, __isl_take isl_set *dom, |
7225 | __isl_give isl_set **empty, unsigned flags) |
7226 | { |
7227 | int i; |
7228 | int full; |
7229 | isl_pw_multi_aff *res; |
7230 | isl_set *todo; |
7231 | |
7232 | full = ISL_FL_ISSET(flags, ISL_OPT_FULL); |
7233 | if (!map || (!full && !dom)) |
7234 | goto error; |
7235 | |
7236 | if (isl_map_plain_is_empty(map)) { |
7237 | if (empty) |
7238 | *empty = dom; |
7239 | else |
7240 | isl_set_free(set: dom); |
7241 | return isl_pw_multi_aff_from_map(map); |
7242 | } |
7243 | |
7244 | res = basic_map_partial_lexopt_pw_multi_aff( |
7245 | bmap: isl_basic_map_copy(bmap: map->p[0]), |
7246 | dom: isl_set_copy(set: dom), empty, flags); |
7247 | |
7248 | if (empty) |
7249 | todo = *empty; |
7250 | for (i = 1; i < map->n; ++i) { |
7251 | isl_pw_multi_aff *res_i; |
7252 | |
7253 | res_i = basic_map_partial_lexopt_pw_multi_aff( |
7254 | bmap: isl_basic_map_copy(bmap: map->p[i]), |
7255 | dom: isl_set_copy(set: dom), empty, flags); |
7256 | |
7257 | if (ISL_FL_ISSET(flags, ISL_OPT_MAX)) |
7258 | res = isl_pw_multi_aff_union_lexmax(pma1: res, pma2: res_i); |
7259 | else |
7260 | res = isl_pw_multi_aff_union_lexmin(pma1: res, pma2: res_i); |
7261 | |
7262 | if (empty) |
7263 | todo = isl_set_intersect(set1: todo, set2: *empty); |
7264 | } |
7265 | |
7266 | isl_set_free(set: dom); |
7267 | isl_map_free(map); |
7268 | |
7269 | if (empty) |
7270 | *empty = todo; |
7271 | |
7272 | return res; |
7273 | error: |
7274 | if (empty) |
7275 | *empty = NULL; |
7276 | isl_set_free(set: dom); |
7277 | isl_map_free(map); |
7278 | return NULL; |
7279 | } |
7280 | |
7281 | #undef TYPE |
7282 | #define TYPE isl_map |
7283 | #undef SUFFIX |
7284 | #define SUFFIX |
7285 | #undef EMPTY |
7286 | #define EMPTY isl_map_empty |
7287 | #undef ADD |
7288 | #define ADD isl_map_union_disjoint |
7289 | #include "isl_map_lexopt_templ.c" |
7290 | |
7291 | /* Given a map "map", compute the lexicographically minimal |
7292 | * (or maximal) image element for each domain element in "dom", |
7293 | * in the form of an isl_map. |
7294 | * If "empty" is not NULL, then set *empty to those elements in "dom" that |
7295 | * do not have an image element. |
7296 | * If "flags" includes ISL_OPT_FULL, then "dom" is NULL and the optimum |
7297 | * should be computed over the domain of "map". "empty" is also NULL |
7298 | * in this case. |
7299 | * |
7300 | * If the input consists of more than one disjunct, then first |
7301 | * compute the desired result in the form of an isl_pw_multi_aff and |
7302 | * then convert that into an isl_map. |
7303 | * |
7304 | * This function used to have an explicit implementation in terms |
7305 | * of isl_maps, but it would continually intersect the domains of |
7306 | * partial results with the complement of the domain of the next |
7307 | * partial solution, potentially leading to an explosion in the number |
7308 | * of disjuncts if there are several disjuncts in the input. |
7309 | * An even earlier implementation of this function would look for |
7310 | * better results in the domain of the partial result and for extra |
7311 | * results in the complement of this domain, which would lead to |
7312 | * even more splintering. |
7313 | */ |
7314 | static __isl_give isl_map *isl_map_partial_lexopt_aligned( |
7315 | __isl_take isl_map *map, __isl_take isl_set *dom, |
7316 | __isl_give isl_set **empty, unsigned flags) |
7317 | { |
7318 | int full; |
7319 | struct isl_map *res; |
7320 | isl_pw_multi_aff *pma; |
7321 | |
7322 | full = ISL_FL_ISSET(flags, ISL_OPT_FULL); |
7323 | if (!map || (!full && !dom)) |
7324 | goto error; |
7325 | |
7326 | if (isl_map_plain_is_empty(map)) { |
7327 | if (empty) |
7328 | *empty = dom; |
7329 | else |
7330 | isl_set_free(set: dom); |
7331 | return map; |
7332 | } |
7333 | |
7334 | if (map->n == 1) { |
7335 | res = basic_map_partial_lexopt(bmap: isl_basic_map_copy(bmap: map->p[0]), |
7336 | dom, empty, flags); |
7337 | isl_map_free(map); |
7338 | return res; |
7339 | } |
7340 | |
7341 | pma = isl_map_partial_lexopt_aligned_pw_multi_aff(map, dom, empty, |
7342 | flags); |
7343 | return isl_map_from_pw_multi_aff_internal(pma); |
7344 | error: |
7345 | if (empty) |
7346 | *empty = NULL; |
7347 | isl_set_free(set: dom); |
7348 | isl_map_free(map); |
7349 | return NULL; |
7350 | } |
7351 | |
7352 | __isl_give isl_map *isl_map_partial_lexmax( |
7353 | __isl_take isl_map *map, __isl_take isl_set *dom, |
7354 | __isl_give isl_set **empty) |
7355 | { |
7356 | return isl_map_partial_lexopt(map, dom, empty, ISL_OPT_MAX); |
7357 | } |
7358 | |
7359 | __isl_give isl_map *isl_map_partial_lexmin( |
7360 | __isl_take isl_map *map, __isl_take isl_set *dom, |
7361 | __isl_give isl_set **empty) |
7362 | { |
7363 | return isl_map_partial_lexopt(map, dom, empty, flags: 0); |
7364 | } |
7365 | |
7366 | __isl_give isl_set *isl_set_partial_lexmin( |
7367 | __isl_take isl_set *set, __isl_take isl_set *dom, |
7368 | __isl_give isl_set **empty) |
7369 | { |
7370 | return set_from_map(isl_map_partial_lexmin(map: set_to_map(set), |
7371 | dom, empty)); |
7372 | } |
7373 | |
7374 | __isl_give isl_set *isl_set_partial_lexmax( |
7375 | __isl_take isl_set *set, __isl_take isl_set *dom, |
7376 | __isl_give isl_set **empty) |
7377 | { |
7378 | return set_from_map(isl_map_partial_lexmax(map: set_to_map(set), |
7379 | dom, empty)); |
7380 | } |
7381 | |
7382 | /* Compute the lexicographic minimum (or maximum if "flags" includes |
7383 | * ISL_OPT_MAX) of "bset" over its parametric domain. |
7384 | */ |
7385 | __isl_give isl_set *isl_basic_set_lexopt(__isl_take isl_basic_set *bset, |
7386 | unsigned flags) |
7387 | { |
7388 | return isl_basic_map_lexopt(bmap: bset, flags); |
7389 | } |
7390 | |
7391 | __isl_give isl_map *isl_basic_map_lexmax(__isl_take isl_basic_map *bmap) |
7392 | { |
7393 | return isl_basic_map_lexopt(bmap, ISL_OPT_MAX); |
7394 | } |
7395 | |
7396 | __isl_give isl_set *isl_basic_set_lexmin(__isl_take isl_basic_set *bset) |
7397 | { |
7398 | return set_from_map(isl_basic_map_lexmin(bmap: bset_to_bmap(bset))); |
7399 | } |
7400 | |
7401 | __isl_give isl_set *isl_basic_set_lexmax(__isl_take isl_basic_set *bset) |
7402 | { |
7403 | return set_from_map(isl_basic_map_lexmax(bmap: bset_to_bmap(bset))); |
7404 | } |
7405 | |
7406 | /* Compute the lexicographic minimum of "bset" over its parametric domain |
7407 | * for the purpose of quantifier elimination. |
7408 | * That is, find an explicit representation for all the existentially |
7409 | * quantified variables in "bset" by computing their lexicographic |
7410 | * minimum. |
7411 | */ |
7412 | static __isl_give isl_set *isl_basic_set_lexmin_compute_divs( |
7413 | __isl_take isl_basic_set *bset) |
7414 | { |
7415 | return isl_basic_set_lexopt(bset, ISL_OPT_QE); |
7416 | } |
7417 | |
7418 | /* Given a basic map with one output dimension, compute the minimum or |
7419 | * maximum of that dimension as an isl_pw_aff. |
7420 | * |
7421 | * Compute the optimum as a lexicographic optimum over the single |
7422 | * output dimension and extract the single isl_pw_aff from the result. |
7423 | */ |
7424 | static __isl_give isl_pw_aff *basic_map_dim_opt(__isl_keep isl_basic_map *bmap, |
7425 | int max) |
7426 | { |
7427 | isl_pw_multi_aff *pma; |
7428 | isl_pw_aff *pwaff; |
7429 | |
7430 | bmap = isl_basic_map_copy(bmap); |
7431 | pma = isl_basic_map_lexopt_pw_multi_aff(bmap, flags: max ? ISL_OPT_MAX : 0); |
7432 | pwaff = isl_pw_multi_aff_get_pw_aff(pma, pos: 0); |
7433 | isl_pw_multi_aff_free(pma); |
7434 | |
7435 | return pwaff; |
7436 | } |
7437 | |
7438 | /* Compute the minimum or maximum of the given output dimension |
7439 | * as a function of the parameters and the input dimensions, |
7440 | * but independently of the other output dimensions. |
7441 | * |
7442 | * We first project out the other output dimension and then compute |
7443 | * the "lexicographic" maximum in each basic map, combining the results |
7444 | * using isl_pw_aff_union_max. |
7445 | */ |
7446 | static __isl_give isl_pw_aff *map_dim_opt(__isl_take isl_map *map, int pos, |
7447 | int max) |
7448 | { |
7449 | int i; |
7450 | isl_pw_aff *pwaff; |
7451 | isl_size n_out; |
7452 | |
7453 | n_out = isl_map_dim(map, type: isl_dim_out); |
7454 | if (n_out < 0) |
7455 | map = isl_map_free(map); |
7456 | map = isl_map_project_out(map, type: isl_dim_out, first: pos + 1, n: n_out - (pos + 1)); |
7457 | map = isl_map_project_out(map, type: isl_dim_out, first: 0, n: pos); |
7458 | if (!map) |
7459 | return NULL; |
7460 | |
7461 | if (map->n == 0) { |
7462 | isl_space *space = isl_map_get_space(map); |
7463 | isl_map_free(map); |
7464 | return isl_pw_aff_empty(space); |
7465 | } |
7466 | |
7467 | pwaff = basic_map_dim_opt(bmap: map->p[0], max); |
7468 | for (i = 1; i < map->n; ++i) { |
7469 | isl_pw_aff *pwaff_i; |
7470 | |
7471 | pwaff_i = basic_map_dim_opt(bmap: map->p[i], max); |
7472 | pwaff = isl_pw_aff_union_opt(pwaff1: pwaff, pwaff2: pwaff_i, max); |
7473 | } |
7474 | |
7475 | isl_map_free(map); |
7476 | |
7477 | return pwaff; |
7478 | } |
7479 | |
7480 | /* Compute the minimum of the given output dimension as a function of the |
7481 | * parameters and input dimensions, but independently of |
7482 | * the other output dimensions. |
7483 | */ |
7484 | __isl_give isl_pw_aff *isl_map_dim_min(__isl_take isl_map *map, int pos) |
7485 | { |
7486 | return map_dim_opt(map, pos, max: 0); |
7487 | } |
7488 | |
7489 | /* Compute the maximum of the given output dimension as a function of the |
7490 | * parameters and input dimensions, but independently of |
7491 | * the other output dimensions. |
7492 | */ |
7493 | __isl_give isl_pw_aff *isl_map_dim_max(__isl_take isl_map *map, int pos) |
7494 | { |
7495 | return map_dim_opt(map, pos, max: 1); |
7496 | } |
7497 | |
7498 | /* Compute the minimum or maximum of the given set dimension |
7499 | * as a function of the parameters, |
7500 | * but independently of the other set dimensions. |
7501 | */ |
7502 | static __isl_give isl_pw_aff *set_dim_opt(__isl_take isl_set *set, int pos, |
7503 | int max) |
7504 | { |
7505 | return map_dim_opt(map: set, pos, max); |
7506 | } |
7507 | |
7508 | /* Compute the maximum of the given set dimension as a function of the |
7509 | * parameters, but independently of the other set dimensions. |
7510 | */ |
7511 | __isl_give isl_pw_aff *isl_set_dim_max(__isl_take isl_set *set, int pos) |
7512 | { |
7513 | return set_dim_opt(set, pos, max: 1); |
7514 | } |
7515 | |
7516 | /* Compute the minimum of the given set dimension as a function of the |
7517 | * parameters, but independently of the other set dimensions. |
7518 | */ |
7519 | __isl_give isl_pw_aff *isl_set_dim_min(__isl_take isl_set *set, int pos) |
7520 | { |
7521 | return set_dim_opt(set, pos, max: 0); |
7522 | } |
7523 | |
7524 | /* Apply a preimage specified by "mat" on the parameters of "bset". |
7525 | * bset is assumed to have only parameters and divs. |
7526 | */ |
7527 | static __isl_give isl_basic_set *basic_set_parameter_preimage( |
7528 | __isl_take isl_basic_set *bset, __isl_take isl_mat *mat) |
7529 | { |
7530 | isl_size nparam; |
7531 | |
7532 | nparam = isl_basic_set_dim(bset, type: isl_dim_param); |
7533 | if (nparam < 0 || !mat) |
7534 | goto error; |
7535 | |
7536 | bset->dim = isl_space_cow(space: bset->dim); |
7537 | if (!bset->dim) |
7538 | goto error; |
7539 | |
7540 | isl_assert(bset->ctx, mat->n_row == 1 + nparam, goto error); |
7541 | |
7542 | bset->dim->nparam = 0; |
7543 | bset->dim->n_out = nparam; |
7544 | bset = isl_basic_set_preimage(bset, mat); |
7545 | if (bset) { |
7546 | bset->dim->nparam = bset->dim->n_out; |
7547 | bset->dim->n_out = 0; |
7548 | } |
7549 | return bset; |
7550 | error: |
7551 | isl_mat_free(mat); |
7552 | isl_basic_set_free(bset); |
7553 | return NULL; |
7554 | } |
7555 | |
7556 | /* Apply a preimage specified by "mat" on the parameters of "set". |
7557 | * set is assumed to have only parameters and divs. |
7558 | */ |
7559 | static __isl_give isl_set *set_parameter_preimage(__isl_take isl_set *set, |
7560 | __isl_take isl_mat *mat) |
7561 | { |
7562 | isl_space *space; |
7563 | isl_size nparam; |
7564 | |
7565 | nparam = isl_set_dim(set, type: isl_dim_param); |
7566 | if (nparam < 0 || !mat) |
7567 | goto error; |
7568 | |
7569 | if (mat->n_row != 1 + nparam) |
7570 | isl_die(isl_set_get_ctx(set), isl_error_internal, |
7571 | "unexpected number of rows" , goto error); |
7572 | |
7573 | space = isl_set_get_space(set); |
7574 | space = isl_space_move_dims(space, dst_type: isl_dim_set, dst_pos: 0, |
7575 | src_type: isl_dim_param, src_pos: 0, n: nparam); |
7576 | set = isl_set_reset_space(set, space); |
7577 | set = isl_set_preimage(set, mat); |
7578 | nparam = isl_set_dim(set, type: isl_dim_out); |
7579 | if (nparam < 0) |
7580 | set = isl_set_free(set); |
7581 | space = isl_set_get_space(set); |
7582 | space = isl_space_move_dims(space, dst_type: isl_dim_param, dst_pos: 0, |
7583 | src_type: isl_dim_out, src_pos: 0, n: nparam); |
7584 | set = isl_set_reset_space(set, space); |
7585 | return set; |
7586 | error: |
7587 | isl_mat_free(mat); |
7588 | isl_set_free(set); |
7589 | return NULL; |
7590 | } |
7591 | |
7592 | /* Intersect the basic set "bset" with the affine space specified by the |
7593 | * equalities in "eq". |
7594 | */ |
7595 | static __isl_give isl_basic_set *basic_set_append_equalities( |
7596 | __isl_take isl_basic_set *bset, __isl_take isl_mat *eq) |
7597 | { |
7598 | int i, k; |
7599 | unsigned len; |
7600 | |
7601 | if (!bset || !eq) |
7602 | goto error; |
7603 | |
7604 | bset = isl_basic_set_extend(base: bset, extra: 0, n_eq: eq->n_row, n_ineq: 0); |
7605 | if (!bset) |
7606 | goto error; |
7607 | |
7608 | len = isl_basic_set_offset(bset, type: isl_dim_div) + bset->extra; |
7609 | for (i = 0; i < eq->n_row; ++i) { |
7610 | k = isl_basic_set_alloc_equality(bset); |
7611 | if (k < 0) |
7612 | goto error; |
7613 | isl_seq_cpy(dst: bset->eq[k], src: eq->row[i], len: eq->n_col); |
7614 | isl_seq_clr(p: bset->eq[k] + eq->n_col, len: len - eq->n_col); |
7615 | } |
7616 | isl_mat_free(mat: eq); |
7617 | |
7618 | bset = isl_basic_set_gauss(bset, NULL); |
7619 | bset = isl_basic_set_finalize(bset); |
7620 | |
7621 | return bset; |
7622 | error: |
7623 | isl_mat_free(mat: eq); |
7624 | isl_basic_set_free(bset); |
7625 | return NULL; |
7626 | } |
7627 | |
7628 | /* Intersect the set "set" with the affine space specified by the |
7629 | * equalities in "eq". |
7630 | */ |
7631 | static __isl_give isl_set *set_append_equalities(__isl_take isl_set *set, |
7632 | __isl_take isl_mat *eq) |
7633 | { |
7634 | int i; |
7635 | |
7636 | if (!set || !eq) |
7637 | goto error; |
7638 | |
7639 | for (i = 0; i < set->n; ++i) { |
7640 | set->p[i] = basic_set_append_equalities(bset: set->p[i], |
7641 | eq: isl_mat_copy(mat: eq)); |
7642 | if (!set->p[i]) |
7643 | goto error; |
7644 | } |
7645 | isl_mat_free(mat: eq); |
7646 | return set; |
7647 | error: |
7648 | isl_mat_free(mat: eq); |
7649 | isl_set_free(set); |
7650 | return NULL; |
7651 | } |
7652 | |
7653 | /* Given a basic set "bset" that only involves parameters and existentially |
7654 | * quantified variables, return the index of the first equality |
7655 | * that only involves parameters. If there is no such equality then |
7656 | * return bset->n_eq. |
7657 | * |
7658 | * This function assumes that isl_basic_set_gauss has been called on "bset". |
7659 | */ |
7660 | static int first_parameter_equality(__isl_keep isl_basic_set *bset) |
7661 | { |
7662 | int i, j; |
7663 | isl_size nparam, n_div; |
7664 | |
7665 | nparam = isl_basic_set_dim(bset, type: isl_dim_param); |
7666 | n_div = isl_basic_set_dim(bset, type: isl_dim_div); |
7667 | if (nparam < 0 || n_div < 0) |
7668 | return -1; |
7669 | |
7670 | for (i = 0, j = n_div - 1; i < bset->n_eq && j >= 0; --j) { |
7671 | if (!isl_int_is_zero(bset->eq[i][1 + nparam + j])) |
7672 | ++i; |
7673 | } |
7674 | |
7675 | return i; |
7676 | } |
7677 | |
7678 | /* Compute an explicit representation for the existentially quantified |
7679 | * variables in "bset" by computing the "minimal value" of the set |
7680 | * variables. Since there are no set variables, the computation of |
7681 | * the minimal value essentially computes an explicit representation |
7682 | * of the non-empty part(s) of "bset". |
7683 | * |
7684 | * The input only involves parameters and existentially quantified variables. |
7685 | * All equalities among parameters have been removed. |
7686 | * |
7687 | * Since the existentially quantified variables in the result are in general |
7688 | * going to be different from those in the input, we first replace |
7689 | * them by the minimal number of variables based on their equalities. |
7690 | * This should simplify the parametric integer programming. |
7691 | */ |
7692 | static __isl_give isl_set *base_compute_divs(__isl_take isl_basic_set *bset) |
7693 | { |
7694 | isl_morph *morph1, *morph2; |
7695 | isl_set *set; |
7696 | isl_size n; |
7697 | |
7698 | if (!bset) |
7699 | return NULL; |
7700 | if (bset->n_eq == 0) |
7701 | return isl_basic_set_lexmin_compute_divs(bset); |
7702 | |
7703 | morph1 = isl_basic_set_parameter_compression(bset); |
7704 | bset = isl_morph_basic_set(morph: isl_morph_copy(morph: morph1), bset); |
7705 | bset = isl_basic_set_lift(bset); |
7706 | morph2 = isl_basic_set_variable_compression(bset, type: isl_dim_set); |
7707 | bset = isl_morph_basic_set(morph: morph2, bset); |
7708 | n = isl_basic_set_dim(bset, type: isl_dim_set); |
7709 | if (n < 0) |
7710 | bset = isl_basic_set_free(bset); |
7711 | bset = isl_basic_set_project_out(bset, type: isl_dim_set, first: 0, n); |
7712 | |
7713 | set = isl_basic_set_lexmin_compute_divs(bset); |
7714 | |
7715 | set = isl_morph_set(morph: isl_morph_inverse(morph: morph1), set); |
7716 | |
7717 | return set; |
7718 | } |
7719 | |
7720 | /* Project the given basic set onto its parameter domain, possibly introducing |
7721 | * new, explicit, existential variables in the constraints. |
7722 | * The input has parameters and (possibly implicit) existential variables. |
7723 | * The output has the same parameters, but only |
7724 | * explicit existentially quantified variables. |
7725 | * |
7726 | * The actual projection is performed by pip, but pip doesn't seem |
7727 | * to like equalities very much, so we first remove the equalities |
7728 | * among the parameters by performing a variable compression on |
7729 | * the parameters. Afterward, an inverse transformation is performed |
7730 | * and the equalities among the parameters are inserted back in. |
7731 | * |
7732 | * The variable compression on the parameters may uncover additional |
7733 | * equalities that were only implicit before. We therefore check |
7734 | * if there are any new parameter equalities in the result and |
7735 | * if so recurse. The removal of parameter equalities is required |
7736 | * for the parameter compression performed by base_compute_divs. |
7737 | */ |
7738 | static __isl_give isl_set *parameter_compute_divs( |
7739 | __isl_take isl_basic_set *bset) |
7740 | { |
7741 | int i; |
7742 | struct isl_mat *eq; |
7743 | struct isl_mat *T, *T2; |
7744 | struct isl_set *set; |
7745 | isl_size nparam; |
7746 | |
7747 | bset = isl_basic_set_cow(bset); |
7748 | if (!bset) |
7749 | return NULL; |
7750 | |
7751 | if (bset->n_eq == 0) |
7752 | return base_compute_divs(bset); |
7753 | |
7754 | bset = isl_basic_set_gauss(bset, NULL); |
7755 | if (!bset) |
7756 | return NULL; |
7757 | if (isl_basic_set_plain_is_empty(bset)) |
7758 | return isl_set_from_basic_set(bset); |
7759 | |
7760 | i = first_parameter_equality(bset); |
7761 | if (i == bset->n_eq) |
7762 | return base_compute_divs(bset); |
7763 | |
7764 | nparam = isl_basic_set_dim(bset, type: isl_dim_param); |
7765 | if (nparam < 0) |
7766 | return isl_set_from_basic_set(bset: isl_basic_set_free(bset)); |
7767 | eq = isl_mat_sub_alloc6(ctx: bset->ctx, row: bset->eq, first_row: i, n_row: bset->n_eq - i, |
7768 | first_col: 0, n_col: 1 + nparam); |
7769 | eq = isl_mat_cow(mat: eq); |
7770 | T = isl_mat_variable_compression(B: isl_mat_copy(mat: eq), T2: &T2); |
7771 | if (T && T->n_col == 0) { |
7772 | isl_mat_free(mat: T); |
7773 | isl_mat_free(mat: T2); |
7774 | isl_mat_free(mat: eq); |
7775 | bset = isl_basic_set_set_to_empty(bset); |
7776 | return isl_set_from_basic_set(bset); |
7777 | } |
7778 | bset = basic_set_parameter_preimage(bset, mat: T); |
7779 | |
7780 | i = first_parameter_equality(bset); |
7781 | if (!bset) |
7782 | set = NULL; |
7783 | else if (i == bset->n_eq) |
7784 | set = base_compute_divs(bset); |
7785 | else |
7786 | set = parameter_compute_divs(bset); |
7787 | set = set_parameter_preimage(set, mat: T2); |
7788 | set = set_append_equalities(set, eq); |
7789 | return set; |
7790 | } |
7791 | |
7792 | /* Insert the divs from "ls" before those of "bmap". |
7793 | * |
7794 | * The number of columns is not changed, which means that the last |
7795 | * dimensions of "bmap" are being reintepreted as the divs from "ls". |
7796 | * The caller is responsible for removing the same number of dimensions |
7797 | * from the space of "bmap". |
7798 | */ |
7799 | static __isl_give isl_basic_map *insert_divs_from_local_space( |
7800 | __isl_take isl_basic_map *bmap, __isl_keep isl_local_space *ls) |
7801 | { |
7802 | int i; |
7803 | isl_size n_div; |
7804 | int old_n_div; |
7805 | |
7806 | n_div = isl_local_space_dim(ls, type: isl_dim_div); |
7807 | if (n_div < 0) |
7808 | return isl_basic_map_free(bmap); |
7809 | if (n_div == 0) |
7810 | return bmap; |
7811 | |
7812 | old_n_div = bmap->n_div; |
7813 | bmap = insert_div_rows(bmap, n: n_div); |
7814 | if (!bmap) |
7815 | return NULL; |
7816 | |
7817 | for (i = 0; i < n_div; ++i) { |
7818 | isl_seq_cpy(dst: bmap->div[i], src: ls->div->row[i], len: ls->div->n_col); |
7819 | isl_seq_clr(p: bmap->div[i] + ls->div->n_col, len: old_n_div); |
7820 | } |
7821 | |
7822 | return bmap; |
7823 | } |
7824 | |
7825 | /* Replace the space of "bmap" by the space and divs of "ls". |
7826 | * |
7827 | * If "ls" has any divs, then we simplify the result since we may |
7828 | * have discovered some additional equalities that could simplify |
7829 | * the div expressions. |
7830 | */ |
7831 | static __isl_give isl_basic_map *basic_replace_space_by_local_space( |
7832 | __isl_take isl_basic_map *bmap, __isl_take isl_local_space *ls) |
7833 | { |
7834 | isl_size n_div; |
7835 | |
7836 | bmap = isl_basic_map_cow(bmap); |
7837 | n_div = isl_local_space_dim(ls, type: isl_dim_div); |
7838 | if (!bmap || n_div < 0) |
7839 | goto error; |
7840 | |
7841 | bmap = insert_divs_from_local_space(bmap, ls); |
7842 | if (!bmap) |
7843 | goto error; |
7844 | |
7845 | isl_space_free(space: bmap->dim); |
7846 | bmap->dim = isl_local_space_get_space(ls); |
7847 | if (!bmap->dim) |
7848 | goto error; |
7849 | |
7850 | isl_local_space_free(ls); |
7851 | if (n_div > 0) |
7852 | bmap = isl_basic_map_simplify(bmap); |
7853 | bmap = isl_basic_map_finalize(bmap); |
7854 | return bmap; |
7855 | error: |
7856 | isl_basic_map_free(bmap); |
7857 | isl_local_space_free(ls); |
7858 | return NULL; |
7859 | } |
7860 | |
7861 | /* Replace the space of "map" by the space and divs of "ls". |
7862 | */ |
7863 | static __isl_give isl_map *replace_space_by_local_space(__isl_take isl_map *map, |
7864 | __isl_take isl_local_space *ls) |
7865 | { |
7866 | int i; |
7867 | |
7868 | map = isl_map_cow(map); |
7869 | if (!map || !ls) |
7870 | goto error; |
7871 | |
7872 | for (i = 0; i < map->n; ++i) { |
7873 | map->p[i] = basic_replace_space_by_local_space(bmap: map->p[i], |
7874 | ls: isl_local_space_copy(ls)); |
7875 | if (!map->p[i]) |
7876 | goto error; |
7877 | } |
7878 | isl_space_free(space: isl_map_take_space(map)); |
7879 | map = isl_map_restore_space(map, space: isl_local_space_get_space(ls)); |
7880 | |
7881 | isl_local_space_free(ls); |
7882 | return map; |
7883 | error: |
7884 | isl_local_space_free(ls); |
7885 | isl_map_free(map); |
7886 | return NULL; |
7887 | } |
7888 | |
7889 | /* Compute an explicit representation for the existentially |
7890 | * quantified variables for which do not know any explicit representation yet. |
7891 | * |
7892 | * We first sort the existentially quantified variables so that the |
7893 | * existentially quantified variables for which we already have an explicit |
7894 | * representation are placed before those for which we do not. |
7895 | * The input dimensions, the output dimensions and the existentially |
7896 | * quantified variables for which we already have an explicit |
7897 | * representation are then turned into parameters. |
7898 | * compute_divs returns a map with the same parameters and |
7899 | * no input or output dimensions and the dimension specification |
7900 | * is reset to that of the input, including the existentially quantified |
7901 | * variables for which we already had an explicit representation. |
7902 | */ |
7903 | static __isl_give isl_map *compute_divs(__isl_take isl_basic_map *bmap) |
7904 | { |
7905 | struct isl_basic_set *bset; |
7906 | struct isl_set *set; |
7907 | struct isl_map *map; |
7908 | isl_space *space; |
7909 | isl_local_space *ls; |
7910 | isl_size nparam; |
7911 | isl_size n_in; |
7912 | isl_size n_out; |
7913 | int n_known; |
7914 | int i; |
7915 | |
7916 | bmap = isl_basic_map_sort_divs(bmap); |
7917 | bmap = isl_basic_map_cow(bmap); |
7918 | if (!bmap) |
7919 | return NULL; |
7920 | |
7921 | n_known = isl_basic_map_first_unknown_div(bmap); |
7922 | nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
7923 | n_in = isl_basic_map_dim(bmap, type: isl_dim_in); |
7924 | n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
7925 | if (n_known < 0 || nparam < 0 || n_in < 0 || n_out < 0) |
7926 | return isl_map_from_basic_map(bmap: isl_basic_map_free(bmap)); |
7927 | |
7928 | space = isl_space_set_alloc(ctx: bmap->ctx, |
7929 | nparam: nparam + n_in + n_out + n_known, dim: 0); |
7930 | if (!space) |
7931 | goto error; |
7932 | |
7933 | ls = isl_basic_map_get_local_space(bmap); |
7934 | ls = isl_local_space_drop_dims(ls, type: isl_dim_div, |
7935 | first: n_known, n: bmap->n_div - n_known); |
7936 | if (n_known > 0) { |
7937 | for (i = n_known; i < bmap->n_div; ++i) |
7938 | swap_div(bmap, a: i - n_known, b: i); |
7939 | bmap->n_div -= n_known; |
7940 | bmap->extra -= n_known; |
7941 | } |
7942 | bmap = isl_basic_map_reset_space(bmap, space); |
7943 | bset = bset_from_bmap(bmap); |
7944 | |
7945 | set = parameter_compute_divs(bset); |
7946 | map = set_to_map(set); |
7947 | map = replace_space_by_local_space(map, ls); |
7948 | |
7949 | return map; |
7950 | error: |
7951 | isl_basic_map_free(bmap); |
7952 | return NULL; |
7953 | } |
7954 | |
7955 | /* Remove the explicit representation of local variable "div", |
7956 | * if there is any. |
7957 | */ |
7958 | __isl_give isl_basic_map *isl_basic_map_mark_div_unknown( |
7959 | __isl_take isl_basic_map *bmap, int div) |
7960 | { |
7961 | isl_bool unknown; |
7962 | |
7963 | unknown = isl_basic_map_div_is_marked_unknown(bmap, div); |
7964 | if (unknown < 0) |
7965 | return isl_basic_map_free(bmap); |
7966 | if (unknown) |
7967 | return bmap; |
7968 | |
7969 | bmap = isl_basic_map_cow(bmap); |
7970 | if (!bmap) |
7971 | return NULL; |
7972 | isl_int_set_si(bmap->div[div][0], 0); |
7973 | return bmap; |
7974 | } |
7975 | |
7976 | /* Is local variable "div" of "bmap" marked as not having an explicit |
7977 | * representation? |
7978 | * Note that even if "div" is not marked in this way and therefore |
7979 | * has an explicit representation, this representation may still |
7980 | * depend (indirectly) on other local variables that do not |
7981 | * have an explicit representation. |
7982 | */ |
7983 | isl_bool isl_basic_map_div_is_marked_unknown(__isl_keep isl_basic_map *bmap, |
7984 | int div) |
7985 | { |
7986 | if (isl_basic_map_check_range(obj: bmap, type: isl_dim_div, first: div, n: 1) < 0) |
7987 | return isl_bool_error; |
7988 | return isl_int_is_zero(bmap->div[div][0]); |
7989 | } |
7990 | |
7991 | /* Return the position of the first local variable that does not |
7992 | * have an explicit representation. |
7993 | * Return the total number of local variables if they all have |
7994 | * an explicit representation. |
7995 | * Return -1 on error. |
7996 | */ |
7997 | int isl_basic_map_first_unknown_div(__isl_keep isl_basic_map *bmap) |
7998 | { |
7999 | int i; |
8000 | |
8001 | if (!bmap) |
8002 | return -1; |
8003 | |
8004 | for (i = 0; i < bmap->n_div; ++i) { |
8005 | if (!isl_basic_map_div_is_known(bmap, div: i)) |
8006 | return i; |
8007 | } |
8008 | return bmap->n_div; |
8009 | } |
8010 | |
8011 | /* Return the position of the first local variable that does not |
8012 | * have an explicit representation. |
8013 | * Return the total number of local variables if they all have |
8014 | * an explicit representation. |
8015 | * Return -1 on error. |
8016 | */ |
8017 | int isl_basic_set_first_unknown_div(__isl_keep isl_basic_set *bset) |
8018 | { |
8019 | return isl_basic_map_first_unknown_div(bmap: bset); |
8020 | } |
8021 | |
8022 | /* Does "bmap" have an explicit representation for all local variables? |
8023 | */ |
8024 | isl_bool isl_basic_map_divs_known(__isl_keep isl_basic_map *bmap) |
8025 | { |
8026 | int first; |
8027 | isl_size n; |
8028 | |
8029 | n = isl_basic_map_dim(bmap, type: isl_dim_div); |
8030 | first = isl_basic_map_first_unknown_div(bmap); |
8031 | if (n < 0 || first < 0) |
8032 | return isl_bool_error; |
8033 | return first == n; |
8034 | } |
8035 | |
8036 | /* Do all basic maps in "map" have an explicit representation |
8037 | * for all local variables? |
8038 | */ |
8039 | isl_bool isl_map_divs_known(__isl_keep isl_map *map) |
8040 | { |
8041 | int i; |
8042 | |
8043 | if (!map) |
8044 | return isl_bool_error; |
8045 | |
8046 | for (i = 0; i < map->n; ++i) { |
8047 | int known = isl_basic_map_divs_known(bmap: map->p[i]); |
8048 | if (known <= 0) |
8049 | return known; |
8050 | } |
8051 | |
8052 | return isl_bool_true; |
8053 | } |
8054 | |
8055 | /* If bmap contains any unknown divs, then compute explicit |
8056 | * expressions for them. However, this computation may be |
8057 | * quite expensive, so first try to remove divs that aren't |
8058 | * strictly needed. |
8059 | */ |
8060 | __isl_give isl_map *isl_basic_map_compute_divs(__isl_take isl_basic_map *bmap) |
8061 | { |
8062 | int known; |
8063 | struct isl_map *map; |
8064 | |
8065 | known = isl_basic_map_divs_known(bmap); |
8066 | if (known < 0) |
8067 | goto error; |
8068 | if (known) |
8069 | return isl_map_from_basic_map(bmap); |
8070 | |
8071 | bmap = isl_basic_map_drop_redundant_divs(bmap); |
8072 | |
8073 | known = isl_basic_map_divs_known(bmap); |
8074 | if (known < 0) |
8075 | goto error; |
8076 | if (known) |
8077 | return isl_map_from_basic_map(bmap); |
8078 | |
8079 | map = compute_divs(bmap); |
8080 | return map; |
8081 | error: |
8082 | isl_basic_map_free(bmap); |
8083 | return NULL; |
8084 | } |
8085 | |
8086 | __isl_give isl_map *isl_map_compute_divs(__isl_take isl_map *map) |
8087 | { |
8088 | int i; |
8089 | int known; |
8090 | struct isl_map *res; |
8091 | |
8092 | if (!map) |
8093 | return NULL; |
8094 | if (map->n == 0) |
8095 | return map; |
8096 | |
8097 | known = isl_map_divs_known(map); |
8098 | if (known < 0) { |
8099 | isl_map_free(map); |
8100 | return NULL; |
8101 | } |
8102 | if (known) |
8103 | return map; |
8104 | |
8105 | res = isl_basic_map_compute_divs(bmap: isl_basic_map_copy(bmap: map->p[0])); |
8106 | for (i = 1 ; i < map->n; ++i) { |
8107 | struct isl_map *r2; |
8108 | r2 = isl_basic_map_compute_divs(bmap: isl_basic_map_copy(bmap: map->p[i])); |
8109 | if (ISL_F_ISSET(map, ISL_MAP_DISJOINT)) |
8110 | res = isl_map_union_disjoint(map1: res, map2: r2); |
8111 | else |
8112 | res = isl_map_union(map1: res, map2: r2); |
8113 | } |
8114 | isl_map_free(map); |
8115 | |
8116 | return res; |
8117 | } |
8118 | |
8119 | __isl_give isl_set *isl_basic_set_compute_divs(__isl_take isl_basic_set *bset) |
8120 | { |
8121 | return set_from_map(isl_basic_map_compute_divs(bmap: bset_to_bmap(bset))); |
8122 | } |
8123 | |
8124 | __isl_give isl_set *isl_set_compute_divs(__isl_take isl_set *set) |
8125 | { |
8126 | return set_from_map(isl_map_compute_divs(map: set_to_map(set))); |
8127 | } |
8128 | |
8129 | __isl_give isl_set *isl_map_domain(__isl_take isl_map *map) |
8130 | { |
8131 | isl_space *space; |
8132 | isl_size n_out; |
8133 | |
8134 | n_out = isl_map_dim(map, type: isl_dim_out); |
8135 | if (n_out < 0) |
8136 | return set_from_map(isl_map_free(map)); |
8137 | space = isl_space_domain(space: isl_map_get_space(map)); |
8138 | |
8139 | map = isl_map_project_out(map, type: isl_dim_out, first: 0, n: n_out); |
8140 | |
8141 | return set_from_map(isl_map_reset_space(map, space)); |
8142 | } |
8143 | |
8144 | /* Return the union of "map1" and "map2", where we assume for now that |
8145 | * "map1" and "map2" are disjoint. Note that the basic maps inside |
8146 | * "map1" or "map2" may not be disjoint from each other. |
8147 | * Also note that this function is also called from isl_map_union, |
8148 | * which takes care of handling the situation where "map1" and "map2" |
8149 | * may not be disjoint. |
8150 | * |
8151 | * If one of the inputs is empty, we can simply return the other input. |
8152 | * Similarly, if one of the inputs is universal, then it is equal to the union. |
8153 | */ |
8154 | static __isl_give isl_map *map_union_disjoint(__isl_take isl_map *map1, |
8155 | __isl_take isl_map *map2) |
8156 | { |
8157 | int i; |
8158 | unsigned flags = 0; |
8159 | struct isl_map *map = NULL; |
8160 | int is_universe; |
8161 | |
8162 | if (isl_map_check_equal_space(map1, map2) < 0) |
8163 | goto error; |
8164 | |
8165 | if (map1->n == 0) { |
8166 | isl_map_free(map: map1); |
8167 | return map2; |
8168 | } |
8169 | if (map2->n == 0) { |
8170 | isl_map_free(map: map2); |
8171 | return map1; |
8172 | } |
8173 | |
8174 | is_universe = isl_map_plain_is_universe(map: map1); |
8175 | if (is_universe < 0) |
8176 | goto error; |
8177 | if (is_universe) { |
8178 | isl_map_free(map: map2); |
8179 | return map1; |
8180 | } |
8181 | |
8182 | is_universe = isl_map_plain_is_universe(map: map2); |
8183 | if (is_universe < 0) |
8184 | goto error; |
8185 | if (is_universe) { |
8186 | isl_map_free(map: map1); |
8187 | return map2; |
8188 | } |
8189 | |
8190 | if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) && |
8191 | ISL_F_ISSET(map2, ISL_MAP_DISJOINT)) |
8192 | ISL_FL_SET(flags, ISL_MAP_DISJOINT); |
8193 | |
8194 | map = isl_map_alloc_space(space: isl_space_copy(space: map1->dim), |
8195 | n: map1->n + map2->n, flags); |
8196 | if (!map) |
8197 | goto error; |
8198 | for (i = 0; i < map1->n; ++i) { |
8199 | map = isl_map_add_basic_map(map, |
8200 | bmap: isl_basic_map_copy(bmap: map1->p[i])); |
8201 | if (!map) |
8202 | goto error; |
8203 | } |
8204 | for (i = 0; i < map2->n; ++i) { |
8205 | map = isl_map_add_basic_map(map, |
8206 | bmap: isl_basic_map_copy(bmap: map2->p[i])); |
8207 | if (!map) |
8208 | goto error; |
8209 | } |
8210 | isl_map_free(map: map1); |
8211 | isl_map_free(map: map2); |
8212 | return map; |
8213 | error: |
8214 | isl_map_free(map); |
8215 | isl_map_free(map: map1); |
8216 | isl_map_free(map: map2); |
8217 | return NULL; |
8218 | } |
8219 | |
8220 | /* Return the union of "map1" and "map2", where "map1" and "map2" are |
8221 | * guaranteed to be disjoint by the caller. |
8222 | * |
8223 | * Note that this functions is called from within isl_map_make_disjoint, |
8224 | * so we have to be careful not to touch the constraints of the inputs |
8225 | * in any way. |
8226 | */ |
8227 | __isl_give isl_map *isl_map_union_disjoint(__isl_take isl_map *map1, |
8228 | __isl_take isl_map *map2) |
8229 | { |
8230 | isl_map_align_params_bin(obj1: &map1, obj2: &map2); |
8231 | return map_union_disjoint(map1, map2); |
8232 | } |
8233 | |
8234 | /* Return the union of "map1" and "map2", where "map1" and "map2" may |
8235 | * not be disjoint. |
8236 | * |
8237 | * We currently simply call map_union_disjoint, the internal operation |
8238 | * of which does not really depend on the inputs being disjoint. |
8239 | * If the result contains more than one basic map, then we clear |
8240 | * the disjoint flag since the result may contain basic maps from |
8241 | * both inputs and these are not guaranteed to be disjoint. |
8242 | * |
8243 | * As a special case, if "map1" and "map2" are obviously equal, |
8244 | * then we simply return "map1". |
8245 | */ |
8246 | __isl_give isl_map *isl_map_union(__isl_take isl_map *map1, |
8247 | __isl_take isl_map *map2) |
8248 | { |
8249 | int equal; |
8250 | |
8251 | if (isl_map_align_params_bin(obj1: &map1, obj2: &map2) < 0) |
8252 | goto error; |
8253 | |
8254 | equal = isl_map_plain_is_equal(map1, map2); |
8255 | if (equal < 0) |
8256 | goto error; |
8257 | if (equal) { |
8258 | isl_map_free(map: map2); |
8259 | return map1; |
8260 | } |
8261 | |
8262 | map1 = map_union_disjoint(map1, map2); |
8263 | if (!map1) |
8264 | return NULL; |
8265 | if (map1->n > 1) |
8266 | ISL_F_CLR(map1, ISL_MAP_DISJOINT); |
8267 | return map1; |
8268 | error: |
8269 | isl_map_free(map: map1); |
8270 | isl_map_free(map: map2); |
8271 | return NULL; |
8272 | } |
8273 | |
8274 | __isl_give isl_set *isl_set_union_disjoint( |
8275 | __isl_take isl_set *set1, __isl_take isl_set *set2) |
8276 | { |
8277 | return set_from_map(isl_map_union_disjoint(map1: set_to_map(set1), |
8278 | map2: set_to_map(set2))); |
8279 | } |
8280 | |
8281 | __isl_give isl_set *isl_set_union(__isl_take isl_set *set1, |
8282 | __isl_take isl_set *set2) |
8283 | { |
8284 | return set_from_map(isl_map_union(map1: set_to_map(set1), map2: set_to_map(set2))); |
8285 | } |
8286 | |
8287 | /* Apply "fn" to pairs of elements from "map" and "set" and collect |
8288 | * the results in a map living in "space". |
8289 | * |
8290 | * "map" and "set" are assumed to be compatible and non-NULL. |
8291 | */ |
8292 | static __isl_give isl_map *map_intersect_set(__isl_take isl_map *map, |
8293 | __isl_take isl_space *space, __isl_take isl_set *set, |
8294 | __isl_give isl_basic_map *fn(__isl_take isl_basic_map *bmap, |
8295 | __isl_take isl_basic_set *bset)) |
8296 | { |
8297 | unsigned flags = 0; |
8298 | struct isl_map *result; |
8299 | int i, j; |
8300 | |
8301 | if (isl_set_plain_is_universe(set)) { |
8302 | isl_set_free(set); |
8303 | return isl_map_reset_equal_dim_space(map, space); |
8304 | } |
8305 | |
8306 | if (ISL_F_ISSET(map, ISL_MAP_DISJOINT) && |
8307 | ISL_F_ISSET(set, ISL_MAP_DISJOINT)) |
8308 | ISL_FL_SET(flags, ISL_MAP_DISJOINT); |
8309 | |
8310 | result = isl_map_alloc_space(space, n: map->n * set->n, flags); |
8311 | for (i = 0; result && i < map->n; ++i) |
8312 | for (j = 0; j < set->n; ++j) { |
8313 | result = isl_map_add_basic_map(map: result, |
8314 | bmap: fn(isl_basic_map_copy(bmap: map->p[i]), |
8315 | isl_basic_set_copy(bset: set->p[j]))); |
8316 | if (!result) |
8317 | break; |
8318 | } |
8319 | |
8320 | isl_map_free(map); |
8321 | isl_set_free(set); |
8322 | return result; |
8323 | } |
8324 | |
8325 | __isl_give isl_map *isl_map_intersect_range(__isl_take isl_map *map, |
8326 | __isl_take isl_set *set) |
8327 | { |
8328 | isl_bool ok; |
8329 | isl_space *space; |
8330 | |
8331 | isl_map_align_params_set(obj1: &map, obj2: &set); |
8332 | ok = isl_map_compatible_range(map, set); |
8333 | if (ok < 0) |
8334 | goto error; |
8335 | if (!ok) |
8336 | isl_die(set->ctx, isl_error_invalid, |
8337 | "incompatible spaces" , goto error); |
8338 | |
8339 | space = isl_map_get_space(map); |
8340 | return map_intersect_set(map, space, set, |
8341 | fn: &isl_basic_map_intersect_range); |
8342 | error: |
8343 | isl_map_free(map); |
8344 | isl_set_free(set); |
8345 | return NULL; |
8346 | } |
8347 | |
8348 | /* Intersect the domain of "map" with "set". |
8349 | * |
8350 | * If the domain dimensions of "map" do not have any identifiers, |
8351 | * then copy them over from "set". |
8352 | */ |
8353 | __isl_give isl_map *isl_map_intersect_domain(__isl_take isl_map *map, |
8354 | __isl_take isl_set *set) |
8355 | { |
8356 | isl_bool ok; |
8357 | isl_space *space; |
8358 | |
8359 | isl_map_align_params_set(obj1: &map, obj2: &set); |
8360 | ok = isl_map_compatible_domain(map, set); |
8361 | if (ok < 0) |
8362 | goto error; |
8363 | if (!ok) |
8364 | isl_die(set->ctx, isl_error_invalid, |
8365 | "incompatible spaces" , goto error); |
8366 | |
8367 | space = isl_map_get_space(map); |
8368 | space = isl_space_copy_ids_if_unset(dst: space, dst_type: isl_dim_in, |
8369 | src: isl_set_peek_space(set), src_type: isl_dim_set); |
8370 | return map_intersect_set(map, space, set, |
8371 | fn: &isl_basic_map_intersect_domain); |
8372 | error: |
8373 | isl_map_free(map); |
8374 | isl_set_free(set); |
8375 | return NULL; |
8376 | } |
8377 | |
8378 | #undef TYPE |
8379 | #define TYPE isl_map |
8380 | static |
8381 | #include "isl_copy_tuple_id_templ.c" |
8382 | |
8383 | /* Data structure that specifies how isl_map_intersect_factor |
8384 | * should operate. |
8385 | * |
8386 | * "preserve_type" is the tuple where the factor differs from |
8387 | * the input map and of which the identifiers needs |
8388 | * to be preserved explicitly. |
8389 | * "other_factor" is used to extract the space of the other factor |
8390 | * from the space of the product ("map"). |
8391 | * "product" is used to combine the given factor and a universe map |
8392 | * in the space returned by "other_factor" to produce a map |
8393 | * that lives in the same space as the input map. |
8394 | */ |
8395 | struct isl_intersect_factor_control { |
8396 | enum isl_dim_type preserve_type; |
8397 | __isl_give isl_space *(*other_factor)(__isl_take isl_space *space); |
8398 | __isl_give isl_map *(*product)(__isl_take isl_map *factor, |
8399 | __isl_take isl_map *other); |
8400 | }; |
8401 | |
8402 | /* Given a map "map" in some product space and a map "factor" |
8403 | * living in some factor space, return the intersection. |
8404 | * |
8405 | * After aligning the parameters, |
8406 | * the map "factor" is first extended to a map living in the same space |
8407 | * as "map" and then a regular intersection is computed. |
8408 | * |
8409 | * Note that the extension is computed as a product, which is anonymous |
8410 | * by default. If "map" has an identifier on the corresponding tuple, |
8411 | * then this identifier needs to be set on the product |
8412 | * before the intersection is computed. |
8413 | */ |
8414 | static __isl_give isl_map *isl_map_intersect_factor( |
8415 | __isl_take isl_map *map, __isl_take isl_map *factor, |
8416 | struct isl_intersect_factor_control *control) |
8417 | { |
8418 | isl_bool equal; |
8419 | isl_space *space; |
8420 | isl_map *other, *product; |
8421 | |
8422 | equal = isl_map_has_equal_params(map1: map, map2: factor); |
8423 | if (equal < 0) |
8424 | goto error; |
8425 | if (!equal) { |
8426 | map = isl_map_align_params(map, model: isl_map_get_space(map: factor)); |
8427 | factor = isl_map_align_params(map: factor, model: isl_map_get_space(map)); |
8428 | } |
8429 | |
8430 | space = isl_map_get_space(map); |
8431 | other = isl_map_universe(space: control->other_factor(space)); |
8432 | product = control->product(factor, other); |
8433 | |
8434 | space = isl_map_peek_space(map); |
8435 | product = isl_map_copy_tuple_id(dst: product, dst_type: control->preserve_type, |
8436 | src: space, src_type: control->preserve_type); |
8437 | return map_intersect(map1: map, map2: product); |
8438 | error: |
8439 | isl_map_free(map); |
8440 | isl_map_free(map: factor); |
8441 | return NULL; |
8442 | } |
8443 | |
8444 | /* Return the domain product of "map2" and "map1". |
8445 | */ |
8446 | static __isl_give isl_map *isl_map_reverse_domain_product( |
8447 | __isl_take isl_map *map1, __isl_take isl_map *map2) |
8448 | { |
8449 | return isl_map_domain_product(map1: map2, map2: map1); |
8450 | } |
8451 | |
8452 | /* Return the range product of "map2" and "map1". |
8453 | */ |
8454 | static __isl_give isl_map *isl_map_reverse_range_product( |
8455 | __isl_take isl_map *map1, __isl_take isl_map *map2) |
8456 | { |
8457 | return isl_map_range_product(map1: map2, map2: map1); |
8458 | } |
8459 | |
8460 | /* Given a map "map" in a space [A -> B] -> C and a map "factor" |
8461 | * in the space A -> C, return the intersection. |
8462 | */ |
8463 | __isl_give isl_map *isl_map_intersect_domain_factor_domain( |
8464 | __isl_take isl_map *map, __isl_take isl_map *factor) |
8465 | { |
8466 | struct isl_intersect_factor_control control = { |
8467 | .preserve_type = isl_dim_in, |
8468 | .other_factor = isl_space_domain_factor_range, |
8469 | .product = isl_map_domain_product, |
8470 | }; |
8471 | |
8472 | return isl_map_intersect_factor(map, factor, control: &control); |
8473 | } |
8474 | |
8475 | /* Given a map "map" in a space [A -> B] -> C and a map "factor" |
8476 | * in the space B -> C, return the intersection. |
8477 | */ |
8478 | __isl_give isl_map *isl_map_intersect_domain_factor_range( |
8479 | __isl_take isl_map *map, __isl_take isl_map *factor) |
8480 | { |
8481 | struct isl_intersect_factor_control control = { |
8482 | .preserve_type = isl_dim_in, |
8483 | .other_factor = isl_space_domain_factor_domain, |
8484 | .product = isl_map_reverse_domain_product, |
8485 | }; |
8486 | |
8487 | return isl_map_intersect_factor(map, factor, control: &control); |
8488 | } |
8489 | |
8490 | /* Given a map "map" in a space A -> [B -> C] and a map "factor" |
8491 | * in the space A -> B, return the intersection. |
8492 | */ |
8493 | __isl_give isl_map *isl_map_intersect_range_factor_domain( |
8494 | __isl_take isl_map *map, __isl_take isl_map *factor) |
8495 | { |
8496 | struct isl_intersect_factor_control control = { |
8497 | .preserve_type = isl_dim_out, |
8498 | .other_factor = isl_space_range_factor_range, |
8499 | .product = isl_map_range_product, |
8500 | }; |
8501 | |
8502 | return isl_map_intersect_factor(map, factor, control: &control); |
8503 | } |
8504 | |
8505 | /* Given a map "map" in a space A -> [B -> C] and a map "factor" |
8506 | * in the space A -> C, return the intersection. |
8507 | */ |
8508 | __isl_give isl_map *isl_map_intersect_range_factor_range( |
8509 | __isl_take isl_map *map, __isl_take isl_map *factor) |
8510 | { |
8511 | struct isl_intersect_factor_control control = { |
8512 | .preserve_type = isl_dim_out, |
8513 | .other_factor = isl_space_range_factor_domain, |
8514 | .product = isl_map_reverse_range_product, |
8515 | }; |
8516 | |
8517 | return isl_map_intersect_factor(map, factor, control: &control); |
8518 | } |
8519 | |
8520 | /* Given a set "set" in a space [A -> B] and a set "domain" |
8521 | * in the space A, return the intersection. |
8522 | * |
8523 | * The set "domain" is first extended to a set living in the space |
8524 | * [A -> B] and then a regular intersection is computed. |
8525 | */ |
8526 | __isl_give isl_set *isl_set_intersect_factor_domain(__isl_take isl_set *set, |
8527 | __isl_take isl_set *domain) |
8528 | { |
8529 | struct isl_intersect_factor_control control = { |
8530 | .preserve_type = isl_dim_set, |
8531 | .other_factor = isl_space_factor_range, |
8532 | .product = isl_map_range_product, |
8533 | }; |
8534 | |
8535 | return set_from_map(isl_map_intersect_factor(map: set_to_map(set), |
8536 | factor: set_to_map(domain), control: &control)); |
8537 | } |
8538 | |
8539 | /* Given a set "set" in a space [A -> B] and a set "range" |
8540 | * in the space B, return the intersection. |
8541 | * |
8542 | * The set "range" is first extended to a set living in the space |
8543 | * [A -> B] and then a regular intersection is computed. |
8544 | */ |
8545 | __isl_give isl_set *isl_set_intersect_factor_range(__isl_take isl_set *set, |
8546 | __isl_take isl_set *range) |
8547 | { |
8548 | struct isl_intersect_factor_control control = { |
8549 | .preserve_type = isl_dim_set, |
8550 | .other_factor = isl_space_factor_domain, |
8551 | .product = isl_map_reverse_range_product, |
8552 | }; |
8553 | |
8554 | return set_from_map(isl_map_intersect_factor(map: set_to_map(set), |
8555 | factor: set_to_map(range), control: &control)); |
8556 | } |
8557 | |
8558 | /* Given a map "map" in a space [A -> B] -> C and a set "domain" |
8559 | * in the space A, return the intersection. |
8560 | * |
8561 | * The set "domain" is extended to a set living in the space [A -> B] and |
8562 | * the domain of "map" is intersected with this set. |
8563 | */ |
8564 | __isl_give isl_map *isl_map_intersect_domain_wrapped_domain( |
8565 | __isl_take isl_map *map, __isl_take isl_set *domain) |
8566 | { |
8567 | isl_space *space; |
8568 | isl_set *factor; |
8569 | |
8570 | isl_map_align_params_set(obj1: &map, obj2: &domain); |
8571 | space = isl_map_get_space(map); |
8572 | space = isl_space_domain_wrapped_range(space); |
8573 | factor = isl_set_universe(space); |
8574 | domain = isl_set_product(set1: domain, set2: factor); |
8575 | return isl_map_intersect_domain(map, set: domain); |
8576 | } |
8577 | |
8578 | /* Given a map "map" in a space A -> [B -> C] and a set "domain" |
8579 | * in the space B, return the intersection. |
8580 | * |
8581 | * The set "domain" is extended to a set living in the space [B -> C] and |
8582 | * the range of "map" is intersected with this set. |
8583 | */ |
8584 | __isl_give isl_map *isl_map_intersect_range_wrapped_domain( |
8585 | __isl_take isl_map *map, __isl_take isl_set *domain) |
8586 | { |
8587 | isl_space *space; |
8588 | isl_set *factor; |
8589 | |
8590 | isl_map_align_params_set(obj1: &map, obj2: &domain); |
8591 | space = isl_map_get_space(map); |
8592 | space = isl_space_range_wrapped_range(space); |
8593 | factor = isl_set_universe(space); |
8594 | domain = isl_set_product(set1: domain, set2: factor); |
8595 | return isl_map_intersect_range(map, set: domain); |
8596 | } |
8597 | |
8598 | __isl_give isl_map *isl_map_apply_domain(__isl_take isl_map *map1, |
8599 | __isl_take isl_map *map2) |
8600 | { |
8601 | if (isl_map_align_params_bin(obj1: &map1, obj2: &map2) < 0) |
8602 | goto error; |
8603 | map1 = isl_map_reverse(map: map1); |
8604 | map1 = isl_map_apply_range(map1, map2); |
8605 | return isl_map_reverse(map: map1); |
8606 | error: |
8607 | isl_map_free(map: map1); |
8608 | isl_map_free(map: map2); |
8609 | return NULL; |
8610 | } |
8611 | |
8612 | __isl_give isl_map *isl_map_apply_range(__isl_take isl_map *map1, |
8613 | __isl_take isl_map *map2) |
8614 | { |
8615 | isl_space *space; |
8616 | struct isl_map *result; |
8617 | int i, j; |
8618 | |
8619 | if (isl_map_align_params_bin(obj1: &map1, obj2: &map2) < 0) |
8620 | goto error; |
8621 | |
8622 | space = isl_space_join(left: isl_space_copy(space: map1->dim), |
8623 | right: isl_space_copy(space: map2->dim)); |
8624 | |
8625 | result = isl_map_alloc_space(space, n: map1->n * map2->n, flags: 0); |
8626 | if (!result) |
8627 | goto error; |
8628 | for (i = 0; i < map1->n; ++i) |
8629 | for (j = 0; j < map2->n; ++j) { |
8630 | result = isl_map_add_basic_map(map: result, |
8631 | bmap: isl_basic_map_apply_range( |
8632 | bmap1: isl_basic_map_copy(bmap: map1->p[i]), |
8633 | bmap2: isl_basic_map_copy(bmap: map2->p[j]))); |
8634 | if (!result) |
8635 | goto error; |
8636 | } |
8637 | isl_map_free(map: map1); |
8638 | isl_map_free(map: map2); |
8639 | if (result && result->n <= 1) |
8640 | ISL_F_SET(result, ISL_MAP_DISJOINT); |
8641 | return result; |
8642 | error: |
8643 | isl_map_free(map: map1); |
8644 | isl_map_free(map: map2); |
8645 | return NULL; |
8646 | } |
8647 | |
8648 | /* Is "bmap" a transformation, i.e., |
8649 | * does it relate elements from the same space. |
8650 | */ |
8651 | isl_bool isl_basic_map_is_transformation(__isl_keep isl_basic_map *bmap) |
8652 | { |
8653 | isl_space *space; |
8654 | |
8655 | space = isl_basic_map_peek_space(bmap); |
8656 | return isl_space_tuple_is_equal(space1: space, type1: isl_dim_in, space2: space, type2: isl_dim_out); |
8657 | } |
8658 | |
8659 | /* Check that "bmap" is a transformation, i.e., |
8660 | * that it relates elements from the same space. |
8661 | */ |
8662 | static isl_stat isl_basic_map_check_transformation( |
8663 | __isl_keep isl_basic_map *bmap) |
8664 | { |
8665 | isl_bool equal; |
8666 | |
8667 | equal = isl_basic_map_is_transformation(bmap); |
8668 | if (equal < 0) |
8669 | return isl_stat_error; |
8670 | if (!equal) |
8671 | isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, |
8672 | "domain and range don't match" , return isl_stat_error); |
8673 | return isl_stat_ok; |
8674 | } |
8675 | |
8676 | /* |
8677 | * returns range - domain |
8678 | */ |
8679 | __isl_give isl_basic_set *isl_basic_map_deltas(__isl_take isl_basic_map *bmap) |
8680 | { |
8681 | isl_space *target_space; |
8682 | struct isl_basic_set *bset; |
8683 | isl_size dim; |
8684 | isl_size nparam; |
8685 | isl_size total; |
8686 | int i; |
8687 | |
8688 | if (isl_basic_map_check_transformation(bmap) < 0) |
8689 | return isl_basic_map_free(bmap); |
8690 | dim = isl_basic_map_dim(bmap, type: isl_dim_in); |
8691 | nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
8692 | if (dim < 0 || nparam < 0) |
8693 | goto error; |
8694 | target_space = isl_space_domain(space: isl_basic_map_get_space(bmap)); |
8695 | bmap = isl_basic_map_from_range(bset: isl_basic_map_wrap(bmap)); |
8696 | bmap = isl_basic_map_add_dims(bmap, type: isl_dim_in, n: dim); |
8697 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
8698 | if (total < 0) |
8699 | bmap = isl_basic_map_free(bmap); |
8700 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq: dim, n_ineq: 0); |
8701 | for (i = 0; i < dim; ++i) { |
8702 | int j = isl_basic_map_alloc_equality(bmap); |
8703 | if (j < 0) { |
8704 | bmap = isl_basic_map_free(bmap); |
8705 | break; |
8706 | } |
8707 | isl_seq_clr(p: bmap->eq[j], len: 1 + total); |
8708 | isl_int_set_si(bmap->eq[j][1+nparam+i], 1); |
8709 | isl_int_set_si(bmap->eq[j][1+nparam+dim+i], 1); |
8710 | isl_int_set_si(bmap->eq[j][1+nparam+2*dim+i], -1); |
8711 | } |
8712 | bset = isl_basic_map_domain(bmap); |
8713 | bset = isl_basic_set_reset_space(bset, space: target_space); |
8714 | return bset; |
8715 | error: |
8716 | isl_basic_map_free(bmap); |
8717 | return NULL; |
8718 | } |
8719 | |
8720 | /* Is the tuple of type "type1" of "map" the same as |
8721 | * the tuple of type "type2" of "space"? |
8722 | */ |
8723 | isl_bool isl_map_space_tuple_is_equal(__isl_keep isl_map *map, |
8724 | enum isl_dim_type type1, __isl_keep isl_space *space, |
8725 | enum isl_dim_type type2) |
8726 | { |
8727 | isl_space *map_space; |
8728 | |
8729 | map_space = isl_map_peek_space(map); |
8730 | return isl_space_tuple_is_equal(space1: map_space, type1, space2: space, type2); |
8731 | } |
8732 | |
8733 | /* Is the tuple of type "type1" of "map1" the same as |
8734 | * the tuple of type "type2" of "map2"? |
8735 | */ |
8736 | isl_bool isl_map_tuple_is_equal(__isl_keep isl_map *map1, |
8737 | enum isl_dim_type type1, __isl_keep isl_map *map2, |
8738 | enum isl_dim_type type2) |
8739 | { |
8740 | isl_space *space1, *space2; |
8741 | |
8742 | space1 = isl_map_peek_space(map: map1); |
8743 | space2 = isl_map_peek_space(map: map2); |
8744 | return isl_space_tuple_is_equal(space1, type1, space2, type2); |
8745 | } |
8746 | |
8747 | /* Is the space of "obj" equal to "space", ignoring parameters? |
8748 | */ |
8749 | isl_bool isl_map_has_space_tuples(__isl_keep isl_map *map, |
8750 | __isl_keep isl_space *space) |
8751 | { |
8752 | isl_space *map_space; |
8753 | |
8754 | map_space = isl_map_peek_space(map); |
8755 | return isl_space_has_equal_tuples(space1: map_space, space2: space); |
8756 | } |
8757 | |
8758 | /* Check that "map" is a transformation, i.e., |
8759 | * that it relates elements from the same space. |
8760 | */ |
8761 | isl_stat isl_map_check_transformation(__isl_keep isl_map *map) |
8762 | { |
8763 | isl_bool equal; |
8764 | |
8765 | equal = isl_map_tuple_is_equal(map1: map, type1: isl_dim_in, map2: map, type2: isl_dim_out); |
8766 | if (equal < 0) |
8767 | return isl_stat_error; |
8768 | if (!equal) |
8769 | isl_die(isl_map_get_ctx(map), isl_error_invalid, |
8770 | "domain and range don't match" , return isl_stat_error); |
8771 | return isl_stat_ok; |
8772 | } |
8773 | |
8774 | /* |
8775 | * returns range - domain |
8776 | */ |
8777 | __isl_give isl_set *isl_map_deltas(__isl_take isl_map *map) |
8778 | { |
8779 | int i; |
8780 | isl_space *space; |
8781 | struct isl_set *result; |
8782 | |
8783 | if (isl_map_check_transformation(map) < 0) |
8784 | goto error; |
8785 | space = isl_map_get_space(map); |
8786 | space = isl_space_domain(space); |
8787 | result = isl_set_alloc_space(space, n: map->n, flags: 0); |
8788 | if (!result) |
8789 | goto error; |
8790 | for (i = 0; i < map->n; ++i) |
8791 | result = isl_set_add_basic_set(set: result, |
8792 | bset: isl_basic_map_deltas(bmap: isl_basic_map_copy(bmap: map->p[i]))); |
8793 | isl_map_free(map); |
8794 | return result; |
8795 | error: |
8796 | isl_map_free(map); |
8797 | return NULL; |
8798 | } |
8799 | |
8800 | /* |
8801 | * returns [domain -> range] -> range - domain |
8802 | */ |
8803 | __isl_give isl_basic_map *isl_basic_map_deltas_map( |
8804 | __isl_take isl_basic_map *bmap) |
8805 | { |
8806 | int i, k; |
8807 | isl_space *space; |
8808 | isl_basic_map *domain; |
8809 | isl_size nparam, n; |
8810 | isl_size total; |
8811 | |
8812 | if (isl_basic_map_check_transformation(bmap) < 0) |
8813 | return isl_basic_map_free(bmap); |
8814 | |
8815 | nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
8816 | n = isl_basic_map_dim(bmap, type: isl_dim_in); |
8817 | if (nparam < 0 || n < 0) |
8818 | return isl_basic_map_free(bmap); |
8819 | |
8820 | space = isl_basic_map_get_space(bmap); |
8821 | space = isl_space_from_range(space: isl_space_domain(space)); |
8822 | domain = isl_basic_map_universe(space); |
8823 | |
8824 | bmap = isl_basic_map_from_domain(bset: isl_basic_map_wrap(bmap)); |
8825 | bmap = isl_basic_map_apply_range(bmap1: bmap, bmap2: domain); |
8826 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq: n, n_ineq: 0); |
8827 | |
8828 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
8829 | if (total < 0) |
8830 | return isl_basic_map_free(bmap); |
8831 | |
8832 | for (i = 0; i < n; ++i) { |
8833 | k = isl_basic_map_alloc_equality(bmap); |
8834 | if (k < 0) |
8835 | goto error; |
8836 | isl_seq_clr(p: bmap->eq[k], len: 1 + total); |
8837 | isl_int_set_si(bmap->eq[k][1 + nparam + i], 1); |
8838 | isl_int_set_si(bmap->eq[k][1 + nparam + n + i], -1); |
8839 | isl_int_set_si(bmap->eq[k][1 + nparam + n + n + i], 1); |
8840 | } |
8841 | |
8842 | bmap = isl_basic_map_gauss(bmap, NULL); |
8843 | return isl_basic_map_finalize(bmap); |
8844 | error: |
8845 | isl_basic_map_free(bmap); |
8846 | return NULL; |
8847 | } |
8848 | |
8849 | /* |
8850 | * returns [domain -> range] -> range - domain |
8851 | */ |
8852 | __isl_give isl_map *isl_map_deltas_map(__isl_take isl_map *map) |
8853 | { |
8854 | if (isl_map_check_transformation(map) < 0) |
8855 | return isl_map_free(map); |
8856 | |
8857 | return isl_map_transform(map, fn_space: &isl_space_range_map, |
8858 | fn_bmap: &isl_basic_map_deltas_map); |
8859 | } |
8860 | |
8861 | /* Return pairs of elements { x -> y } such that y - x is in "deltas". |
8862 | */ |
8863 | __isl_give isl_map *isl_set_translation(__isl_take isl_set *deltas) |
8864 | { |
8865 | isl_space *space; |
8866 | isl_map *map; |
8867 | |
8868 | space = isl_space_map_from_set(space: isl_set_get_space(set: deltas)); |
8869 | map = isl_map_deltas_map(map: isl_map_universe(space)); |
8870 | map = isl_map_intersect_range(map, set: deltas); |
8871 | |
8872 | return isl_set_unwrap(set: isl_map_domain(map)); |
8873 | } |
8874 | |
8875 | __isl_give isl_basic_map *isl_basic_map_identity(__isl_take isl_space *space) |
8876 | { |
8877 | isl_size n_in, n_out; |
8878 | |
8879 | n_in = isl_space_dim(space, type: isl_dim_in); |
8880 | n_out = isl_space_dim(space, type: isl_dim_out); |
8881 | if (n_in < 0 || n_out < 0) |
8882 | goto error; |
8883 | if (n_in != n_out) |
8884 | isl_die(space->ctx, isl_error_invalid, |
8885 | "number of input and output dimensions needs to be " |
8886 | "the same" , goto error); |
8887 | return isl_basic_map_equal(space, n_equal: n_in); |
8888 | error: |
8889 | isl_space_free(space); |
8890 | return NULL; |
8891 | } |
8892 | |
8893 | __isl_give isl_map *isl_map_identity(__isl_take isl_space *space) |
8894 | { |
8895 | return isl_map_from_basic_map(bmap: isl_basic_map_identity(space)); |
8896 | } |
8897 | |
8898 | __isl_give isl_map *isl_set_identity(__isl_take isl_set *set) |
8899 | { |
8900 | isl_space *space = isl_set_get_space(set); |
8901 | isl_map *id; |
8902 | id = isl_map_identity(space: isl_space_map_from_set(space)); |
8903 | return isl_map_intersect_range(map: id, set); |
8904 | } |
8905 | |
8906 | /* Construct a basic set with all set dimensions having only non-negative |
8907 | * values. |
8908 | */ |
8909 | __isl_give isl_basic_set *isl_basic_set_positive_orthant( |
8910 | __isl_take isl_space *space) |
8911 | { |
8912 | int i; |
8913 | isl_size nparam; |
8914 | isl_size dim; |
8915 | isl_size total; |
8916 | struct isl_basic_set *bset; |
8917 | |
8918 | nparam = isl_space_dim(space, type: isl_dim_param); |
8919 | dim = isl_space_dim(space, type: isl_dim_set); |
8920 | total = isl_space_dim(space, type: isl_dim_all); |
8921 | if (nparam < 0 || dim < 0 || total < 0) |
8922 | space = isl_space_free(space); |
8923 | bset = isl_basic_set_alloc_space(space, extra: 0, n_eq: 0, n_ineq: dim); |
8924 | if (!bset) |
8925 | return NULL; |
8926 | for (i = 0; i < dim; ++i) { |
8927 | int k = isl_basic_set_alloc_inequality(bset); |
8928 | if (k < 0) |
8929 | goto error; |
8930 | isl_seq_clr(p: bset->ineq[k], len: 1 + total); |
8931 | isl_int_set_si(bset->ineq[k][1 + nparam + i], 1); |
8932 | } |
8933 | return bset; |
8934 | error: |
8935 | isl_basic_set_free(bset); |
8936 | return NULL; |
8937 | } |
8938 | |
8939 | /* Construct the half-space x_pos >= 0. |
8940 | */ |
8941 | static __isl_give isl_basic_set *nonneg_halfspace(__isl_take isl_space *space, |
8942 | int pos) |
8943 | { |
8944 | int k; |
8945 | isl_size total; |
8946 | isl_basic_set *nonneg; |
8947 | |
8948 | total = isl_space_dim(space, type: isl_dim_all); |
8949 | if (total < 0) |
8950 | space = isl_space_free(space); |
8951 | nonneg = isl_basic_set_alloc_space(space, extra: 0, n_eq: 0, n_ineq: 1); |
8952 | k = isl_basic_set_alloc_inequality(bset: nonneg); |
8953 | if (k < 0) |
8954 | goto error; |
8955 | isl_seq_clr(p: nonneg->ineq[k], len: 1 + total); |
8956 | isl_int_set_si(nonneg->ineq[k][pos], 1); |
8957 | |
8958 | return isl_basic_set_finalize(bset: nonneg); |
8959 | error: |
8960 | isl_basic_set_free(bset: nonneg); |
8961 | return NULL; |
8962 | } |
8963 | |
8964 | /* Construct the half-space x_pos <= -1. |
8965 | */ |
8966 | static __isl_give isl_basic_set *neg_halfspace(__isl_take isl_space *space, |
8967 | int pos) |
8968 | { |
8969 | int k; |
8970 | isl_size total; |
8971 | isl_basic_set *neg; |
8972 | |
8973 | total = isl_space_dim(space, type: isl_dim_all); |
8974 | if (total < 0) |
8975 | space = isl_space_free(space); |
8976 | neg = isl_basic_set_alloc_space(space, extra: 0, n_eq: 0, n_ineq: 1); |
8977 | k = isl_basic_set_alloc_inequality(bset: neg); |
8978 | if (k < 0) |
8979 | goto error; |
8980 | isl_seq_clr(p: neg->ineq[k], len: 1 + total); |
8981 | isl_int_set_si(neg->ineq[k][0], -1); |
8982 | isl_int_set_si(neg->ineq[k][pos], -1); |
8983 | |
8984 | return isl_basic_set_finalize(bset: neg); |
8985 | error: |
8986 | isl_basic_set_free(bset: neg); |
8987 | return NULL; |
8988 | } |
8989 | |
8990 | __isl_give isl_set *isl_set_split_dims(__isl_take isl_set *set, |
8991 | enum isl_dim_type type, unsigned first, unsigned n) |
8992 | { |
8993 | int i; |
8994 | unsigned offset; |
8995 | isl_basic_set *nonneg; |
8996 | isl_basic_set *neg; |
8997 | |
8998 | if (n == 0) |
8999 | return set; |
9000 | |
9001 | if (isl_set_check_range(set, type, first, n) < 0) |
9002 | return isl_set_free(set); |
9003 | |
9004 | offset = pos(space: set->dim, type); |
9005 | for (i = 0; i < n; ++i) { |
9006 | nonneg = nonneg_halfspace(space: isl_set_get_space(set), |
9007 | pos: offset + first + i); |
9008 | neg = neg_halfspace(space: isl_set_get_space(set), pos: offset + first + i); |
9009 | |
9010 | set = isl_set_intersect(set1: set, set2: isl_basic_set_union(bset1: nonneg, bset2: neg)); |
9011 | } |
9012 | |
9013 | return set; |
9014 | } |
9015 | |
9016 | static isl_stat foreach_orthant(__isl_take isl_set *set, int *signs, int first, |
9017 | int len, |
9018 | isl_stat (*fn)(__isl_take isl_set *orthant, int *signs, void *user), |
9019 | void *user) |
9020 | { |
9021 | isl_set *half; |
9022 | |
9023 | if (!set) |
9024 | return isl_stat_error; |
9025 | if (isl_set_plain_is_empty(set)) { |
9026 | isl_set_free(set); |
9027 | return isl_stat_ok; |
9028 | } |
9029 | if (first == len) |
9030 | return fn(set, signs, user); |
9031 | |
9032 | signs[first] = 1; |
9033 | half = isl_set_from_basic_set(bset: nonneg_halfspace(space: isl_set_get_space(set), |
9034 | pos: 1 + first)); |
9035 | half = isl_set_intersect(set1: half, set2: isl_set_copy(set)); |
9036 | if (foreach_orthant(set: half, signs, first: first + 1, len, fn, user) < 0) |
9037 | goto error; |
9038 | |
9039 | signs[first] = -1; |
9040 | half = isl_set_from_basic_set(bset: neg_halfspace(space: isl_set_get_space(set), |
9041 | pos: 1 + first)); |
9042 | half = isl_set_intersect(set1: half, set2: set); |
9043 | return foreach_orthant(set: half, signs, first: first + 1, len, fn, user); |
9044 | error: |
9045 | isl_set_free(set); |
9046 | return isl_stat_error; |
9047 | } |
9048 | |
9049 | /* Call "fn" on the intersections of "set" with each of the orthants |
9050 | * (except for obviously empty intersections). The orthant is identified |
9051 | * by the signs array, with each entry having value 1 or -1 according |
9052 | * to the sign of the corresponding variable. |
9053 | */ |
9054 | isl_stat isl_set_foreach_orthant(__isl_keep isl_set *set, |
9055 | isl_stat (*fn)(__isl_take isl_set *orthant, int *signs, void *user), |
9056 | void *user) |
9057 | { |
9058 | isl_size nparam; |
9059 | isl_size nvar; |
9060 | int *signs; |
9061 | isl_stat r; |
9062 | |
9063 | if (!set) |
9064 | return isl_stat_error; |
9065 | if (isl_set_plain_is_empty(set)) |
9066 | return isl_stat_ok; |
9067 | |
9068 | nparam = isl_set_dim(set, type: isl_dim_param); |
9069 | nvar = isl_set_dim(set, type: isl_dim_set); |
9070 | if (nparam < 0 || nvar < 0) |
9071 | return isl_stat_error; |
9072 | |
9073 | signs = isl_alloc_array(set->ctx, int, nparam + nvar); |
9074 | |
9075 | r = foreach_orthant(set: isl_set_copy(set), signs, first: 0, len: nparam + nvar, |
9076 | fn, user); |
9077 | |
9078 | free(ptr: signs); |
9079 | |
9080 | return r; |
9081 | } |
9082 | |
9083 | isl_bool isl_set_is_equal(__isl_keep isl_set *set1, __isl_keep isl_set *set2) |
9084 | { |
9085 | return isl_map_is_equal(map1: set_to_map(set1), map2: set_to_map(set2)); |
9086 | } |
9087 | |
9088 | isl_bool isl_basic_map_is_subset(__isl_keep isl_basic_map *bmap1, |
9089 | __isl_keep isl_basic_map *bmap2) |
9090 | { |
9091 | isl_bool is_subset; |
9092 | struct isl_map *map1; |
9093 | struct isl_map *map2; |
9094 | |
9095 | if (!bmap1 || !bmap2) |
9096 | return isl_bool_error; |
9097 | |
9098 | map1 = isl_map_from_basic_map(bmap: isl_basic_map_copy(bmap: bmap1)); |
9099 | map2 = isl_map_from_basic_map(bmap: isl_basic_map_copy(bmap: bmap2)); |
9100 | |
9101 | is_subset = isl_map_is_subset(map1, map2); |
9102 | |
9103 | isl_map_free(map: map1); |
9104 | isl_map_free(map: map2); |
9105 | |
9106 | return is_subset; |
9107 | } |
9108 | |
9109 | isl_bool isl_basic_set_is_subset(__isl_keep isl_basic_set *bset1, |
9110 | __isl_keep isl_basic_set *bset2) |
9111 | { |
9112 | return isl_basic_map_is_subset(bmap1: bset1, bmap2: bset2); |
9113 | } |
9114 | |
9115 | isl_bool isl_basic_map_is_equal(__isl_keep isl_basic_map *bmap1, |
9116 | __isl_keep isl_basic_map *bmap2) |
9117 | { |
9118 | isl_bool is_subset; |
9119 | |
9120 | if (!bmap1 || !bmap2) |
9121 | return isl_bool_error; |
9122 | is_subset = isl_basic_map_is_subset(bmap1, bmap2); |
9123 | if (is_subset != isl_bool_true) |
9124 | return is_subset; |
9125 | is_subset = isl_basic_map_is_subset(bmap1: bmap2, bmap2: bmap1); |
9126 | return is_subset; |
9127 | } |
9128 | |
9129 | isl_bool isl_basic_set_is_equal(__isl_keep isl_basic_set *bset1, |
9130 | __isl_keep isl_basic_set *bset2) |
9131 | { |
9132 | return isl_basic_map_is_equal( |
9133 | bmap1: bset_to_bmap(bset: bset1), bmap2: bset_to_bmap(bset: bset2)); |
9134 | } |
9135 | |
9136 | isl_bool isl_map_is_empty(__isl_keep isl_map *map) |
9137 | { |
9138 | int i; |
9139 | int is_empty; |
9140 | |
9141 | if (!map) |
9142 | return isl_bool_error; |
9143 | for (i = 0; i < map->n; ++i) { |
9144 | is_empty = isl_basic_map_is_empty(bmap: map->p[i]); |
9145 | if (is_empty < 0) |
9146 | return isl_bool_error; |
9147 | if (!is_empty) |
9148 | return isl_bool_false; |
9149 | } |
9150 | return isl_bool_true; |
9151 | } |
9152 | |
9153 | isl_bool isl_map_plain_is_empty(__isl_keep isl_map *map) |
9154 | { |
9155 | return map ? map->n == 0 : isl_bool_error; |
9156 | } |
9157 | |
9158 | isl_bool isl_set_plain_is_empty(__isl_keep isl_set *set) |
9159 | { |
9160 | return set ? set->n == 0 : isl_bool_error; |
9161 | } |
9162 | |
9163 | isl_bool isl_set_is_empty(__isl_keep isl_set *set) |
9164 | { |
9165 | return isl_map_is_empty(map: set_to_map(set)); |
9166 | } |
9167 | |
9168 | #undef TYPE |
9169 | #define TYPE isl_basic_map |
9170 | |
9171 | static |
9172 | #include "isl_type_has_equal_space_bin_templ.c" |
9173 | #include "isl_type_check_equal_space_templ.c" |
9174 | |
9175 | /* Check that "bset1" and "bset2" live in the same space, |
9176 | * reporting an error if they do not. |
9177 | */ |
9178 | isl_stat isl_basic_set_check_equal_space(__isl_keep isl_basic_set *bset1, |
9179 | __isl_keep isl_basic_set *bset2) |
9180 | { |
9181 | return isl_basic_map_check_equal_space(obj1: bset_to_bmap(bset: bset1), |
9182 | obj2: bset_to_bmap(bset: bset1)); |
9183 | } |
9184 | |
9185 | #undef TYPE |
9186 | #define TYPE isl_map |
9187 | |
9188 | #include "isl_type_has_equal_space_bin_templ.c" |
9189 | #include "isl_type_check_equal_space_templ.c" |
9190 | #include "isl_type_has_space_templ.c" |
9191 | |
9192 | isl_bool isl_set_has_equal_space(__isl_keep isl_set *set1, |
9193 | __isl_keep isl_set *set2) |
9194 | { |
9195 | return isl_map_has_equal_space(obj1: set_to_map(set1), obj2: set_to_map(set2)); |
9196 | } |
9197 | |
9198 | #undef TYPE1 |
9199 | #define TYPE1 isl_map |
9200 | #undef TYPE2 |
9201 | #define TYPE2 isl_basic_map |
9202 | #undef TYPE_PAIR |
9203 | #define TYPE_PAIR isl_map_basic_map |
9204 | |
9205 | static |
9206 | #include "isl_type_has_equal_space_templ.c" |
9207 | #include "isl_type_check_equal_space_templ.c" |
9208 | |
9209 | /* Check that "set" and "bset" live in the same space, |
9210 | * reporting an error if they do not. |
9211 | */ |
9212 | isl_stat isl_set_basic_set_check_equal_space(__isl_keep isl_set *set, |
9213 | __isl_keep isl_basic_set *bset) |
9214 | { |
9215 | return isl_map_basic_map_check_equal_space(obj1: set_to_map(set), |
9216 | obj2: bset_to_bmap(bset)); |
9217 | } |
9218 | |
9219 | static isl_bool map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2) |
9220 | { |
9221 | isl_bool is_subset; |
9222 | |
9223 | if (!map1 || !map2) |
9224 | return isl_bool_error; |
9225 | is_subset = isl_map_is_subset(map1, map2); |
9226 | if (is_subset != isl_bool_true) |
9227 | return is_subset; |
9228 | is_subset = isl_map_is_subset(map1: map2, map2: map1); |
9229 | return is_subset; |
9230 | } |
9231 | |
9232 | /* Is "map1" equal to "map2"? |
9233 | * |
9234 | * First check if they are obviously equal. |
9235 | * If not, then perform a more detailed analysis. |
9236 | */ |
9237 | isl_bool isl_map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2) |
9238 | { |
9239 | isl_bool equal; |
9240 | |
9241 | equal = isl_map_plain_is_equal(map1, map2); |
9242 | if (equal < 0 || equal) |
9243 | return equal; |
9244 | return isl_map_align_params_map_map_and_test(map1, map2, fn: &map_is_equal); |
9245 | } |
9246 | |
9247 | isl_bool isl_basic_map_is_strict_subset(__isl_keep isl_basic_map *bmap1, |
9248 | __isl_keep isl_basic_map *bmap2) |
9249 | { |
9250 | isl_bool is_subset; |
9251 | |
9252 | if (!bmap1 || !bmap2) |
9253 | return isl_bool_error; |
9254 | is_subset = isl_basic_map_is_subset(bmap1, bmap2); |
9255 | if (is_subset != isl_bool_true) |
9256 | return is_subset; |
9257 | is_subset = isl_basic_map_is_subset(bmap1: bmap2, bmap2: bmap1); |
9258 | return isl_bool_not(b: is_subset); |
9259 | } |
9260 | |
9261 | isl_bool isl_map_is_strict_subset(__isl_keep isl_map *map1, |
9262 | __isl_keep isl_map *map2) |
9263 | { |
9264 | isl_bool is_subset; |
9265 | |
9266 | if (!map1 || !map2) |
9267 | return isl_bool_error; |
9268 | is_subset = isl_map_is_subset(map1, map2); |
9269 | if (is_subset != isl_bool_true) |
9270 | return is_subset; |
9271 | is_subset = isl_map_is_subset(map1: map2, map2: map1); |
9272 | return isl_bool_not(b: is_subset); |
9273 | } |
9274 | |
9275 | isl_bool isl_set_is_strict_subset(__isl_keep isl_set *set1, |
9276 | __isl_keep isl_set *set2) |
9277 | { |
9278 | return isl_map_is_strict_subset(map1: set_to_map(set1), map2: set_to_map(set2)); |
9279 | } |
9280 | |
9281 | /* Is "bmap" obviously equal to the universe with the same space? |
9282 | * |
9283 | * That is, does it not have any constraints? |
9284 | */ |
9285 | isl_bool isl_basic_map_plain_is_universe(__isl_keep isl_basic_map *bmap) |
9286 | { |
9287 | if (!bmap) |
9288 | return isl_bool_error; |
9289 | return bmap->n_eq == 0 && bmap->n_ineq == 0; |
9290 | } |
9291 | |
9292 | /* Is "bset" obviously equal to the universe with the same space? |
9293 | */ |
9294 | isl_bool isl_basic_set_plain_is_universe(__isl_keep isl_basic_set *bset) |
9295 | { |
9296 | return isl_basic_map_plain_is_universe(bmap: bset); |
9297 | } |
9298 | |
9299 | /* If "c" does not involve any existentially quantified variables, |
9300 | * then set *univ to false and abort |
9301 | */ |
9302 | static isl_stat involves_divs(__isl_take isl_constraint *c, void *user) |
9303 | { |
9304 | isl_bool *univ = user; |
9305 | isl_size n; |
9306 | |
9307 | n = isl_constraint_dim(constraint: c, type: isl_dim_div); |
9308 | if (n < 0) |
9309 | c = isl_constraint_free(c); |
9310 | *univ = isl_constraint_involves_dims(constraint: c, type: isl_dim_div, first: 0, n); |
9311 | isl_constraint_free(c); |
9312 | if (*univ < 0 || !*univ) |
9313 | return isl_stat_error; |
9314 | return isl_stat_ok; |
9315 | } |
9316 | |
9317 | /* Is "bmap" equal to the universe with the same space? |
9318 | * |
9319 | * First check if it is obviously equal to the universe. |
9320 | * If not and if there are any constraints not involving |
9321 | * existentially quantified variables, then it is certainly |
9322 | * not equal to the universe. |
9323 | * Otherwise, check if the universe is a subset of "bmap". |
9324 | */ |
9325 | isl_bool isl_basic_map_is_universe(__isl_keep isl_basic_map *bmap) |
9326 | { |
9327 | isl_size n_div; |
9328 | isl_bool univ; |
9329 | isl_basic_map *test; |
9330 | |
9331 | univ = isl_basic_map_plain_is_universe(bmap); |
9332 | if (univ < 0 || univ) |
9333 | return univ; |
9334 | n_div = isl_basic_map_dim(bmap, type: isl_dim_div); |
9335 | if (n_div < 0) |
9336 | return isl_bool_error; |
9337 | if (n_div == 0) |
9338 | return isl_bool_false; |
9339 | univ = isl_bool_true; |
9340 | if (isl_basic_map_foreach_constraint(bmap, fn: &involves_divs, user: &univ) < 0 && |
9341 | univ) |
9342 | return isl_bool_error; |
9343 | if (univ < 0 || !univ) |
9344 | return univ; |
9345 | test = isl_basic_map_universe(space: isl_basic_map_get_space(bmap)); |
9346 | univ = isl_basic_map_is_subset(bmap1: test, bmap2: bmap); |
9347 | isl_basic_map_free(bmap: test); |
9348 | return univ; |
9349 | } |
9350 | |
9351 | /* Is "bset" equal to the universe with the same space? |
9352 | */ |
9353 | isl_bool isl_basic_set_is_universe(__isl_keep isl_basic_set *bset) |
9354 | { |
9355 | return isl_basic_map_is_universe(bmap: bset); |
9356 | } |
9357 | |
9358 | isl_bool isl_map_plain_is_universe(__isl_keep isl_map *map) |
9359 | { |
9360 | int i; |
9361 | |
9362 | if (!map) |
9363 | return isl_bool_error; |
9364 | |
9365 | for (i = 0; i < map->n; ++i) { |
9366 | isl_bool r = isl_basic_map_plain_is_universe(bmap: map->p[i]); |
9367 | if (r < 0 || r) |
9368 | return r; |
9369 | } |
9370 | |
9371 | return isl_bool_false; |
9372 | } |
9373 | |
9374 | isl_bool isl_set_plain_is_universe(__isl_keep isl_set *set) |
9375 | { |
9376 | return isl_map_plain_is_universe(map: set_to_map(set)); |
9377 | } |
9378 | |
9379 | isl_bool isl_basic_map_is_empty(__isl_keep isl_basic_map *bmap) |
9380 | { |
9381 | struct isl_basic_set *bset = NULL; |
9382 | struct isl_vec *sample = NULL; |
9383 | isl_bool empty, non_empty; |
9384 | |
9385 | if (!bmap) |
9386 | return isl_bool_error; |
9387 | |
9388 | if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) |
9389 | return isl_bool_true; |
9390 | |
9391 | if (isl_basic_map_plain_is_universe(bmap)) |
9392 | return isl_bool_false; |
9393 | |
9394 | if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) { |
9395 | struct isl_basic_map *copy = isl_basic_map_copy(bmap); |
9396 | copy = isl_basic_map_remove_redundancies(bmap: copy); |
9397 | empty = isl_basic_map_plain_is_empty(bmap: copy); |
9398 | isl_basic_map_free(bmap: copy); |
9399 | return empty; |
9400 | } |
9401 | |
9402 | non_empty = isl_basic_map_plain_is_non_empty(bmap); |
9403 | if (non_empty < 0) |
9404 | return isl_bool_error; |
9405 | if (non_empty) |
9406 | return isl_bool_false; |
9407 | isl_vec_free(vec: bmap->sample); |
9408 | bmap->sample = NULL; |
9409 | bset = isl_basic_map_underlying_set(bmap: isl_basic_map_copy(bmap)); |
9410 | if (!bset) |
9411 | return isl_bool_error; |
9412 | sample = isl_basic_set_sample_vec(bset); |
9413 | if (!sample) |
9414 | return isl_bool_error; |
9415 | empty = sample->size == 0; |
9416 | isl_vec_free(vec: bmap->sample); |
9417 | bmap->sample = sample; |
9418 | if (empty) |
9419 | ISL_F_SET(bmap, ISL_BASIC_MAP_EMPTY); |
9420 | |
9421 | return empty; |
9422 | } |
9423 | |
9424 | isl_bool isl_basic_map_plain_is_empty(__isl_keep isl_basic_map *bmap) |
9425 | { |
9426 | if (!bmap) |
9427 | return isl_bool_error; |
9428 | return ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY); |
9429 | } |
9430 | |
9431 | isl_bool isl_basic_set_plain_is_empty(__isl_keep isl_basic_set *bset) |
9432 | { |
9433 | if (!bset) |
9434 | return isl_bool_error; |
9435 | return ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY); |
9436 | } |
9437 | |
9438 | /* Is "bmap" known to be non-empty? |
9439 | * |
9440 | * That is, is the cached sample still valid? |
9441 | */ |
9442 | isl_bool isl_basic_map_plain_is_non_empty(__isl_keep isl_basic_map *bmap) |
9443 | { |
9444 | isl_size total; |
9445 | |
9446 | if (!bmap) |
9447 | return isl_bool_error; |
9448 | if (!bmap->sample) |
9449 | return isl_bool_false; |
9450 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
9451 | if (total < 0) |
9452 | return isl_bool_error; |
9453 | if (bmap->sample->size != 1 + total) |
9454 | return isl_bool_false; |
9455 | return isl_basic_map_contains(bmap, vec: bmap->sample); |
9456 | } |
9457 | |
9458 | isl_bool isl_basic_set_is_empty(__isl_keep isl_basic_set *bset) |
9459 | { |
9460 | return isl_basic_map_is_empty(bmap: bset_to_bmap(bset)); |
9461 | } |
9462 | |
9463 | __isl_give isl_map *isl_basic_map_union(__isl_take isl_basic_map *bmap1, |
9464 | __isl_take isl_basic_map *bmap2) |
9465 | { |
9466 | struct isl_map *map; |
9467 | |
9468 | if (isl_basic_map_check_equal_space(obj1: bmap1, obj2: bmap2) < 0) |
9469 | goto error; |
9470 | |
9471 | map = isl_map_alloc_space(space: isl_space_copy(space: bmap1->dim), n: 2, flags: 0); |
9472 | if (!map) |
9473 | goto error; |
9474 | map = isl_map_add_basic_map(map, bmap: bmap1); |
9475 | map = isl_map_add_basic_map(map, bmap: bmap2); |
9476 | return map; |
9477 | error: |
9478 | isl_basic_map_free(bmap: bmap1); |
9479 | isl_basic_map_free(bmap: bmap2); |
9480 | return NULL; |
9481 | } |
9482 | |
9483 | __isl_give isl_set *isl_basic_set_union(__isl_take isl_basic_set *bset1, |
9484 | __isl_take isl_basic_set *bset2) |
9485 | { |
9486 | return set_from_map(isl_basic_map_union(bmap1: bset_to_bmap(bset: bset1), |
9487 | bmap2: bset_to_bmap(bset: bset2))); |
9488 | } |
9489 | |
9490 | /* Order divs such that any div only depends on previous divs */ |
9491 | __isl_give isl_basic_map *isl_basic_map_order_divs( |
9492 | __isl_take isl_basic_map *bmap) |
9493 | { |
9494 | int i; |
9495 | isl_size off; |
9496 | |
9497 | off = isl_basic_map_var_offset(bmap, type: isl_dim_div); |
9498 | if (off < 0) |
9499 | return isl_basic_map_free(bmap); |
9500 | |
9501 | for (i = 0; i < bmap->n_div; ++i) { |
9502 | int pos; |
9503 | if (isl_int_is_zero(bmap->div[i][0])) |
9504 | continue; |
9505 | pos = isl_seq_first_non_zero(p: bmap->div[i]+1+1+off+i, |
9506 | len: bmap->n_div-i); |
9507 | if (pos == -1) |
9508 | continue; |
9509 | if (pos == 0) |
9510 | isl_die(isl_basic_map_get_ctx(bmap), isl_error_internal, |
9511 | "integer division depends on itself" , |
9512 | return isl_basic_map_free(bmap)); |
9513 | bmap = isl_basic_map_swap_div(bmap, a: i, b: i + pos); |
9514 | if (!bmap) |
9515 | return NULL; |
9516 | --i; |
9517 | } |
9518 | return bmap; |
9519 | } |
9520 | |
9521 | __isl_give isl_map *isl_map_order_divs(__isl_take isl_map *map) |
9522 | { |
9523 | int i; |
9524 | |
9525 | if (!map) |
9526 | return 0; |
9527 | |
9528 | for (i = 0; i < map->n; ++i) { |
9529 | map->p[i] = isl_basic_map_order_divs(bmap: map->p[i]); |
9530 | if (!map->p[i]) |
9531 | goto error; |
9532 | } |
9533 | |
9534 | return map; |
9535 | error: |
9536 | isl_map_free(map); |
9537 | return NULL; |
9538 | } |
9539 | |
9540 | /* Sort the local variables of "bset". |
9541 | */ |
9542 | __isl_give isl_basic_set *isl_basic_set_sort_divs( |
9543 | __isl_take isl_basic_set *bset) |
9544 | { |
9545 | return bset_from_bmap(bmap: isl_basic_map_sort_divs(bmap: bset_to_bmap(bset))); |
9546 | } |
9547 | |
9548 | /* Apply the expansion computed by isl_merge_divs. |
9549 | * The expansion itself is given by "exp" while the resulting |
9550 | * list of divs is given by "div". |
9551 | * |
9552 | * Move the integer divisions of "bmap" into the right position |
9553 | * according to "exp" and then introduce the additional integer |
9554 | * divisions, adding div constraints. |
9555 | * The moving should be done first to avoid moving coefficients |
9556 | * in the definitions of the extra integer divisions. |
9557 | */ |
9558 | __isl_give isl_basic_map *isl_basic_map_expand_divs( |
9559 | __isl_take isl_basic_map *bmap, __isl_take isl_mat *div, int *exp) |
9560 | { |
9561 | int i, j; |
9562 | int n_div; |
9563 | |
9564 | bmap = isl_basic_map_cow(bmap); |
9565 | if (!bmap || !div) |
9566 | goto error; |
9567 | |
9568 | if (div->n_row < bmap->n_div) |
9569 | isl_die(isl_mat_get_ctx(div), isl_error_invalid, |
9570 | "not an expansion" , goto error); |
9571 | |
9572 | n_div = bmap->n_div; |
9573 | bmap = isl_basic_map_extend(base: bmap, extra: div->n_row - n_div, n_eq: 0, |
9574 | n_ineq: 2 * (div->n_row - n_div)); |
9575 | |
9576 | for (i = n_div; i < div->n_row; ++i) |
9577 | if (isl_basic_map_alloc_div(bmap) < 0) |
9578 | goto error; |
9579 | |
9580 | for (j = n_div - 1; j >= 0; --j) { |
9581 | if (exp[j] == j) |
9582 | break; |
9583 | bmap = isl_basic_map_swap_div(bmap, a: j, b: exp[j]); |
9584 | if (!bmap) |
9585 | goto error; |
9586 | } |
9587 | j = 0; |
9588 | for (i = 0; i < div->n_row; ++i) { |
9589 | if (j < n_div && exp[j] == i) { |
9590 | j++; |
9591 | } else { |
9592 | isl_seq_cpy(dst: bmap->div[i], src: div->row[i], len: div->n_col); |
9593 | if (isl_basic_map_div_is_marked_unknown(bmap, div: i)) |
9594 | continue; |
9595 | bmap = isl_basic_map_add_div_constraints(bmap, pos: i); |
9596 | if (!bmap) |
9597 | goto error; |
9598 | } |
9599 | } |
9600 | |
9601 | isl_mat_free(mat: div); |
9602 | return bmap; |
9603 | error: |
9604 | isl_basic_map_free(bmap); |
9605 | isl_mat_free(mat: div); |
9606 | return NULL; |
9607 | } |
9608 | |
9609 | /* Apply the expansion computed by isl_merge_divs. |
9610 | * The expansion itself is given by "exp" while the resulting |
9611 | * list of divs is given by "div". |
9612 | */ |
9613 | __isl_give isl_basic_set *isl_basic_set_expand_divs( |
9614 | __isl_take isl_basic_set *bset, __isl_take isl_mat *div, int *exp) |
9615 | { |
9616 | return isl_basic_map_expand_divs(bmap: bset, div, exp); |
9617 | } |
9618 | |
9619 | /* Look for a div in dst that corresponds to the div "div" in src. |
9620 | * The divs before "div" in src and dst are assumed to be the same. |
9621 | * |
9622 | * Return the position of the corresponding div in dst |
9623 | * if there is one. Otherwise, return a position beyond the integer divisions. |
9624 | * Return -1 on error. |
9625 | */ |
9626 | static int find_div(__isl_keep isl_basic_map *dst, |
9627 | __isl_keep isl_basic_map *src, unsigned div) |
9628 | { |
9629 | int i; |
9630 | isl_size n_div; |
9631 | isl_size v_div; |
9632 | |
9633 | v_div = isl_basic_map_var_offset(bmap: src, type: isl_dim_div); |
9634 | n_div = isl_basic_map_dim(bmap: dst, type: isl_dim_div); |
9635 | if (n_div < 0 || v_div < 0) |
9636 | return -1; |
9637 | isl_assert(dst->ctx, div <= n_div, return -1); |
9638 | for (i = div; i < n_div; ++i) |
9639 | if (isl_seq_eq(p1: dst->div[i], p2: src->div[div], len: 1+1+v_div+div) && |
9640 | isl_seq_first_non_zero(p: dst->div[i] + 1 + 1 + v_div + div, |
9641 | len: n_div - div) == -1) |
9642 | return i; |
9643 | return n_div; |
9644 | } |
9645 | |
9646 | /* Align the divs of "dst" to those of "src", adding divs from "src" |
9647 | * if needed. That is, make sure that the first src->n_div divs |
9648 | * of the result are equal to those of src. |
9649 | * The integer division of "src" are assumed to be ordered. |
9650 | * |
9651 | * The integer divisions are swapped into the right position |
9652 | * (possibly after adding them first). This may result |
9653 | * in the remaining integer divisions appearing in the wrong order, |
9654 | * i.e., with some integer division appearing before |
9655 | * some other integer division on which it depends. |
9656 | * The integer divisions therefore need to be ordered. |
9657 | * This will not affect the integer divisions aligned to those of "src", |
9658 | * since "src" is assumed to have ordered integer divisions. |
9659 | * |
9660 | * The result is not finalized as by design it will have redundant |
9661 | * divs if any divs from "src" were copied. |
9662 | */ |
9663 | __isl_give isl_basic_map *isl_basic_map_align_divs( |
9664 | __isl_take isl_basic_map *dst, __isl_keep isl_basic_map *src) |
9665 | { |
9666 | int i; |
9667 | isl_bool known; |
9668 | int extended; |
9669 | isl_size v_div; |
9670 | isl_size dst_n_div; |
9671 | |
9672 | if (!dst || !src) |
9673 | return isl_basic_map_free(bmap: dst); |
9674 | |
9675 | if (src->n_div == 0) |
9676 | return dst; |
9677 | |
9678 | known = isl_basic_map_divs_known(bmap: src); |
9679 | if (known < 0) |
9680 | return isl_basic_map_free(bmap: dst); |
9681 | if (!known) |
9682 | isl_die(isl_basic_map_get_ctx(src), isl_error_invalid, |
9683 | "some src divs are unknown" , |
9684 | return isl_basic_map_free(dst)); |
9685 | |
9686 | v_div = isl_basic_map_var_offset(bmap: src, type: isl_dim_div); |
9687 | if (v_div < 0) |
9688 | return isl_basic_map_free(bmap: dst); |
9689 | |
9690 | extended = 0; |
9691 | dst_n_div = isl_basic_map_dim(bmap: dst, type: isl_dim_div); |
9692 | if (dst_n_div < 0) |
9693 | dst = isl_basic_map_free(bmap: dst); |
9694 | for (i = 0; i < src->n_div; ++i) { |
9695 | int j = find_div(dst, src, div: i); |
9696 | if (j < 0) |
9697 | dst = isl_basic_map_free(bmap: dst); |
9698 | if (j == dst_n_div) { |
9699 | if (!extended) { |
9700 | int = src->n_div - i; |
9701 | dst = isl_basic_map_cow(bmap: dst); |
9702 | if (!dst) |
9703 | return isl_basic_map_free(bmap: dst); |
9704 | dst = isl_basic_map_extend(base: dst, |
9705 | extra, n_eq: 0, n_ineq: 2 * extra); |
9706 | extended = 1; |
9707 | } |
9708 | j = isl_basic_map_alloc_div(bmap: dst); |
9709 | if (j < 0) |
9710 | return isl_basic_map_free(bmap: dst); |
9711 | isl_seq_cpy(dst: dst->div[j], src: src->div[i], len: 1+1+v_div+i); |
9712 | isl_seq_clr(p: dst->div[j]+1+1+v_div+i, len: dst->n_div - i); |
9713 | dst_n_div++; |
9714 | dst = isl_basic_map_add_div_constraints(bmap: dst, pos: j); |
9715 | if (!dst) |
9716 | return isl_basic_map_free(bmap: dst); |
9717 | } |
9718 | if (j != i) |
9719 | dst = isl_basic_map_swap_div(bmap: dst, a: i, b: j); |
9720 | if (!dst) |
9721 | return isl_basic_map_free(bmap: dst); |
9722 | } |
9723 | return isl_basic_map_order_divs(bmap: dst); |
9724 | } |
9725 | |
9726 | __isl_give isl_map *isl_map_align_divs_internal(__isl_take isl_map *map) |
9727 | { |
9728 | int i; |
9729 | |
9730 | if (!map) |
9731 | return NULL; |
9732 | if (map->n == 0) |
9733 | return map; |
9734 | map = isl_map_compute_divs(map); |
9735 | map = isl_map_order_divs(map); |
9736 | map = isl_map_cow(map); |
9737 | if (!map) |
9738 | return NULL; |
9739 | |
9740 | for (i = 1; i < map->n; ++i) |
9741 | map->p[0] = isl_basic_map_align_divs(dst: map->p[0], src: map->p[i]); |
9742 | for (i = 1; i < map->n; ++i) { |
9743 | map->p[i] = isl_basic_map_align_divs(dst: map->p[i], src: map->p[0]); |
9744 | if (!map->p[i]) |
9745 | return isl_map_free(map); |
9746 | } |
9747 | |
9748 | map = isl_map_unmark_normalized(map); |
9749 | return map; |
9750 | } |
9751 | |
9752 | __isl_give isl_map *isl_map_align_divs(__isl_take isl_map *map) |
9753 | { |
9754 | return isl_map_align_divs_internal(map); |
9755 | } |
9756 | |
9757 | __isl_give isl_set *isl_set_align_divs(__isl_take isl_set *set) |
9758 | { |
9759 | return set_from_map(isl_map_align_divs_internal(map: set_to_map(set))); |
9760 | } |
9761 | |
9762 | /* Align the divs of the basic maps in "map" to those |
9763 | * of the basic maps in "list", as well as to the other basic maps in "map". |
9764 | * The elements in "list" are assumed to have known divs. |
9765 | */ |
9766 | __isl_give isl_map *isl_map_align_divs_to_basic_map_list( |
9767 | __isl_take isl_map *map, __isl_keep isl_basic_map_list *list) |
9768 | { |
9769 | int i; |
9770 | isl_size n; |
9771 | |
9772 | n = isl_basic_map_list_n_basic_map(list); |
9773 | map = isl_map_compute_divs(map); |
9774 | map = isl_map_cow(map); |
9775 | if (!map || n < 0) |
9776 | return isl_map_free(map); |
9777 | if (map->n == 0) |
9778 | return map; |
9779 | |
9780 | for (i = 0; i < n; ++i) { |
9781 | isl_basic_map *bmap; |
9782 | |
9783 | bmap = isl_basic_map_list_get_basic_map(list, index: i); |
9784 | bmap = isl_basic_map_order_divs(bmap); |
9785 | map->p[0] = isl_basic_map_align_divs(dst: map->p[0], src: bmap); |
9786 | isl_basic_map_free(bmap); |
9787 | } |
9788 | if (!map->p[0]) |
9789 | return isl_map_free(map); |
9790 | |
9791 | return isl_map_align_divs_internal(map); |
9792 | } |
9793 | |
9794 | /* Align the divs of each element of "list" to those of "bmap". |
9795 | * Both "bmap" and the elements of "list" are assumed to have known divs. |
9796 | */ |
9797 | __isl_give isl_basic_map_list *isl_basic_map_list_align_divs_to_basic_map( |
9798 | __isl_take isl_basic_map_list *list, __isl_keep isl_basic_map *bmap) |
9799 | { |
9800 | int i; |
9801 | isl_size n; |
9802 | |
9803 | n = isl_basic_map_list_n_basic_map(list); |
9804 | if (n < 0 || !bmap) |
9805 | return isl_basic_map_list_free(list); |
9806 | |
9807 | for (i = 0; i < n; ++i) { |
9808 | isl_basic_map *bmap_i; |
9809 | |
9810 | bmap_i = isl_basic_map_list_get_basic_map(list, index: i); |
9811 | bmap_i = isl_basic_map_align_divs(dst: bmap_i, src: bmap); |
9812 | list = isl_basic_map_list_set_basic_map(list, index: i, el: bmap_i); |
9813 | } |
9814 | |
9815 | return list; |
9816 | } |
9817 | |
9818 | __isl_give isl_set *isl_set_apply( __isl_take isl_set *set, |
9819 | __isl_take isl_map *map) |
9820 | { |
9821 | isl_bool ok; |
9822 | |
9823 | isl_map_align_params_set(obj1: &map, obj2: &set); |
9824 | ok = isl_map_compatible_domain(map, set); |
9825 | if (ok < 0) |
9826 | goto error; |
9827 | if (!ok) |
9828 | isl_die(isl_set_get_ctx(set), isl_error_invalid, |
9829 | "incompatible spaces" , goto error); |
9830 | map = isl_map_intersect_domain(map, set); |
9831 | set = isl_map_range(map); |
9832 | return set; |
9833 | error: |
9834 | isl_set_free(set); |
9835 | isl_map_free(map); |
9836 | return NULL; |
9837 | } |
9838 | |
9839 | /* There is no need to cow as removing empty parts doesn't change |
9840 | * the meaning of the set. |
9841 | */ |
9842 | __isl_give isl_map *isl_map_remove_empty_parts(__isl_take isl_map *map) |
9843 | { |
9844 | int i; |
9845 | |
9846 | if (!map) |
9847 | return NULL; |
9848 | |
9849 | for (i = map->n - 1; i >= 0; --i) |
9850 | map = remove_if_empty(map, i); |
9851 | |
9852 | return map; |
9853 | } |
9854 | |
9855 | __isl_give isl_set *isl_set_remove_empty_parts(__isl_take isl_set *set) |
9856 | { |
9857 | return set_from_map(isl_map_remove_empty_parts(map: set_to_map(set))); |
9858 | } |
9859 | |
9860 | /* Create a binary relation that maps the shared initial "pos" dimensions |
9861 | * of "bset1" and "bset2" to the remaining dimensions of "bset1" and "bset2". |
9862 | */ |
9863 | static __isl_give isl_basic_map *join_initial(__isl_keep isl_basic_set *bset1, |
9864 | __isl_keep isl_basic_set *bset2, int pos) |
9865 | { |
9866 | isl_basic_map *bmap1; |
9867 | isl_basic_map *bmap2; |
9868 | |
9869 | bmap1 = isl_basic_map_from_range(bset: isl_basic_set_copy(bset: bset1)); |
9870 | bmap2 = isl_basic_map_from_range(bset: isl_basic_set_copy(bset: bset2)); |
9871 | bmap1 = isl_basic_map_move_dims(bmap: bmap1, dst_type: isl_dim_in, dst_pos: 0, |
9872 | src_type: isl_dim_out, src_pos: 0, n: pos); |
9873 | bmap2 = isl_basic_map_move_dims(bmap: bmap2, dst_type: isl_dim_in, dst_pos: 0, |
9874 | src_type: isl_dim_out, src_pos: 0, n: pos); |
9875 | return isl_basic_map_range_product(bmap1, bmap2); |
9876 | } |
9877 | |
9878 | /* Given two basic sets bset1 and bset2, compute the maximal difference |
9879 | * between the values of dimension pos in bset1 and those in bset2 |
9880 | * for any common value of the parameters and dimensions preceding pos. |
9881 | */ |
9882 | static enum isl_lp_result basic_set_maximal_difference_at( |
9883 | __isl_keep isl_basic_set *bset1, __isl_keep isl_basic_set *bset2, |
9884 | int pos, isl_int *opt) |
9885 | { |
9886 | isl_basic_map *bmap1; |
9887 | struct isl_ctx *ctx; |
9888 | struct isl_vec *obj; |
9889 | isl_size total; |
9890 | isl_size nparam; |
9891 | isl_size dim1; |
9892 | enum isl_lp_result res; |
9893 | |
9894 | nparam = isl_basic_set_dim(bset: bset1, type: isl_dim_param); |
9895 | dim1 = isl_basic_set_dim(bset: bset1, type: isl_dim_set); |
9896 | if (nparam < 0 || dim1 < 0 || !bset2) |
9897 | return isl_lp_error; |
9898 | |
9899 | bmap1 = join_initial(bset1, bset2, pos); |
9900 | total = isl_basic_map_dim(bmap: bmap1, type: isl_dim_all); |
9901 | if (total < 0) |
9902 | return isl_lp_error; |
9903 | |
9904 | ctx = bmap1->ctx; |
9905 | obj = isl_vec_alloc(ctx, size: 1 + total); |
9906 | if (!obj) |
9907 | goto error; |
9908 | isl_seq_clr(p: obj->block.data, len: 1 + total); |
9909 | isl_int_set_si(obj->block.data[1+nparam+pos], 1); |
9910 | isl_int_set_si(obj->block.data[1+nparam+pos+(dim1-pos)], -1); |
9911 | res = isl_basic_map_solve_lp(bmap: bmap1, max: 1, f: obj->block.data, denom: ctx->one, |
9912 | opt, NULL, NULL); |
9913 | isl_basic_map_free(bmap: bmap1); |
9914 | isl_vec_free(vec: obj); |
9915 | return res; |
9916 | error: |
9917 | isl_basic_map_free(bmap: bmap1); |
9918 | return isl_lp_error; |
9919 | } |
9920 | |
9921 | /* Given two _disjoint_ basic sets bset1 and bset2, check whether |
9922 | * for any common value of the parameters and dimensions preceding pos |
9923 | * in both basic sets, the values of dimension pos in bset1 are |
9924 | * smaller or larger than those in bset2. |
9925 | * |
9926 | * Returns |
9927 | * 1 if bset1 follows bset2 |
9928 | * -1 if bset1 precedes bset2 |
9929 | * 0 if bset1 and bset2 are incomparable |
9930 | * -2 if some error occurred. |
9931 | */ |
9932 | int isl_basic_set_compare_at(__isl_keep isl_basic_set *bset1, |
9933 | __isl_keep isl_basic_set *bset2, int pos) |
9934 | { |
9935 | isl_int opt; |
9936 | enum isl_lp_result res; |
9937 | int cmp; |
9938 | |
9939 | isl_int_init(opt); |
9940 | |
9941 | res = basic_set_maximal_difference_at(bset1, bset2, pos, opt: &opt); |
9942 | |
9943 | if (res == isl_lp_empty) |
9944 | cmp = 0; |
9945 | else if ((res == isl_lp_ok && isl_int_is_pos(opt)) || |
9946 | res == isl_lp_unbounded) |
9947 | cmp = 1; |
9948 | else if (res == isl_lp_ok && isl_int_is_neg(opt)) |
9949 | cmp = -1; |
9950 | else |
9951 | cmp = -2; |
9952 | |
9953 | isl_int_clear(opt); |
9954 | return cmp; |
9955 | } |
9956 | |
9957 | /* Given two basic sets bset1 and bset2, check whether |
9958 | * for any common value of the parameters and dimensions preceding pos |
9959 | * there is a value of dimension pos in bset1 that is larger |
9960 | * than a value of the same dimension in bset2. |
9961 | * |
9962 | * Return |
9963 | * 1 if there exists such a pair |
9964 | * 0 if there is no such pair, but there is a pair of equal values |
9965 | * -1 otherwise |
9966 | * -2 if some error occurred. |
9967 | */ |
9968 | int isl_basic_set_follows_at(__isl_keep isl_basic_set *bset1, |
9969 | __isl_keep isl_basic_set *bset2, int pos) |
9970 | { |
9971 | isl_bool empty; |
9972 | isl_basic_map *bmap; |
9973 | isl_size dim1; |
9974 | |
9975 | dim1 = isl_basic_set_dim(bset: bset1, type: isl_dim_set); |
9976 | if (dim1 < 0) |
9977 | return -2; |
9978 | bmap = join_initial(bset1, bset2, pos); |
9979 | bmap = isl_basic_map_order_ge(bmap, type1: isl_dim_out, pos1: 0, |
9980 | type2: isl_dim_out, pos2: dim1 - pos); |
9981 | empty = isl_basic_map_is_empty(bmap); |
9982 | if (empty < 0) |
9983 | goto error; |
9984 | if (empty) { |
9985 | isl_basic_map_free(bmap); |
9986 | return -1; |
9987 | } |
9988 | bmap = isl_basic_map_order_gt(bmap, type1: isl_dim_out, pos1: 0, |
9989 | type2: isl_dim_out, pos2: dim1 - pos); |
9990 | empty = isl_basic_map_is_empty(bmap); |
9991 | if (empty < 0) |
9992 | goto error; |
9993 | isl_basic_map_free(bmap); |
9994 | if (empty) |
9995 | return 0; |
9996 | return 1; |
9997 | error: |
9998 | isl_basic_map_free(bmap); |
9999 | return -2; |
10000 | } |
10001 | |
10002 | /* Given two sets set1 and set2, check whether |
10003 | * for any common value of the parameters and dimensions preceding pos |
10004 | * there is a value of dimension pos in set1 that is larger |
10005 | * than a value of the same dimension in set2. |
10006 | * |
10007 | * Return |
10008 | * 1 if there exists such a pair |
10009 | * 0 if there is no such pair, but there is a pair of equal values |
10010 | * -1 otherwise |
10011 | * -2 if some error occurred. |
10012 | */ |
10013 | int isl_set_follows_at(__isl_keep isl_set *set1, |
10014 | __isl_keep isl_set *set2, int pos) |
10015 | { |
10016 | int i, j; |
10017 | int follows = -1; |
10018 | |
10019 | if (!set1 || !set2) |
10020 | return -2; |
10021 | |
10022 | for (i = 0; i < set1->n; ++i) |
10023 | for (j = 0; j < set2->n; ++j) { |
10024 | int f; |
10025 | f = isl_basic_set_follows_at(bset1: set1->p[i], bset2: set2->p[j], pos); |
10026 | if (f == 1 || f == -2) |
10027 | return f; |
10028 | if (f > follows) |
10029 | follows = f; |
10030 | } |
10031 | |
10032 | return follows; |
10033 | } |
10034 | |
10035 | static isl_bool isl_basic_map_plain_has_fixed_var( |
10036 | __isl_keep isl_basic_map *bmap, unsigned pos, isl_int *val) |
10037 | { |
10038 | int i; |
10039 | int d; |
10040 | isl_size total; |
10041 | |
10042 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
10043 | if (total < 0) |
10044 | return isl_bool_error; |
10045 | for (i = 0, d = total-1; i < bmap->n_eq && d+1 > pos; ++i) { |
10046 | for (; d+1 > pos; --d) |
10047 | if (!isl_int_is_zero(bmap->eq[i][1+d])) |
10048 | break; |
10049 | if (d != pos) |
10050 | continue; |
10051 | if (isl_seq_first_non_zero(p: bmap->eq[i]+1, len: d) != -1) |
10052 | return isl_bool_false; |
10053 | if (isl_seq_first_non_zero(p: bmap->eq[i]+1+d+1, len: total-d-1) != -1) |
10054 | return isl_bool_false; |
10055 | if (!isl_int_is_one(bmap->eq[i][1+d])) |
10056 | return isl_bool_false; |
10057 | if (val) |
10058 | isl_int_neg(*val, bmap->eq[i][0]); |
10059 | return isl_bool_true; |
10060 | } |
10061 | return isl_bool_false; |
10062 | } |
10063 | |
10064 | static isl_bool isl_map_plain_has_fixed_var(__isl_keep isl_map *map, |
10065 | unsigned pos, isl_int *val) |
10066 | { |
10067 | int i; |
10068 | isl_int v; |
10069 | isl_int tmp; |
10070 | isl_bool fixed; |
10071 | |
10072 | if (!map) |
10073 | return isl_bool_error; |
10074 | if (map->n == 0) |
10075 | return isl_bool_false; |
10076 | if (map->n == 1) |
10077 | return isl_basic_map_plain_has_fixed_var(bmap: map->p[0], pos, val); |
10078 | isl_int_init(v); |
10079 | isl_int_init(tmp); |
10080 | fixed = isl_basic_map_plain_has_fixed_var(bmap: map->p[0], pos, val: &v); |
10081 | for (i = 1; fixed == isl_bool_true && i < map->n; ++i) { |
10082 | fixed = isl_basic_map_plain_has_fixed_var(bmap: map->p[i], pos, val: &tmp); |
10083 | if (fixed == isl_bool_true && isl_int_ne(tmp, v)) |
10084 | fixed = isl_bool_false; |
10085 | } |
10086 | if (val) |
10087 | isl_int_set(*val, v); |
10088 | isl_int_clear(tmp); |
10089 | isl_int_clear(v); |
10090 | return fixed; |
10091 | } |
10092 | |
10093 | static isl_bool isl_basic_set_plain_has_fixed_var( |
10094 | __isl_keep isl_basic_set *bset, unsigned pos, isl_int *val) |
10095 | { |
10096 | return isl_basic_map_plain_has_fixed_var(bmap: bset_to_bmap(bset), |
10097 | pos, val); |
10098 | } |
10099 | |
10100 | isl_bool isl_basic_map_plain_is_fixed(__isl_keep isl_basic_map *bmap, |
10101 | enum isl_dim_type type, unsigned pos, isl_int *val) |
10102 | { |
10103 | if (isl_basic_map_check_range(obj: bmap, type, first: pos, n: 1) < 0) |
10104 | return isl_bool_error; |
10105 | return isl_basic_map_plain_has_fixed_var(bmap, |
10106 | pos: isl_basic_map_offset(bmap, type) - 1 + pos, val); |
10107 | } |
10108 | |
10109 | /* If "bmap" obviously lies on a hyperplane where the given dimension |
10110 | * has a fixed value, then return that value. |
10111 | * Otherwise return NaN. |
10112 | */ |
10113 | __isl_give isl_val *isl_basic_map_plain_get_val_if_fixed( |
10114 | __isl_keep isl_basic_map *bmap, |
10115 | enum isl_dim_type type, unsigned pos) |
10116 | { |
10117 | isl_ctx *ctx; |
10118 | isl_val *v; |
10119 | isl_bool fixed; |
10120 | |
10121 | if (!bmap) |
10122 | return NULL; |
10123 | ctx = isl_basic_map_get_ctx(bmap); |
10124 | v = isl_val_alloc(ctx); |
10125 | if (!v) |
10126 | return NULL; |
10127 | fixed = isl_basic_map_plain_is_fixed(bmap, type, pos, val: &v->n); |
10128 | if (fixed < 0) |
10129 | return isl_val_free(v); |
10130 | if (fixed) { |
10131 | isl_int_set_si(v->d, 1); |
10132 | return v; |
10133 | } |
10134 | isl_val_free(v); |
10135 | return isl_val_nan(ctx); |
10136 | } |
10137 | |
10138 | isl_bool isl_map_plain_is_fixed(__isl_keep isl_map *map, |
10139 | enum isl_dim_type type, unsigned pos, isl_int *val) |
10140 | { |
10141 | if (isl_map_check_range(obj: map, type, first: pos, n: 1) < 0) |
10142 | return isl_bool_error; |
10143 | return isl_map_plain_has_fixed_var(map, |
10144 | pos: map_offset(map, type) - 1 + pos, val); |
10145 | } |
10146 | |
10147 | /* If "map" obviously lies on a hyperplane where the given dimension |
10148 | * has a fixed value, then return that value. |
10149 | * Otherwise return NaN. |
10150 | */ |
10151 | __isl_give isl_val *isl_map_plain_get_val_if_fixed(__isl_keep isl_map *map, |
10152 | enum isl_dim_type type, unsigned pos) |
10153 | { |
10154 | isl_ctx *ctx; |
10155 | isl_val *v; |
10156 | isl_bool fixed; |
10157 | |
10158 | if (!map) |
10159 | return NULL; |
10160 | ctx = isl_map_get_ctx(map); |
10161 | v = isl_val_alloc(ctx); |
10162 | if (!v) |
10163 | return NULL; |
10164 | fixed = isl_map_plain_is_fixed(map, type, pos, val: &v->n); |
10165 | if (fixed < 0) |
10166 | return isl_val_free(v); |
10167 | if (fixed) { |
10168 | isl_int_set_si(v->d, 1); |
10169 | return v; |
10170 | } |
10171 | isl_val_free(v); |
10172 | return isl_val_nan(ctx); |
10173 | } |
10174 | |
10175 | /* If "set" obviously lies on a hyperplane where the given dimension |
10176 | * has a fixed value, then return that value. |
10177 | * Otherwise return NaN. |
10178 | */ |
10179 | __isl_give isl_val *isl_set_plain_get_val_if_fixed(__isl_keep isl_set *set, |
10180 | enum isl_dim_type type, unsigned pos) |
10181 | { |
10182 | return isl_map_plain_get_val_if_fixed(map: set, type, pos); |
10183 | } |
10184 | |
10185 | /* Return a sequence of values in the same space as "set" |
10186 | * that are equal to the corresponding set dimensions of "set" |
10187 | * for those set dimensions that obviously lie on a hyperplane |
10188 | * where the dimension has a fixed value. |
10189 | * The other elements are set to NaN. |
10190 | */ |
10191 | __isl_give isl_multi_val *isl_set_get_plain_multi_val_if_fixed( |
10192 | __isl_keep isl_set *set) |
10193 | { |
10194 | int i; |
10195 | isl_size n; |
10196 | isl_space *space; |
10197 | isl_multi_val *mv; |
10198 | |
10199 | space = isl_space_drop_all_params(space: isl_set_get_space(set)); |
10200 | mv = isl_multi_val_alloc(space); |
10201 | n = isl_multi_val_size(multi: mv); |
10202 | if (n < 0) |
10203 | return isl_multi_val_free(multi: mv); |
10204 | |
10205 | for (i = 0; i < n; ++i) { |
10206 | isl_val *v; |
10207 | |
10208 | v = isl_set_plain_get_val_if_fixed(set, type: isl_dim_set, pos: i); |
10209 | mv = isl_multi_val_set_val(multi: mv, pos: i, el: v); |
10210 | } |
10211 | |
10212 | return mv; |
10213 | } |
10214 | |
10215 | /* Check if dimension dim has fixed value and if so and if val is not NULL, |
10216 | * then return this fixed value in *val. |
10217 | */ |
10218 | isl_bool isl_basic_set_plain_dim_is_fixed(__isl_keep isl_basic_set *bset, |
10219 | unsigned dim, isl_int *val) |
10220 | { |
10221 | isl_size nparam; |
10222 | |
10223 | nparam = isl_basic_set_dim(bset, type: isl_dim_param); |
10224 | if (nparam < 0) |
10225 | return isl_bool_error; |
10226 | return isl_basic_set_plain_has_fixed_var(bset, pos: nparam + dim, val); |
10227 | } |
10228 | |
10229 | /* Return -1 if the constraint "c1" should be sorted before "c2" |
10230 | * and 1 if it should be sorted after "c2". |
10231 | * Return 0 if the two constraints are the same (up to the constant term). |
10232 | * |
10233 | * In particular, if a constraint involves later variables than another |
10234 | * then it is sorted after this other constraint. |
10235 | * uset_gist depends on constraints without existentially quantified |
10236 | * variables sorting first. |
10237 | * |
10238 | * For constraints that have the same latest variable, those |
10239 | * with the same coefficient for this latest variable (first in absolute value |
10240 | * and then in actual value) are grouped together. |
10241 | * This is useful for detecting pairs of constraints that can |
10242 | * be chained in their printed representation. |
10243 | * |
10244 | * Finally, within a group, constraints are sorted according to |
10245 | * their coefficients (excluding the constant term). |
10246 | */ |
10247 | static int sort_constraint_cmp(const void *p1, const void *p2, void *arg) |
10248 | { |
10249 | isl_int **c1 = (isl_int **) p1; |
10250 | isl_int **c2 = (isl_int **) p2; |
10251 | int l1, l2; |
10252 | unsigned size = *(unsigned *) arg; |
10253 | int cmp; |
10254 | |
10255 | l1 = isl_seq_last_non_zero(p: *c1 + 1, len: size); |
10256 | l2 = isl_seq_last_non_zero(p: *c2 + 1, len: size); |
10257 | |
10258 | if (l1 != l2) |
10259 | return l1 - l2; |
10260 | |
10261 | cmp = isl_int_abs_cmp((*c1)[1 + l1], (*c2)[1 + l1]); |
10262 | if (cmp != 0) |
10263 | return cmp; |
10264 | cmp = isl_int_cmp((*c1)[1 + l1], (*c2)[1 + l1]); |
10265 | if (cmp != 0) |
10266 | return -cmp; |
10267 | |
10268 | return isl_seq_cmp(p1: *c1 + 1, p2: *c2 + 1, len: size); |
10269 | } |
10270 | |
10271 | /* Return -1 if the constraint "c1" of "bmap" is sorted before "c2" |
10272 | * by isl_basic_map_sort_constraints, 1 if it is sorted after "c2" |
10273 | * and 0 if the two constraints are the same (up to the constant term). |
10274 | */ |
10275 | int isl_basic_map_constraint_cmp(__isl_keep isl_basic_map *bmap, |
10276 | isl_int *c1, isl_int *c2) |
10277 | { |
10278 | isl_size total; |
10279 | unsigned size; |
10280 | |
10281 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
10282 | if (total < 0) |
10283 | return -2; |
10284 | size = total; |
10285 | return sort_constraint_cmp(p1: &c1, p2: &c2, arg: &size); |
10286 | } |
10287 | |
10288 | __isl_give isl_basic_map *isl_basic_map_sort_constraints( |
10289 | __isl_take isl_basic_map *bmap) |
10290 | { |
10291 | isl_size total; |
10292 | unsigned size; |
10293 | |
10294 | if (!bmap) |
10295 | return NULL; |
10296 | if (bmap->n_ineq == 0) |
10297 | return bmap; |
10298 | if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_SORTED)) |
10299 | return bmap; |
10300 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
10301 | if (total < 0) |
10302 | return isl_basic_map_free(bmap); |
10303 | size = total; |
10304 | if (isl_sort(pbase: bmap->ineq, total_elems: bmap->n_ineq, size: sizeof(isl_int *), |
10305 | cmp: &sort_constraint_cmp, arg: &size) < 0) |
10306 | return isl_basic_map_free(bmap); |
10307 | ISL_F_SET(bmap, ISL_BASIC_MAP_SORTED); |
10308 | return bmap; |
10309 | } |
10310 | |
10311 | __isl_give isl_basic_set *isl_basic_set_sort_constraints( |
10312 | __isl_take isl_basic_set *bset) |
10313 | { |
10314 | isl_basic_map *bmap = bset_to_bmap(bset); |
10315 | return bset_from_bmap(bmap: isl_basic_map_sort_constraints(bmap)); |
10316 | } |
10317 | |
10318 | __isl_give isl_basic_map *isl_basic_map_normalize( |
10319 | __isl_take isl_basic_map *bmap) |
10320 | { |
10321 | bmap = isl_basic_map_remove_redundancies(bmap); |
10322 | bmap = isl_basic_map_sort_constraints(bmap); |
10323 | return bmap; |
10324 | } |
10325 | int isl_basic_map_plain_cmp(__isl_keep isl_basic_map *bmap1, |
10326 | __isl_keep isl_basic_map *bmap2) |
10327 | { |
10328 | int i, cmp; |
10329 | isl_size total; |
10330 | isl_space *space1, *space2; |
10331 | |
10332 | if (!bmap1 || !bmap2) |
10333 | return -1; |
10334 | |
10335 | if (bmap1 == bmap2) |
10336 | return 0; |
10337 | space1 = isl_basic_map_peek_space(bmap: bmap1); |
10338 | space2 = isl_basic_map_peek_space(bmap: bmap2); |
10339 | cmp = isl_space_cmp(space1, space2); |
10340 | if (cmp) |
10341 | return cmp; |
10342 | if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_RATIONAL) != |
10343 | ISL_F_ISSET(bmap2, ISL_BASIC_MAP_RATIONAL)) |
10344 | return ISL_F_ISSET(bmap1, ISL_BASIC_MAP_RATIONAL) ? -1 : 1; |
10345 | if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_EMPTY) && |
10346 | ISL_F_ISSET(bmap2, ISL_BASIC_MAP_EMPTY)) |
10347 | return 0; |
10348 | if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_EMPTY)) |
10349 | return 1; |
10350 | if (ISL_F_ISSET(bmap2, ISL_BASIC_MAP_EMPTY)) |
10351 | return -1; |
10352 | if (bmap1->n_eq != bmap2->n_eq) |
10353 | return bmap1->n_eq - bmap2->n_eq; |
10354 | if (bmap1->n_ineq != bmap2->n_ineq) |
10355 | return bmap1->n_ineq - bmap2->n_ineq; |
10356 | if (bmap1->n_div != bmap2->n_div) |
10357 | return bmap1->n_div - bmap2->n_div; |
10358 | total = isl_basic_map_dim(bmap: bmap1, type: isl_dim_all); |
10359 | if (total < 0) |
10360 | return -1; |
10361 | for (i = 0; i < bmap1->n_eq; ++i) { |
10362 | cmp = isl_seq_cmp(p1: bmap1->eq[i], p2: bmap2->eq[i], len: 1+total); |
10363 | if (cmp) |
10364 | return cmp; |
10365 | } |
10366 | for (i = 0; i < bmap1->n_ineq; ++i) { |
10367 | cmp = isl_seq_cmp(p1: bmap1->ineq[i], p2: bmap2->ineq[i], len: 1+total); |
10368 | if (cmp) |
10369 | return cmp; |
10370 | } |
10371 | for (i = 0; i < bmap1->n_div; ++i) { |
10372 | isl_bool unknown1, unknown2; |
10373 | |
10374 | unknown1 = isl_basic_map_div_is_marked_unknown(bmap: bmap1, div: i); |
10375 | unknown2 = isl_basic_map_div_is_marked_unknown(bmap: bmap2, div: i); |
10376 | if (unknown1 < 0 || unknown2 < 0) |
10377 | return -1; |
10378 | if (unknown1 && unknown2) |
10379 | continue; |
10380 | if (unknown1) |
10381 | return 1; |
10382 | if (unknown2) |
10383 | return -1; |
10384 | cmp = isl_seq_cmp(p1: bmap1->div[i], p2: bmap2->div[i], len: 1+1+total); |
10385 | if (cmp) |
10386 | return cmp; |
10387 | } |
10388 | return 0; |
10389 | } |
10390 | |
10391 | int isl_basic_set_plain_cmp(__isl_keep isl_basic_set *bset1, |
10392 | __isl_keep isl_basic_set *bset2) |
10393 | { |
10394 | return isl_basic_map_plain_cmp(bmap1: bset1, bmap2: bset2); |
10395 | } |
10396 | |
10397 | int isl_set_plain_cmp(__isl_keep isl_set *set1, __isl_keep isl_set *set2) |
10398 | { |
10399 | int i, cmp; |
10400 | |
10401 | if (set1 == set2) |
10402 | return 0; |
10403 | if (set1->n != set2->n) |
10404 | return set1->n - set2->n; |
10405 | |
10406 | for (i = 0; i < set1->n; ++i) { |
10407 | cmp = isl_basic_set_plain_cmp(bset1: set1->p[i], bset2: set2->p[i]); |
10408 | if (cmp) |
10409 | return cmp; |
10410 | } |
10411 | |
10412 | return 0; |
10413 | } |
10414 | |
10415 | isl_bool isl_basic_map_plain_is_equal(__isl_keep isl_basic_map *bmap1, |
10416 | __isl_keep isl_basic_map *bmap2) |
10417 | { |
10418 | if (!bmap1 || !bmap2) |
10419 | return isl_bool_error; |
10420 | return isl_basic_map_plain_cmp(bmap1, bmap2) == 0; |
10421 | } |
10422 | |
10423 | isl_bool isl_basic_set_plain_is_equal(__isl_keep isl_basic_set *bset1, |
10424 | __isl_keep isl_basic_set *bset2) |
10425 | { |
10426 | return isl_basic_map_plain_is_equal(bmap1: bset_to_bmap(bset: bset1), |
10427 | bmap2: bset_to_bmap(bset: bset2)); |
10428 | } |
10429 | |
10430 | static int qsort_bmap_cmp(const void *p1, const void *p2) |
10431 | { |
10432 | isl_basic_map *bmap1 = *(isl_basic_map **) p1; |
10433 | isl_basic_map *bmap2 = *(isl_basic_map **) p2; |
10434 | |
10435 | return isl_basic_map_plain_cmp(bmap1, bmap2); |
10436 | } |
10437 | |
10438 | /* Sort the basic maps of "map" and remove duplicate basic maps. |
10439 | * |
10440 | * While removing basic maps, we make sure that the basic maps remain |
10441 | * sorted because isl_map_normalize expects the basic maps of the result |
10442 | * to be sorted. |
10443 | */ |
10444 | static __isl_give isl_map *sort_and_remove_duplicates(__isl_take isl_map *map) |
10445 | { |
10446 | int i, j; |
10447 | |
10448 | map = isl_map_remove_empty_parts(map); |
10449 | if (!map) |
10450 | return NULL; |
10451 | qsort(base: map->p, nmemb: map->n, size: sizeof(struct isl_basic_map *), compar: qsort_bmap_cmp); |
10452 | for (i = map->n - 1; i >= 1; --i) { |
10453 | if (!isl_basic_map_plain_is_equal(bmap1: map->p[i - 1], bmap2: map->p[i])) |
10454 | continue; |
10455 | isl_basic_map_free(bmap: map->p[i-1]); |
10456 | for (j = i; j < map->n; ++j) |
10457 | map->p[j - 1] = map->p[j]; |
10458 | map->n--; |
10459 | } |
10460 | |
10461 | return map; |
10462 | } |
10463 | |
10464 | /* Remove obvious duplicates among the basic maps of "map". |
10465 | * |
10466 | * Unlike isl_map_normalize, this function does not remove redundant |
10467 | * constraints and only removes duplicates that have exactly the same |
10468 | * constraints in the input. It does sort the constraints and |
10469 | * the basic maps to ease the detection of duplicates. |
10470 | * |
10471 | * If "map" has already been normalized or if the basic maps are |
10472 | * disjoint, then there can be no duplicates. |
10473 | */ |
10474 | __isl_give isl_map *isl_map_remove_obvious_duplicates(__isl_take isl_map *map) |
10475 | { |
10476 | int i; |
10477 | isl_basic_map *bmap; |
10478 | |
10479 | if (!map) |
10480 | return NULL; |
10481 | if (map->n <= 1) |
10482 | return map; |
10483 | if (ISL_F_ISSET(map, ISL_MAP_NORMALIZED | ISL_MAP_DISJOINT)) |
10484 | return map; |
10485 | for (i = 0; i < map->n; ++i) { |
10486 | bmap = isl_basic_map_copy(bmap: map->p[i]); |
10487 | bmap = isl_basic_map_sort_constraints(bmap); |
10488 | if (!bmap) |
10489 | return isl_map_free(map); |
10490 | isl_basic_map_free(bmap: map->p[i]); |
10491 | map->p[i] = bmap; |
10492 | } |
10493 | |
10494 | map = sort_and_remove_duplicates(map); |
10495 | return map; |
10496 | } |
10497 | |
10498 | /* We normalize in place, but if anything goes wrong we need |
10499 | * to return NULL, so we need to make sure we don't change the |
10500 | * meaning of any possible other copies of map. |
10501 | */ |
10502 | __isl_give isl_map *isl_map_normalize(__isl_take isl_map *map) |
10503 | { |
10504 | int i; |
10505 | struct isl_basic_map *bmap; |
10506 | |
10507 | if (!map) |
10508 | return NULL; |
10509 | if (ISL_F_ISSET(map, ISL_MAP_NORMALIZED)) |
10510 | return map; |
10511 | for (i = 0; i < map->n; ++i) { |
10512 | bmap = isl_basic_map_normalize(bmap: isl_basic_map_copy(bmap: map->p[i])); |
10513 | if (!bmap) |
10514 | goto error; |
10515 | isl_basic_map_free(bmap: map->p[i]); |
10516 | map->p[i] = bmap; |
10517 | } |
10518 | |
10519 | map = sort_and_remove_duplicates(map); |
10520 | if (map) |
10521 | ISL_F_SET(map, ISL_MAP_NORMALIZED); |
10522 | return map; |
10523 | error: |
10524 | isl_map_free(map); |
10525 | return NULL; |
10526 | } |
10527 | |
10528 | __isl_give isl_set *isl_set_normalize(__isl_take isl_set *set) |
10529 | { |
10530 | return set_from_map(isl_map_normalize(map: set_to_map(set))); |
10531 | } |
10532 | |
10533 | isl_bool isl_map_plain_is_equal(__isl_keep isl_map *map1, |
10534 | __isl_keep isl_map *map2) |
10535 | { |
10536 | int i; |
10537 | isl_bool equal; |
10538 | |
10539 | if (!map1 || !map2) |
10540 | return isl_bool_error; |
10541 | |
10542 | if (map1 == map2) |
10543 | return isl_bool_true; |
10544 | equal = isl_map_has_equal_space(obj1: map1, obj2: map2); |
10545 | if (equal < 0 || !equal) |
10546 | return equal; |
10547 | |
10548 | map1 = isl_map_copy(map: map1); |
10549 | map2 = isl_map_copy(map: map2); |
10550 | map1 = isl_map_normalize(map: map1); |
10551 | map2 = isl_map_normalize(map: map2); |
10552 | if (!map1 || !map2) |
10553 | goto error; |
10554 | equal = map1->n == map2->n; |
10555 | for (i = 0; equal && i < map1->n; ++i) { |
10556 | equal = isl_basic_map_plain_is_equal(bmap1: map1->p[i], bmap2: map2->p[i]); |
10557 | if (equal < 0) |
10558 | goto error; |
10559 | } |
10560 | isl_map_free(map: map1); |
10561 | isl_map_free(map: map2); |
10562 | return equal; |
10563 | error: |
10564 | isl_map_free(map: map1); |
10565 | isl_map_free(map: map2); |
10566 | return isl_bool_error; |
10567 | } |
10568 | |
10569 | isl_bool isl_set_plain_is_equal(__isl_keep isl_set *set1, |
10570 | __isl_keep isl_set *set2) |
10571 | { |
10572 | return isl_map_plain_is_equal(map1: set_to_map(set1), map2: set_to_map(set2)); |
10573 | } |
10574 | |
10575 | /* Return the basic maps in "map" as a list. |
10576 | */ |
10577 | __isl_give isl_basic_map_list *isl_map_get_basic_map_list( |
10578 | __isl_keep isl_map *map) |
10579 | { |
10580 | int i; |
10581 | isl_ctx *ctx; |
10582 | isl_basic_map_list *list; |
10583 | |
10584 | if (!map) |
10585 | return NULL; |
10586 | ctx = isl_map_get_ctx(map); |
10587 | list = isl_basic_map_list_alloc(ctx, n: map->n); |
10588 | |
10589 | for (i = 0; i < map->n; ++i) { |
10590 | isl_basic_map *bmap; |
10591 | |
10592 | bmap = isl_basic_map_copy(bmap: map->p[i]); |
10593 | list = isl_basic_map_list_add(list, el: bmap); |
10594 | } |
10595 | |
10596 | return list; |
10597 | } |
10598 | |
10599 | /* Return the intersection of the elements in the non-empty list "list". |
10600 | * All elements are assumed to live in the same space. |
10601 | */ |
10602 | __isl_give isl_basic_map *isl_basic_map_list_intersect( |
10603 | __isl_take isl_basic_map_list *list) |
10604 | { |
10605 | int i; |
10606 | isl_size n; |
10607 | isl_basic_map *bmap; |
10608 | |
10609 | n = isl_basic_map_list_n_basic_map(list); |
10610 | if (n < 0) |
10611 | goto error; |
10612 | if (n < 1) |
10613 | isl_die(isl_basic_map_list_get_ctx(list), isl_error_invalid, |
10614 | "expecting non-empty list" , goto error); |
10615 | |
10616 | bmap = isl_basic_map_list_get_basic_map(list, index: 0); |
10617 | for (i = 1; i < n; ++i) { |
10618 | isl_basic_map *bmap_i; |
10619 | |
10620 | bmap_i = isl_basic_map_list_get_basic_map(list, index: i); |
10621 | bmap = isl_basic_map_intersect(bmap1: bmap, bmap2: bmap_i); |
10622 | } |
10623 | |
10624 | isl_basic_map_list_free(list); |
10625 | return bmap; |
10626 | error: |
10627 | isl_basic_map_list_free(list); |
10628 | return NULL; |
10629 | } |
10630 | |
10631 | /* Return the intersection of the elements in the non-empty list "list". |
10632 | * All elements are assumed to live in the same space. |
10633 | */ |
10634 | __isl_give isl_basic_set *isl_basic_set_list_intersect( |
10635 | __isl_take isl_basic_set_list *list) |
10636 | { |
10637 | return isl_basic_map_list_intersect(list); |
10638 | } |
10639 | |
10640 | /* Return the union of the elements of "list". |
10641 | * The list is required to have at least one element. |
10642 | */ |
10643 | __isl_give isl_set *isl_basic_set_list_union( |
10644 | __isl_take isl_basic_set_list *list) |
10645 | { |
10646 | int i; |
10647 | isl_size n; |
10648 | isl_space *space; |
10649 | isl_basic_set *bset; |
10650 | isl_set *set; |
10651 | |
10652 | n = isl_basic_set_list_n_basic_set(list); |
10653 | if (n < 0) |
10654 | goto error; |
10655 | if (n < 1) |
10656 | isl_die(isl_basic_set_list_get_ctx(list), isl_error_invalid, |
10657 | "expecting non-empty list" , goto error); |
10658 | |
10659 | bset = isl_basic_set_list_get_basic_set(list, index: 0); |
10660 | space = isl_basic_set_get_space(bset); |
10661 | isl_basic_set_free(bset); |
10662 | |
10663 | set = isl_set_alloc_space(space, n, flags: 0); |
10664 | for (i = 0; i < n; ++i) { |
10665 | bset = isl_basic_set_list_get_basic_set(list, index: i); |
10666 | set = isl_set_add_basic_set(set, bset); |
10667 | } |
10668 | |
10669 | isl_basic_set_list_free(list); |
10670 | return set; |
10671 | error: |
10672 | isl_basic_set_list_free(list); |
10673 | return NULL; |
10674 | } |
10675 | |
10676 | /* Return the union of the elements in the non-empty list "list". |
10677 | * All elements are assumed to live in the same space. |
10678 | */ |
10679 | __isl_give isl_set *isl_set_list_union(__isl_take isl_set_list *list) |
10680 | { |
10681 | int i; |
10682 | isl_size n; |
10683 | isl_set *set; |
10684 | |
10685 | n = isl_set_list_n_set(list); |
10686 | if (n < 0) |
10687 | goto error; |
10688 | if (n < 1) |
10689 | isl_die(isl_set_list_get_ctx(list), isl_error_invalid, |
10690 | "expecting non-empty list" , goto error); |
10691 | |
10692 | set = isl_set_list_get_set(list, index: 0); |
10693 | for (i = 1; i < n; ++i) { |
10694 | isl_set *set_i; |
10695 | |
10696 | set_i = isl_set_list_get_set(list, index: i); |
10697 | set = isl_set_union(set1: set, set2: set_i); |
10698 | } |
10699 | |
10700 | isl_set_list_free(list); |
10701 | return set; |
10702 | error: |
10703 | isl_set_list_free(list); |
10704 | return NULL; |
10705 | } |
10706 | |
10707 | __isl_give isl_basic_map *isl_basic_map_product( |
10708 | __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) |
10709 | { |
10710 | isl_space *space_result = NULL; |
10711 | struct isl_basic_map *bmap; |
10712 | unsigned in1, in2, out1, out2, nparam, total, pos; |
10713 | struct isl_dim_map *dim_map1, *dim_map2; |
10714 | |
10715 | if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0) |
10716 | goto error; |
10717 | space_result = isl_space_product(left: isl_space_copy(space: bmap1->dim), |
10718 | right: isl_space_copy(space: bmap2->dim)); |
10719 | |
10720 | in1 = isl_basic_map_dim(bmap: bmap1, type: isl_dim_in); |
10721 | in2 = isl_basic_map_dim(bmap: bmap2, type: isl_dim_in); |
10722 | out1 = isl_basic_map_dim(bmap: bmap1, type: isl_dim_out); |
10723 | out2 = isl_basic_map_dim(bmap: bmap2, type: isl_dim_out); |
10724 | nparam = isl_basic_map_dim(bmap: bmap1, type: isl_dim_param); |
10725 | |
10726 | total = nparam + in1 + in2 + out1 + out2 + bmap1->n_div + bmap2->n_div; |
10727 | dim_map1 = isl_dim_map_alloc(ctx: bmap1->ctx, len: total); |
10728 | dim_map2 = isl_dim_map_alloc(ctx: bmap1->ctx, len: total); |
10729 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_param, dst_pos: pos = 0); |
10730 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_param, dst_pos: pos = 0); |
10731 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_in, dst_pos: pos += nparam); |
10732 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_in, dst_pos: pos += in1); |
10733 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_out, dst_pos: pos += in2); |
10734 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_out, dst_pos: pos += out1); |
10735 | isl_dim_map_div(dim_map: dim_map1, bmap: bmap1, dst_pos: pos += out2); |
10736 | isl_dim_map_div(dim_map: dim_map2, bmap: bmap2, dst_pos: pos += bmap1->n_div); |
10737 | |
10738 | bmap = isl_basic_map_alloc_space(space: space_result, |
10739 | extra: bmap1->n_div + bmap2->n_div, |
10740 | n_eq: bmap1->n_eq + bmap2->n_eq, |
10741 | n_ineq: bmap1->n_ineq + bmap2->n_ineq); |
10742 | bmap = isl_basic_map_add_constraints_dim_map(dst: bmap, src: bmap1, dim_map: dim_map1); |
10743 | bmap = isl_basic_map_add_constraints_dim_map(dst: bmap, src: bmap2, dim_map: dim_map2); |
10744 | bmap = isl_basic_map_simplify(bmap); |
10745 | return isl_basic_map_finalize(bmap); |
10746 | error: |
10747 | isl_basic_map_free(bmap: bmap1); |
10748 | isl_basic_map_free(bmap: bmap2); |
10749 | return NULL; |
10750 | } |
10751 | |
10752 | __isl_give isl_basic_map *isl_basic_map_flat_product( |
10753 | __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) |
10754 | { |
10755 | isl_basic_map *prod; |
10756 | |
10757 | prod = isl_basic_map_product(bmap1, bmap2); |
10758 | prod = isl_basic_map_flatten(bmap: prod); |
10759 | return prod; |
10760 | } |
10761 | |
10762 | __isl_give isl_basic_set *isl_basic_set_flat_product( |
10763 | __isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2) |
10764 | { |
10765 | return isl_basic_map_flat_range_product(bmap1: bset1, bmap2: bset2); |
10766 | } |
10767 | |
10768 | __isl_give isl_basic_map *isl_basic_map_domain_product( |
10769 | __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) |
10770 | { |
10771 | isl_space *space1, *space2; |
10772 | isl_space *space_result = NULL; |
10773 | isl_basic_map *bmap; |
10774 | isl_size in1, in2, out, nparam; |
10775 | unsigned total, pos; |
10776 | struct isl_dim_map *dim_map1, *dim_map2; |
10777 | |
10778 | in1 = isl_basic_map_dim(bmap: bmap1, type: isl_dim_in); |
10779 | in2 = isl_basic_map_dim(bmap: bmap2, type: isl_dim_in); |
10780 | out = isl_basic_map_dim(bmap: bmap1, type: isl_dim_out); |
10781 | nparam = isl_basic_map_dim(bmap: bmap1, type: isl_dim_param); |
10782 | if (in1 < 0 || in2 < 0 || out < 0 || nparam < 0) |
10783 | goto error; |
10784 | |
10785 | space1 = isl_basic_map_get_space(bmap: bmap1); |
10786 | space2 = isl_basic_map_get_space(bmap: bmap2); |
10787 | space_result = isl_space_domain_product(left: space1, right: space2); |
10788 | |
10789 | total = nparam + in1 + in2 + out + bmap1->n_div + bmap2->n_div; |
10790 | dim_map1 = isl_dim_map_alloc(ctx: bmap1->ctx, len: total); |
10791 | dim_map2 = isl_dim_map_alloc(ctx: bmap1->ctx, len: total); |
10792 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_param, dst_pos: pos = 0); |
10793 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_param, dst_pos: pos = 0); |
10794 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_in, dst_pos: pos += nparam); |
10795 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_in, dst_pos: pos += in1); |
10796 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_out, dst_pos: pos += in2); |
10797 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_out, dst_pos: pos); |
10798 | isl_dim_map_div(dim_map: dim_map1, bmap: bmap1, dst_pos: pos += out); |
10799 | isl_dim_map_div(dim_map: dim_map2, bmap: bmap2, dst_pos: pos += bmap1->n_div); |
10800 | |
10801 | bmap = isl_basic_map_alloc_space(space: space_result, |
10802 | extra: bmap1->n_div + bmap2->n_div, |
10803 | n_eq: bmap1->n_eq + bmap2->n_eq, |
10804 | n_ineq: bmap1->n_ineq + bmap2->n_ineq); |
10805 | bmap = isl_basic_map_add_constraints_dim_map(dst: bmap, src: bmap1, dim_map: dim_map1); |
10806 | bmap = isl_basic_map_add_constraints_dim_map(dst: bmap, src: bmap2, dim_map: dim_map2); |
10807 | bmap = isl_basic_map_simplify(bmap); |
10808 | return isl_basic_map_finalize(bmap); |
10809 | error: |
10810 | isl_basic_map_free(bmap: bmap1); |
10811 | isl_basic_map_free(bmap: bmap2); |
10812 | return NULL; |
10813 | } |
10814 | |
10815 | __isl_give isl_basic_map *isl_basic_map_range_product( |
10816 | __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) |
10817 | { |
10818 | isl_bool rational; |
10819 | isl_space *space_result = NULL; |
10820 | isl_basic_map *bmap; |
10821 | isl_size in, out1, out2, nparam; |
10822 | unsigned total, pos; |
10823 | struct isl_dim_map *dim_map1, *dim_map2; |
10824 | |
10825 | rational = isl_basic_map_is_rational(bmap: bmap1); |
10826 | if (rational >= 0 && rational) |
10827 | rational = isl_basic_map_is_rational(bmap: bmap2); |
10828 | in = isl_basic_map_dim(bmap: bmap1, type: isl_dim_in); |
10829 | out1 = isl_basic_map_dim(bmap: bmap1, type: isl_dim_out); |
10830 | out2 = isl_basic_map_dim(bmap: bmap2, type: isl_dim_out); |
10831 | nparam = isl_basic_map_dim(bmap: bmap1, type: isl_dim_param); |
10832 | if (in < 0 || out1 < 0 || out2 < 0 || nparam < 0 || rational < 0) |
10833 | goto error; |
10834 | |
10835 | if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0) |
10836 | goto error; |
10837 | |
10838 | space_result = isl_space_range_product(left: isl_space_copy(space: bmap1->dim), |
10839 | right: isl_space_copy(space: bmap2->dim)); |
10840 | |
10841 | total = nparam + in + out1 + out2 + bmap1->n_div + bmap2->n_div; |
10842 | dim_map1 = isl_dim_map_alloc(ctx: bmap1->ctx, len: total); |
10843 | dim_map2 = isl_dim_map_alloc(ctx: bmap1->ctx, len: total); |
10844 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_param, dst_pos: pos = 0); |
10845 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_param, dst_pos: pos = 0); |
10846 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_in, dst_pos: pos += nparam); |
10847 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_in, dst_pos: pos); |
10848 | isl_dim_map_dim(dim_map: dim_map1, space: bmap1->dim, type: isl_dim_out, dst_pos: pos += in); |
10849 | isl_dim_map_dim(dim_map: dim_map2, space: bmap2->dim, type: isl_dim_out, dst_pos: pos += out1); |
10850 | isl_dim_map_div(dim_map: dim_map1, bmap: bmap1, dst_pos: pos += out2); |
10851 | isl_dim_map_div(dim_map: dim_map2, bmap: bmap2, dst_pos: pos += bmap1->n_div); |
10852 | |
10853 | bmap = isl_basic_map_alloc_space(space: space_result, |
10854 | extra: bmap1->n_div + bmap2->n_div, |
10855 | n_eq: bmap1->n_eq + bmap2->n_eq, |
10856 | n_ineq: bmap1->n_ineq + bmap2->n_ineq); |
10857 | bmap = isl_basic_map_add_constraints_dim_map(dst: bmap, src: bmap1, dim_map: dim_map1); |
10858 | bmap = isl_basic_map_add_constraints_dim_map(dst: bmap, src: bmap2, dim_map: dim_map2); |
10859 | if (rational) |
10860 | bmap = isl_basic_map_set_rational(bmap); |
10861 | bmap = isl_basic_map_simplify(bmap); |
10862 | return isl_basic_map_finalize(bmap); |
10863 | error: |
10864 | isl_basic_map_free(bmap: bmap1); |
10865 | isl_basic_map_free(bmap: bmap2); |
10866 | return NULL; |
10867 | } |
10868 | |
10869 | __isl_give isl_basic_map *isl_basic_map_flat_range_product( |
10870 | __isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2) |
10871 | { |
10872 | isl_basic_map *prod; |
10873 | |
10874 | prod = isl_basic_map_range_product(bmap1, bmap2); |
10875 | prod = isl_basic_map_flatten_range(bmap: prod); |
10876 | return prod; |
10877 | } |
10878 | |
10879 | /* Apply "basic_map_product" to each pair of basic maps in "map1" and "map2" |
10880 | * and collect the results. |
10881 | * The result live in the space obtained by calling "space_product" |
10882 | * on the spaces of "map1" and "map2". |
10883 | * If "remove_duplicates" is set then the result may contain duplicates |
10884 | * (even if the inputs do not) and so we try and remove the obvious |
10885 | * duplicates. |
10886 | */ |
10887 | static __isl_give isl_map *map_product(__isl_take isl_map *map1, |
10888 | __isl_take isl_map *map2, |
10889 | __isl_give isl_space *(*space_product)(__isl_take isl_space *left, |
10890 | __isl_take isl_space *right), |
10891 | __isl_give isl_basic_map *(*basic_map_product)( |
10892 | __isl_take isl_basic_map *left, |
10893 | __isl_take isl_basic_map *right), |
10894 | int remove_duplicates) |
10895 | { |
10896 | unsigned flags = 0; |
10897 | struct isl_map *result; |
10898 | int i, j; |
10899 | isl_bool m; |
10900 | |
10901 | m = isl_map_has_equal_params(map1, map2); |
10902 | if (m < 0) |
10903 | goto error; |
10904 | if (!m) |
10905 | isl_die(isl_map_get_ctx(map1), isl_error_invalid, |
10906 | "parameters don't match" , goto error); |
10907 | |
10908 | if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) && |
10909 | ISL_F_ISSET(map2, ISL_MAP_DISJOINT)) |
10910 | ISL_FL_SET(flags, ISL_MAP_DISJOINT); |
10911 | |
10912 | result = isl_map_alloc_space(space: space_product(isl_space_copy(space: map1->dim), |
10913 | isl_space_copy(space: map2->dim)), |
10914 | n: map1->n * map2->n, flags); |
10915 | if (!result) |
10916 | goto error; |
10917 | for (i = 0; i < map1->n; ++i) |
10918 | for (j = 0; j < map2->n; ++j) { |
10919 | struct isl_basic_map *part; |
10920 | part = basic_map_product(isl_basic_map_copy(bmap: map1->p[i]), |
10921 | isl_basic_map_copy(bmap: map2->p[j])); |
10922 | if (isl_basic_map_is_empty(bmap: part)) |
10923 | isl_basic_map_free(bmap: part); |
10924 | else |
10925 | result = isl_map_add_basic_map(map: result, bmap: part); |
10926 | if (!result) |
10927 | goto error; |
10928 | } |
10929 | if (remove_duplicates) |
10930 | result = isl_map_remove_obvious_duplicates(map: result); |
10931 | isl_map_free(map: map1); |
10932 | isl_map_free(map: map2); |
10933 | return result; |
10934 | error: |
10935 | isl_map_free(map: map1); |
10936 | isl_map_free(map: map2); |
10937 | return NULL; |
10938 | } |
10939 | |
10940 | /* Given two maps A -> B and C -> D, construct a map [A -> C] -> [B -> D] |
10941 | */ |
10942 | __isl_give isl_map *isl_map_product(__isl_take isl_map *map1, |
10943 | __isl_take isl_map *map2) |
10944 | { |
10945 | isl_map_align_params_bin(obj1: &map1, obj2: &map2); |
10946 | return map_product(map1, map2, space_product: &isl_space_product, |
10947 | basic_map_product: &isl_basic_map_product, remove_duplicates: 0); |
10948 | } |
10949 | |
10950 | /* Given two maps A -> B and C -> D, construct a map (A, C) -> (B, D) |
10951 | */ |
10952 | __isl_give isl_map *isl_map_flat_product(__isl_take isl_map *map1, |
10953 | __isl_take isl_map *map2) |
10954 | { |
10955 | isl_map *prod; |
10956 | |
10957 | prod = isl_map_product(map1, map2); |
10958 | prod = isl_map_flatten(map: prod); |
10959 | return prod; |
10960 | } |
10961 | |
10962 | /* Given two set A and B, construct its Cartesian product A x B. |
10963 | */ |
10964 | __isl_give isl_set *isl_set_product(__isl_take isl_set *set1, |
10965 | __isl_take isl_set *set2) |
10966 | { |
10967 | return isl_map_range_product(map1: set1, map2: set2); |
10968 | } |
10969 | |
10970 | __isl_give isl_set *isl_set_flat_product(__isl_take isl_set *set1, |
10971 | __isl_take isl_set *set2) |
10972 | { |
10973 | return isl_map_flat_range_product(map1: set1, map2: set2); |
10974 | } |
10975 | |
10976 | /* Given two maps A -> B and C -> D, construct a map [A -> C] -> (B * D) |
10977 | */ |
10978 | __isl_give isl_map *isl_map_domain_product(__isl_take isl_map *map1, |
10979 | __isl_take isl_map *map2) |
10980 | { |
10981 | isl_map_align_params_bin(obj1: &map1, obj2: &map2); |
10982 | return map_product(map1, map2, space_product: &isl_space_domain_product, |
10983 | basic_map_product: &isl_basic_map_domain_product, remove_duplicates: 1); |
10984 | } |
10985 | |
10986 | /* Given two maps A -> B and C -> D, construct a map (A * C) -> [B -> D] |
10987 | */ |
10988 | __isl_give isl_map *isl_map_range_product(__isl_take isl_map *map1, |
10989 | __isl_take isl_map *map2) |
10990 | { |
10991 | isl_map_align_params_bin(obj1: &map1, obj2: &map2); |
10992 | return map_product(map1, map2, space_product: &isl_space_range_product, |
10993 | basic_map_product: &isl_basic_map_range_product, remove_duplicates: 1); |
10994 | } |
10995 | |
10996 | /* Given a map of the form [A -> B] -> [C -> D], return the map A -> C. |
10997 | */ |
10998 | __isl_give isl_map *isl_map_factor_domain(__isl_take isl_map *map) |
10999 | { |
11000 | isl_space *space; |
11001 | isl_size total1, keep1, total2, keep2; |
11002 | |
11003 | total1 = isl_map_dim(map, type: isl_dim_in); |
11004 | total2 = isl_map_dim(map, type: isl_dim_out); |
11005 | if (total1 < 0 || total2 < 0) |
11006 | return isl_map_free(map); |
11007 | if (!isl_space_domain_is_wrapping(space: map->dim) || |
11008 | !isl_space_range_is_wrapping(space: map->dim)) |
11009 | isl_die(isl_map_get_ctx(map), isl_error_invalid, |
11010 | "not a product" , return isl_map_free(map)); |
11011 | |
11012 | space = isl_map_get_space(map); |
11013 | space = isl_space_factor_domain(space); |
11014 | keep1 = isl_space_dim(space, type: isl_dim_in); |
11015 | keep2 = isl_space_dim(space, type: isl_dim_out); |
11016 | if (keep1 < 0 || keep2 < 0) |
11017 | map = isl_map_free(map); |
11018 | map = isl_map_project_out(map, type: isl_dim_in, first: keep1, n: total1 - keep1); |
11019 | map = isl_map_project_out(map, type: isl_dim_out, first: keep2, n: total2 - keep2); |
11020 | map = isl_map_reset_space(map, space); |
11021 | |
11022 | return map; |
11023 | } |
11024 | |
11025 | /* Given a map of the form [A -> B] -> [C -> D], return the map B -> D. |
11026 | */ |
11027 | __isl_give isl_map *isl_map_factor_range(__isl_take isl_map *map) |
11028 | { |
11029 | isl_space *space; |
11030 | isl_size total1, keep1, total2, keep2; |
11031 | |
11032 | total1 = isl_map_dim(map, type: isl_dim_in); |
11033 | total2 = isl_map_dim(map, type: isl_dim_out); |
11034 | if (total1 < 0 || total2 < 0) |
11035 | return isl_map_free(map); |
11036 | if (!isl_space_domain_is_wrapping(space: map->dim) || |
11037 | !isl_space_range_is_wrapping(space: map->dim)) |
11038 | isl_die(isl_map_get_ctx(map), isl_error_invalid, |
11039 | "not a product" , return isl_map_free(map)); |
11040 | |
11041 | space = isl_map_get_space(map); |
11042 | space = isl_space_factor_range(space); |
11043 | keep1 = isl_space_dim(space, type: isl_dim_in); |
11044 | keep2 = isl_space_dim(space, type: isl_dim_out); |
11045 | if (keep1 < 0 || keep2 < 0) |
11046 | map = isl_map_free(map); |
11047 | map = isl_map_project_out(map, type: isl_dim_in, first: 0, n: total1 - keep1); |
11048 | map = isl_map_project_out(map, type: isl_dim_out, first: 0, n: total2 - keep2); |
11049 | map = isl_map_reset_space(map, space); |
11050 | |
11051 | return map; |
11052 | } |
11053 | |
11054 | /* Given a map of the form [A -> B] -> C, return the map A -> C. |
11055 | */ |
11056 | __isl_give isl_map *isl_map_domain_factor_domain(__isl_take isl_map *map) |
11057 | { |
11058 | isl_space *space; |
11059 | isl_size total, keep; |
11060 | |
11061 | total = isl_map_dim(map, type: isl_dim_in); |
11062 | if (total < 0) |
11063 | return isl_map_free(map); |
11064 | if (!isl_space_domain_is_wrapping(space: map->dim)) |
11065 | isl_die(isl_map_get_ctx(map), isl_error_invalid, |
11066 | "domain is not a product" , return isl_map_free(map)); |
11067 | |
11068 | space = isl_map_get_space(map); |
11069 | space = isl_space_domain_factor_domain(space); |
11070 | keep = isl_space_dim(space, type: isl_dim_in); |
11071 | if (keep < 0) |
11072 | map = isl_map_free(map); |
11073 | map = isl_map_project_out(map, type: isl_dim_in, first: keep, n: total - keep); |
11074 | map = isl_map_reset_space(map, space); |
11075 | |
11076 | return map; |
11077 | } |
11078 | |
11079 | /* Given a map of the form [A -> B] -> C, return the map B -> C. |
11080 | */ |
11081 | __isl_give isl_map *isl_map_domain_factor_range(__isl_take isl_map *map) |
11082 | { |
11083 | isl_space *space; |
11084 | isl_size total, keep; |
11085 | |
11086 | total = isl_map_dim(map, type: isl_dim_in); |
11087 | if (total < 0) |
11088 | return isl_map_free(map); |
11089 | if (!isl_space_domain_is_wrapping(space: map->dim)) |
11090 | isl_die(isl_map_get_ctx(map), isl_error_invalid, |
11091 | "domain is not a product" , return isl_map_free(map)); |
11092 | |
11093 | space = isl_map_get_space(map); |
11094 | space = isl_space_domain_factor_range(space); |
11095 | keep = isl_space_dim(space, type: isl_dim_in); |
11096 | if (keep < 0) |
11097 | map = isl_map_free(map); |
11098 | map = isl_map_project_out(map, type: isl_dim_in, first: 0, n: total - keep); |
11099 | map = isl_map_reset_space(map, space); |
11100 | |
11101 | return map; |
11102 | } |
11103 | |
11104 | /* Given a map A -> [B -> C], extract the map A -> B. |
11105 | */ |
11106 | __isl_give isl_map *isl_map_range_factor_domain(__isl_take isl_map *map) |
11107 | { |
11108 | isl_space *space; |
11109 | isl_size total, keep; |
11110 | |
11111 | total = isl_map_dim(map, type: isl_dim_out); |
11112 | if (total < 0) |
11113 | return isl_map_free(map); |
11114 | if (!isl_space_range_is_wrapping(space: map->dim)) |
11115 | isl_die(isl_map_get_ctx(map), isl_error_invalid, |
11116 | "range is not a product" , return isl_map_free(map)); |
11117 | |
11118 | space = isl_map_get_space(map); |
11119 | space = isl_space_range_factor_domain(space); |
11120 | keep = isl_space_dim(space, type: isl_dim_out); |
11121 | if (keep < 0) |
11122 | map = isl_map_free(map); |
11123 | map = isl_map_project_out(map, type: isl_dim_out, first: keep, n: total - keep); |
11124 | map = isl_map_reset_space(map, space); |
11125 | |
11126 | return map; |
11127 | } |
11128 | |
11129 | /* Given a map A -> [B -> C], extract the map A -> C. |
11130 | */ |
11131 | __isl_give isl_map *isl_map_range_factor_range(__isl_take isl_map *map) |
11132 | { |
11133 | isl_space *space; |
11134 | isl_size total, keep; |
11135 | |
11136 | total = isl_map_dim(map, type: isl_dim_out); |
11137 | if (total < 0) |
11138 | return isl_map_free(map); |
11139 | if (!isl_space_range_is_wrapping(space: map->dim)) |
11140 | isl_die(isl_map_get_ctx(map), isl_error_invalid, |
11141 | "range is not a product" , return isl_map_free(map)); |
11142 | |
11143 | space = isl_map_get_space(map); |
11144 | space = isl_space_range_factor_range(space); |
11145 | keep = isl_space_dim(space, type: isl_dim_out); |
11146 | if (keep < 0) |
11147 | map = isl_map_free(map); |
11148 | map = isl_map_project_out(map, type: isl_dim_out, first: 0, n: total - keep); |
11149 | map = isl_map_reset_space(map, space); |
11150 | |
11151 | return map; |
11152 | } |
11153 | |
11154 | /* Given two maps A -> B and C -> D, construct a map (A, C) -> (B * D) |
11155 | */ |
11156 | __isl_give isl_map *isl_map_flat_domain_product(__isl_take isl_map *map1, |
11157 | __isl_take isl_map *map2) |
11158 | { |
11159 | isl_map *prod; |
11160 | |
11161 | prod = isl_map_domain_product(map1, map2); |
11162 | prod = isl_map_flatten_domain(map: prod); |
11163 | return prod; |
11164 | } |
11165 | |
11166 | /* Given two maps A -> B and C -> D, construct a map (A * C) -> (B, D) |
11167 | */ |
11168 | __isl_give isl_map *isl_map_flat_range_product(__isl_take isl_map *map1, |
11169 | __isl_take isl_map *map2) |
11170 | { |
11171 | isl_map *prod; |
11172 | |
11173 | prod = isl_map_range_product(map1, map2); |
11174 | prod = isl_map_flatten_range(map: prod); |
11175 | return prod; |
11176 | } |
11177 | |
11178 | uint32_t isl_basic_map_get_hash(__isl_keep isl_basic_map *bmap) |
11179 | { |
11180 | int i; |
11181 | uint32_t hash = isl_hash_init(); |
11182 | isl_size total; |
11183 | |
11184 | if (!bmap) |
11185 | return 0; |
11186 | bmap = isl_basic_map_copy(bmap); |
11187 | bmap = isl_basic_map_normalize(bmap); |
11188 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
11189 | if (total < 0) |
11190 | return 0; |
11191 | isl_hash_byte(hash, bmap->n_eq & 0xFF); |
11192 | for (i = 0; i < bmap->n_eq; ++i) { |
11193 | uint32_t c_hash; |
11194 | c_hash = isl_seq_get_hash(p: bmap->eq[i], len: 1 + total); |
11195 | isl_hash_hash(hash, c_hash); |
11196 | } |
11197 | isl_hash_byte(hash, bmap->n_ineq & 0xFF); |
11198 | for (i = 0; i < bmap->n_ineq; ++i) { |
11199 | uint32_t c_hash; |
11200 | c_hash = isl_seq_get_hash(p: bmap->ineq[i], len: 1 + total); |
11201 | isl_hash_hash(hash, c_hash); |
11202 | } |
11203 | isl_hash_byte(hash, bmap->n_div & 0xFF); |
11204 | for (i = 0; i < bmap->n_div; ++i) { |
11205 | uint32_t c_hash; |
11206 | if (isl_int_is_zero(bmap->div[i][0])) |
11207 | continue; |
11208 | isl_hash_byte(hash, i & 0xFF); |
11209 | c_hash = isl_seq_get_hash(p: bmap->div[i], len: 1 + 1 + total); |
11210 | isl_hash_hash(hash, c_hash); |
11211 | } |
11212 | isl_basic_map_free(bmap); |
11213 | return hash; |
11214 | } |
11215 | |
11216 | uint32_t isl_basic_set_get_hash(__isl_keep isl_basic_set *bset) |
11217 | { |
11218 | return isl_basic_map_get_hash(bmap: bset_to_bmap(bset)); |
11219 | } |
11220 | |
11221 | uint32_t isl_map_get_hash(__isl_keep isl_map *map) |
11222 | { |
11223 | int i; |
11224 | uint32_t hash; |
11225 | |
11226 | if (!map) |
11227 | return 0; |
11228 | map = isl_map_copy(map); |
11229 | map = isl_map_normalize(map); |
11230 | if (!map) |
11231 | return 0; |
11232 | |
11233 | hash = isl_hash_init(); |
11234 | for (i = 0; i < map->n; ++i) { |
11235 | uint32_t bmap_hash; |
11236 | bmap_hash = isl_basic_map_get_hash(bmap: map->p[i]); |
11237 | isl_hash_hash(hash, bmap_hash); |
11238 | } |
11239 | |
11240 | isl_map_free(map); |
11241 | |
11242 | return hash; |
11243 | } |
11244 | |
11245 | uint32_t isl_set_get_hash(__isl_keep isl_set *set) |
11246 | { |
11247 | return isl_map_get_hash(map: set_to_map(set)); |
11248 | } |
11249 | |
11250 | /* Return the number of basic maps in the (current) representation of "map". |
11251 | */ |
11252 | isl_size isl_map_n_basic_map(__isl_keep isl_map *map) |
11253 | { |
11254 | return map ? map->n : isl_size_error; |
11255 | } |
11256 | |
11257 | isl_size isl_set_n_basic_set(__isl_keep isl_set *set) |
11258 | { |
11259 | return set ? set->n : isl_size_error; |
11260 | } |
11261 | |
11262 | isl_stat isl_map_foreach_basic_map(__isl_keep isl_map *map, |
11263 | isl_stat (*fn)(__isl_take isl_basic_map *bmap, void *user), void *user) |
11264 | { |
11265 | int i; |
11266 | |
11267 | if (!map) |
11268 | return isl_stat_error; |
11269 | |
11270 | for (i = 0; i < map->n; ++i) |
11271 | if (fn(isl_basic_map_copy(bmap: map->p[i]), user) < 0) |
11272 | return isl_stat_error; |
11273 | |
11274 | return isl_stat_ok; |
11275 | } |
11276 | |
11277 | isl_stat isl_set_foreach_basic_set(__isl_keep isl_set *set, |
11278 | isl_stat (*fn)(__isl_take isl_basic_set *bset, void *user), void *user) |
11279 | { |
11280 | int i; |
11281 | |
11282 | if (!set) |
11283 | return isl_stat_error; |
11284 | |
11285 | for (i = 0; i < set->n; ++i) |
11286 | if (fn(isl_basic_set_copy(bset: set->p[i]), user) < 0) |
11287 | return isl_stat_error; |
11288 | |
11289 | return isl_stat_ok; |
11290 | } |
11291 | |
11292 | /* Does "test" succeed on every basic set in "set"? |
11293 | */ |
11294 | isl_bool isl_set_every_basic_set(__isl_keep isl_set *set, |
11295 | isl_bool (*test)(__isl_keep isl_basic_set *bset, void *user), |
11296 | void *user) |
11297 | { |
11298 | int i; |
11299 | |
11300 | if (!set) |
11301 | return isl_bool_error; |
11302 | |
11303 | for (i = 0; i < set->n; ++i) { |
11304 | isl_bool r; |
11305 | |
11306 | r = test(set->p[i], user); |
11307 | if (r < 0 || !r) |
11308 | return r; |
11309 | } |
11310 | |
11311 | return isl_bool_true; |
11312 | } |
11313 | |
11314 | /* Return a list of basic sets, the union of which is equal to "set". |
11315 | */ |
11316 | __isl_give isl_basic_set_list *isl_set_get_basic_set_list( |
11317 | __isl_keep isl_set *set) |
11318 | { |
11319 | int i; |
11320 | isl_basic_set_list *list; |
11321 | |
11322 | if (!set) |
11323 | return NULL; |
11324 | |
11325 | list = isl_basic_set_list_alloc(ctx: isl_set_get_ctx(set), n: set->n); |
11326 | for (i = 0; i < set->n; ++i) { |
11327 | isl_basic_set *bset; |
11328 | |
11329 | bset = isl_basic_set_copy(bset: set->p[i]); |
11330 | list = isl_basic_set_list_add(list, el: bset); |
11331 | } |
11332 | |
11333 | return list; |
11334 | } |
11335 | |
11336 | __isl_give isl_basic_set *isl_basic_set_lift(__isl_take isl_basic_set *bset) |
11337 | { |
11338 | isl_space *space; |
11339 | |
11340 | if (!bset) |
11341 | return NULL; |
11342 | |
11343 | bset = isl_basic_set_cow(bset); |
11344 | if (!bset) |
11345 | return NULL; |
11346 | |
11347 | space = isl_basic_set_get_space(bset); |
11348 | space = isl_space_lift(space, n_local: bset->n_div); |
11349 | if (!space) |
11350 | goto error; |
11351 | isl_space_free(space: bset->dim); |
11352 | bset->dim = space; |
11353 | bset->extra -= bset->n_div; |
11354 | bset->n_div = 0; |
11355 | |
11356 | bset = isl_basic_set_finalize(bset); |
11357 | |
11358 | return bset; |
11359 | error: |
11360 | isl_basic_set_free(bset); |
11361 | return NULL; |
11362 | } |
11363 | |
11364 | __isl_give isl_set *isl_set_lift(__isl_take isl_set *set) |
11365 | { |
11366 | int i; |
11367 | isl_space *space; |
11368 | unsigned n_div; |
11369 | |
11370 | set = set_from_map(isl_map_align_divs_internal(map: set_to_map(set))); |
11371 | |
11372 | if (!set) |
11373 | return NULL; |
11374 | |
11375 | set = isl_set_cow(set); |
11376 | if (!set) |
11377 | return NULL; |
11378 | |
11379 | n_div = set->p[0]->n_div; |
11380 | space = isl_set_get_space(set); |
11381 | space = isl_space_lift(space, n_local: n_div); |
11382 | if (!space) |
11383 | goto error; |
11384 | isl_space_free(space: set->dim); |
11385 | set->dim = space; |
11386 | |
11387 | for (i = 0; i < set->n; ++i) { |
11388 | set->p[i] = isl_basic_set_lift(bset: set->p[i]); |
11389 | if (!set->p[i]) |
11390 | goto error; |
11391 | } |
11392 | |
11393 | return set; |
11394 | error: |
11395 | isl_set_free(set); |
11396 | return NULL; |
11397 | } |
11398 | |
11399 | int isl_basic_set_size(__isl_keep isl_basic_set *bset) |
11400 | { |
11401 | isl_size dim; |
11402 | int size = 0; |
11403 | |
11404 | dim = isl_basic_set_dim(bset, type: isl_dim_all); |
11405 | if (dim < 0) |
11406 | return -1; |
11407 | size += bset->n_eq * (1 + dim); |
11408 | size += bset->n_ineq * (1 + dim); |
11409 | size += bset->n_div * (2 + dim); |
11410 | |
11411 | return size; |
11412 | } |
11413 | |
11414 | int isl_set_size(__isl_keep isl_set *set) |
11415 | { |
11416 | int i; |
11417 | int size = 0; |
11418 | |
11419 | if (!set) |
11420 | return -1; |
11421 | |
11422 | for (i = 0; i < set->n; ++i) |
11423 | size += isl_basic_set_size(bset: set->p[i]); |
11424 | |
11425 | return size; |
11426 | } |
11427 | |
11428 | /* Check if there is any lower bound (if lower == 0) and/or upper |
11429 | * bound (if upper == 0) on the specified dim. |
11430 | */ |
11431 | static isl_bool basic_map_dim_is_bounded(__isl_keep isl_basic_map *bmap, |
11432 | enum isl_dim_type type, unsigned pos, int lower, int upper) |
11433 | { |
11434 | int i; |
11435 | |
11436 | if (isl_basic_map_check_range(obj: bmap, type, first: pos, n: 1) < 0) |
11437 | return isl_bool_error; |
11438 | |
11439 | pos += isl_basic_map_offset(bmap, type); |
11440 | |
11441 | for (i = 0; i < bmap->n_div; ++i) { |
11442 | if (isl_int_is_zero(bmap->div[i][0])) |
11443 | continue; |
11444 | if (!isl_int_is_zero(bmap->div[i][1 + pos])) |
11445 | return isl_bool_true; |
11446 | } |
11447 | |
11448 | for (i = 0; i < bmap->n_eq; ++i) |
11449 | if (!isl_int_is_zero(bmap->eq[i][pos])) |
11450 | return isl_bool_true; |
11451 | |
11452 | for (i = 0; i < bmap->n_ineq; ++i) { |
11453 | int sgn = isl_int_sgn(bmap->ineq[i][pos]); |
11454 | if (sgn > 0) |
11455 | lower = 1; |
11456 | if (sgn < 0) |
11457 | upper = 1; |
11458 | } |
11459 | |
11460 | return lower && upper; |
11461 | } |
11462 | |
11463 | isl_bool isl_basic_map_dim_is_bounded(__isl_keep isl_basic_map *bmap, |
11464 | enum isl_dim_type type, unsigned pos) |
11465 | { |
11466 | return basic_map_dim_is_bounded(bmap, type, pos, lower: 0, upper: 0); |
11467 | } |
11468 | |
11469 | isl_bool isl_basic_map_dim_has_lower_bound(__isl_keep isl_basic_map *bmap, |
11470 | enum isl_dim_type type, unsigned pos) |
11471 | { |
11472 | return basic_map_dim_is_bounded(bmap, type, pos, lower: 0, upper: 1); |
11473 | } |
11474 | |
11475 | isl_bool isl_basic_map_dim_has_upper_bound(__isl_keep isl_basic_map *bmap, |
11476 | enum isl_dim_type type, unsigned pos) |
11477 | { |
11478 | return basic_map_dim_is_bounded(bmap, type, pos, lower: 1, upper: 0); |
11479 | } |
11480 | |
11481 | isl_bool isl_map_dim_is_bounded(__isl_keep isl_map *map, |
11482 | enum isl_dim_type type, unsigned pos) |
11483 | { |
11484 | int i; |
11485 | |
11486 | if (!map) |
11487 | return isl_bool_error; |
11488 | |
11489 | for (i = 0; i < map->n; ++i) { |
11490 | isl_bool bounded; |
11491 | bounded = isl_basic_map_dim_is_bounded(bmap: map->p[i], type, pos); |
11492 | if (bounded < 0 || !bounded) |
11493 | return bounded; |
11494 | } |
11495 | |
11496 | return isl_bool_true; |
11497 | } |
11498 | |
11499 | /* Return true if the specified dim is involved in both an upper bound |
11500 | * and a lower bound. |
11501 | */ |
11502 | isl_bool isl_set_dim_is_bounded(__isl_keep isl_set *set, |
11503 | enum isl_dim_type type, unsigned pos) |
11504 | { |
11505 | return isl_map_dim_is_bounded(map: set_to_map(set), type, pos); |
11506 | } |
11507 | |
11508 | /* Does "map" have a bound (according to "fn") for any of its basic maps? |
11509 | */ |
11510 | static isl_bool has_any_bound(__isl_keep isl_map *map, |
11511 | enum isl_dim_type type, unsigned pos, |
11512 | isl_bool (*fn)(__isl_keep isl_basic_map *bmap, |
11513 | enum isl_dim_type type, unsigned pos)) |
11514 | { |
11515 | int i; |
11516 | |
11517 | if (!map) |
11518 | return isl_bool_error; |
11519 | |
11520 | for (i = 0; i < map->n; ++i) { |
11521 | isl_bool bounded; |
11522 | bounded = fn(map->p[i], type, pos); |
11523 | if (bounded < 0 || bounded) |
11524 | return bounded; |
11525 | } |
11526 | |
11527 | return isl_bool_false; |
11528 | } |
11529 | |
11530 | /* Return 1 if the specified dim is involved in any lower bound. |
11531 | */ |
11532 | isl_bool isl_set_dim_has_any_lower_bound(__isl_keep isl_set *set, |
11533 | enum isl_dim_type type, unsigned pos) |
11534 | { |
11535 | return has_any_bound(map: set, type, pos, |
11536 | fn: &isl_basic_map_dim_has_lower_bound); |
11537 | } |
11538 | |
11539 | /* Return 1 if the specified dim is involved in any upper bound. |
11540 | */ |
11541 | isl_bool isl_set_dim_has_any_upper_bound(__isl_keep isl_set *set, |
11542 | enum isl_dim_type type, unsigned pos) |
11543 | { |
11544 | return has_any_bound(map: set, type, pos, |
11545 | fn: &isl_basic_map_dim_has_upper_bound); |
11546 | } |
11547 | |
11548 | /* Does "map" have a bound (according to "fn") for all of its basic maps? |
11549 | */ |
11550 | static isl_bool has_bound(__isl_keep isl_map *map, |
11551 | enum isl_dim_type type, unsigned pos, |
11552 | isl_bool (*fn)(__isl_keep isl_basic_map *bmap, |
11553 | enum isl_dim_type type, unsigned pos)) |
11554 | { |
11555 | int i; |
11556 | |
11557 | if (!map) |
11558 | return isl_bool_error; |
11559 | |
11560 | for (i = 0; i < map->n; ++i) { |
11561 | isl_bool bounded; |
11562 | bounded = fn(map->p[i], type, pos); |
11563 | if (bounded < 0 || !bounded) |
11564 | return bounded; |
11565 | } |
11566 | |
11567 | return isl_bool_true; |
11568 | } |
11569 | |
11570 | /* Return 1 if the specified dim has a lower bound (in each of its basic sets). |
11571 | */ |
11572 | isl_bool isl_set_dim_has_lower_bound(__isl_keep isl_set *set, |
11573 | enum isl_dim_type type, unsigned pos) |
11574 | { |
11575 | return has_bound(map: set, type, pos, fn: &isl_basic_map_dim_has_lower_bound); |
11576 | } |
11577 | |
11578 | /* Return 1 if the specified dim has an upper bound (in each of its basic sets). |
11579 | */ |
11580 | isl_bool isl_set_dim_has_upper_bound(__isl_keep isl_set *set, |
11581 | enum isl_dim_type type, unsigned pos) |
11582 | { |
11583 | return has_bound(map: set, type, pos, fn: &isl_basic_map_dim_has_upper_bound); |
11584 | } |
11585 | |
11586 | /* For each of the "n" variables starting at "first", determine |
11587 | * the sign of the variable and put the results in the first "n" |
11588 | * elements of the array "signs". |
11589 | * Sign |
11590 | * 1 means that the variable is non-negative |
11591 | * -1 means that the variable is non-positive |
11592 | * 0 means the variable attains both positive and negative values. |
11593 | */ |
11594 | isl_stat isl_basic_set_vars_get_sign(__isl_keep isl_basic_set *bset, |
11595 | unsigned first, unsigned n, int *signs) |
11596 | { |
11597 | isl_vec *bound = NULL; |
11598 | struct isl_tab *tab = NULL; |
11599 | struct isl_tab_undo *snap; |
11600 | int i; |
11601 | isl_size total; |
11602 | |
11603 | total = isl_basic_set_dim(bset, type: isl_dim_all); |
11604 | if (total < 0 || !signs) |
11605 | return isl_stat_error; |
11606 | |
11607 | bound = isl_vec_alloc(ctx: bset->ctx, size: 1 + total); |
11608 | tab = isl_tab_from_basic_set(bset, track: 0); |
11609 | if (!bound || !tab) |
11610 | goto error; |
11611 | |
11612 | isl_seq_clr(p: bound->el, len: bound->size); |
11613 | isl_int_set_si(bound->el[0], -1); |
11614 | |
11615 | snap = isl_tab_snap(tab); |
11616 | for (i = 0; i < n; ++i) { |
11617 | int empty; |
11618 | |
11619 | isl_int_set_si(bound->el[1 + first + i], -1); |
11620 | if (isl_tab_add_ineq(tab, ineq: bound->el) < 0) |
11621 | goto error; |
11622 | empty = tab->empty; |
11623 | isl_int_set_si(bound->el[1 + first + i], 0); |
11624 | if (isl_tab_rollback(tab, snap) < 0) |
11625 | goto error; |
11626 | |
11627 | if (empty) { |
11628 | signs[i] = 1; |
11629 | continue; |
11630 | } |
11631 | |
11632 | isl_int_set_si(bound->el[1 + first + i], 1); |
11633 | if (isl_tab_add_ineq(tab, ineq: bound->el) < 0) |
11634 | goto error; |
11635 | empty = tab->empty; |
11636 | isl_int_set_si(bound->el[1 + first + i], 0); |
11637 | if (isl_tab_rollback(tab, snap) < 0) |
11638 | goto error; |
11639 | |
11640 | signs[i] = empty ? -1 : 0; |
11641 | } |
11642 | |
11643 | isl_tab_free(tab); |
11644 | isl_vec_free(vec: bound); |
11645 | return isl_stat_ok; |
11646 | error: |
11647 | isl_tab_free(tab); |
11648 | isl_vec_free(vec: bound); |
11649 | return isl_stat_error; |
11650 | } |
11651 | |
11652 | isl_stat isl_basic_set_dims_get_sign(__isl_keep isl_basic_set *bset, |
11653 | enum isl_dim_type type, unsigned first, unsigned n, int *signs) |
11654 | { |
11655 | if (!bset || !signs) |
11656 | return isl_stat_error; |
11657 | if (isl_basic_set_check_range(bset, type, first, n) < 0) |
11658 | return isl_stat_error; |
11659 | |
11660 | first += pos(space: bset->dim, type) - 1; |
11661 | return isl_basic_set_vars_get_sign(bset, first, n, signs); |
11662 | } |
11663 | |
11664 | /* Is it possible for the integer division "div" to depend (possibly |
11665 | * indirectly) on any output dimensions? |
11666 | * |
11667 | * If the div is undefined, then we conservatively assume that it |
11668 | * may depend on them. |
11669 | * Otherwise, we check if it actually depends on them or on any integer |
11670 | * divisions that may depend on them. |
11671 | */ |
11672 | static isl_bool div_may_involve_output(__isl_keep isl_basic_map *bmap, int div) |
11673 | { |
11674 | int i; |
11675 | isl_size n_out, n_div; |
11676 | unsigned o_out, o_div; |
11677 | |
11678 | if (isl_int_is_zero(bmap->div[div][0])) |
11679 | return isl_bool_true; |
11680 | |
11681 | n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
11682 | if (n_out < 0) |
11683 | return isl_bool_error; |
11684 | o_out = isl_basic_map_offset(bmap, type: isl_dim_out); |
11685 | |
11686 | if (isl_seq_first_non_zero(p: bmap->div[div] + 1 + o_out, len: n_out) != -1) |
11687 | return isl_bool_true; |
11688 | |
11689 | n_div = isl_basic_map_dim(bmap, type: isl_dim_div); |
11690 | if (n_div < 0) |
11691 | return isl_bool_error; |
11692 | o_div = isl_basic_map_offset(bmap, type: isl_dim_div); |
11693 | |
11694 | for (i = 0; i < n_div; ++i) { |
11695 | isl_bool may_involve; |
11696 | |
11697 | if (isl_int_is_zero(bmap->div[div][1 + o_div + i])) |
11698 | continue; |
11699 | may_involve = div_may_involve_output(bmap, div: i); |
11700 | if (may_involve < 0 || may_involve) |
11701 | return may_involve; |
11702 | } |
11703 | |
11704 | return isl_bool_false; |
11705 | } |
11706 | |
11707 | /* Return the first integer division of "bmap" in the range |
11708 | * [first, first + n[ that may depend on any output dimensions and |
11709 | * that has a non-zero coefficient in "c" (where the first coefficient |
11710 | * in "c" corresponds to integer division "first"). |
11711 | */ |
11712 | static int first_div_may_involve_output(__isl_keep isl_basic_map *bmap, |
11713 | isl_int *c, int first, int n) |
11714 | { |
11715 | int k; |
11716 | |
11717 | if (!bmap) |
11718 | return -1; |
11719 | |
11720 | for (k = first; k < first + n; ++k) { |
11721 | isl_bool may_involve; |
11722 | |
11723 | if (isl_int_is_zero(c[k])) |
11724 | continue; |
11725 | may_involve = div_may_involve_output(bmap, div: k); |
11726 | if (may_involve < 0) |
11727 | return -1; |
11728 | if (may_involve) |
11729 | return k; |
11730 | } |
11731 | |
11732 | return first + n; |
11733 | } |
11734 | |
11735 | /* Look for a pair of inequality constraints in "bmap" of the form |
11736 | * |
11737 | * -l + i >= 0 or i >= l |
11738 | * and |
11739 | * n + l - i >= 0 or i <= l + n |
11740 | * |
11741 | * with n < "m" and i the output dimension at position "pos". |
11742 | * (Note that n >= 0 as otherwise the two constraints would conflict.) |
11743 | * Furthermore, "l" is only allowed to involve parameters, input dimensions |
11744 | * and earlier output dimensions, as well as integer divisions that do |
11745 | * not involve any of the output dimensions. |
11746 | * |
11747 | * Return the index of the first inequality constraint or bmap->n_ineq |
11748 | * if no such pair can be found. |
11749 | */ |
11750 | static int find_modulo_constraint_pair(__isl_keep isl_basic_map *bmap, |
11751 | int pos, isl_int m) |
11752 | { |
11753 | int i, j; |
11754 | isl_ctx *ctx; |
11755 | isl_size total; |
11756 | isl_size n_div, n_out; |
11757 | unsigned o_div, o_out; |
11758 | int less; |
11759 | |
11760 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
11761 | n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
11762 | n_div = isl_basic_map_dim(bmap, type: isl_dim_div); |
11763 | if (total < 0 || n_out < 0 || n_div < 0) |
11764 | return -1; |
11765 | |
11766 | ctx = isl_basic_map_get_ctx(bmap); |
11767 | o_out = isl_basic_map_offset(bmap, type: isl_dim_out); |
11768 | o_div = isl_basic_map_offset(bmap, type: isl_dim_div); |
11769 | for (i = 0; i < bmap->n_ineq; ++i) { |
11770 | if (!isl_int_abs_eq(bmap->ineq[i][o_out + pos], ctx->one)) |
11771 | continue; |
11772 | if (isl_seq_first_non_zero(p: bmap->ineq[i] + o_out + pos + 1, |
11773 | len: n_out - (pos + 1)) != -1) |
11774 | continue; |
11775 | if (first_div_may_involve_output(bmap, c: bmap->ineq[i] + o_div, |
11776 | first: 0, n: n_div) < n_div) |
11777 | continue; |
11778 | for (j = i + 1; j < bmap->n_ineq; ++j) { |
11779 | if (!isl_int_abs_eq(bmap->ineq[j][o_out + pos], |
11780 | ctx->one)) |
11781 | continue; |
11782 | if (!isl_seq_is_neg(p1: bmap->ineq[i] + 1, |
11783 | p2: bmap->ineq[j] + 1, len: total)) |
11784 | continue; |
11785 | break; |
11786 | } |
11787 | if (j >= bmap->n_ineq) |
11788 | continue; |
11789 | isl_int_add(bmap->ineq[i][0], |
11790 | bmap->ineq[i][0], bmap->ineq[j][0]); |
11791 | less = isl_int_abs_lt(bmap->ineq[i][0], m); |
11792 | isl_int_sub(bmap->ineq[i][0], |
11793 | bmap->ineq[i][0], bmap->ineq[j][0]); |
11794 | if (!less) |
11795 | continue; |
11796 | if (isl_int_is_one(bmap->ineq[i][o_out + pos])) |
11797 | return i; |
11798 | else |
11799 | return j; |
11800 | } |
11801 | |
11802 | return bmap->n_ineq; |
11803 | } |
11804 | |
11805 | /* Return the index of the equality of "bmap" that defines |
11806 | * the output dimension "pos" in terms of earlier dimensions. |
11807 | * The equality may also involve integer divisions, as long |
11808 | * as those integer divisions are defined in terms of |
11809 | * parameters or input dimensions. |
11810 | * In this case, *div is set to the number of integer divisions and |
11811 | * *ineq is set to the number of inequality constraints (provided |
11812 | * div and ineq are not NULL). |
11813 | * |
11814 | * The equality may also involve a single integer division involving |
11815 | * the output dimensions (typically only output dimension "pos") as |
11816 | * long as the coefficient of output dimension "pos" is 1 or -1 and |
11817 | * there is a pair of constraints i >= l and i <= l + n, with i referring |
11818 | * to output dimension "pos", l an expression involving only earlier |
11819 | * dimensions and n smaller than the coefficient of the integer division |
11820 | * in the equality. In this case, the output dimension can be defined |
11821 | * in terms of a modulo expression that does not involve the integer division. |
11822 | * *div is then set to this single integer division and |
11823 | * *ineq is set to the index of constraint i >= l. |
11824 | * |
11825 | * Return bmap->n_eq if there is no such equality. |
11826 | * Return -1 on error. |
11827 | */ |
11828 | int isl_basic_map_output_defining_equality(__isl_keep isl_basic_map *bmap, |
11829 | int pos, int *div, int *ineq) |
11830 | { |
11831 | int j, k, l; |
11832 | isl_size n_div, n_out; |
11833 | unsigned o_div, o_out; |
11834 | |
11835 | n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
11836 | n_div = isl_basic_map_dim(bmap, type: isl_dim_div); |
11837 | if (n_out < 0 || n_div < 0) |
11838 | return -1; |
11839 | |
11840 | o_out = isl_basic_map_offset(bmap, type: isl_dim_out); |
11841 | o_div = isl_basic_map_offset(bmap, type: isl_dim_div); |
11842 | |
11843 | if (ineq) |
11844 | *ineq = bmap->n_ineq; |
11845 | if (div) |
11846 | *div = n_div; |
11847 | for (j = 0; j < bmap->n_eq; ++j) { |
11848 | if (isl_int_is_zero(bmap->eq[j][o_out + pos])) |
11849 | continue; |
11850 | if (isl_seq_first_non_zero(p: bmap->eq[j] + o_out + pos + 1, |
11851 | len: n_out - (pos + 1)) != -1) |
11852 | continue; |
11853 | k = first_div_may_involve_output(bmap, c: bmap->eq[j] + o_div, |
11854 | first: 0, n: n_div); |
11855 | if (k >= n_div) |
11856 | return j; |
11857 | if (!isl_int_is_one(bmap->eq[j][o_out + pos]) && |
11858 | !isl_int_is_negone(bmap->eq[j][o_out + pos])) |
11859 | continue; |
11860 | if (first_div_may_involve_output(bmap, c: bmap->eq[j] + o_div, |
11861 | first: k + 1, n: n_div - (k+1)) < n_div) |
11862 | continue; |
11863 | l = find_modulo_constraint_pair(bmap, pos, |
11864 | m: bmap->eq[j][o_div + k]); |
11865 | if (l < 0) |
11866 | return -1; |
11867 | if (l >= bmap->n_ineq) |
11868 | continue; |
11869 | if (div) |
11870 | *div = k; |
11871 | if (ineq) |
11872 | *ineq = l; |
11873 | return j; |
11874 | } |
11875 | |
11876 | return bmap->n_eq; |
11877 | } |
11878 | |
11879 | /* Check if the given basic map is obviously single-valued. |
11880 | * In particular, for each output dimension, check that there is |
11881 | * an equality that defines the output dimension in terms of |
11882 | * earlier dimensions. |
11883 | */ |
11884 | isl_bool isl_basic_map_plain_is_single_valued(__isl_keep isl_basic_map *bmap) |
11885 | { |
11886 | int i; |
11887 | isl_size n_out; |
11888 | |
11889 | n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
11890 | if (n_out < 0) |
11891 | return isl_bool_error; |
11892 | |
11893 | for (i = 0; i < n_out; ++i) { |
11894 | int eq; |
11895 | |
11896 | eq = isl_basic_map_output_defining_equality(bmap, pos: i, |
11897 | NULL, NULL); |
11898 | if (eq < 0) |
11899 | return isl_bool_error; |
11900 | if (eq >= bmap->n_eq) |
11901 | return isl_bool_false; |
11902 | } |
11903 | |
11904 | return isl_bool_true; |
11905 | } |
11906 | |
11907 | /* Check if the given basic map is single-valued. |
11908 | * We simply compute |
11909 | * |
11910 | * M \circ M^-1 |
11911 | * |
11912 | * and check if the result is a subset of the identity mapping. |
11913 | */ |
11914 | isl_bool isl_basic_map_is_single_valued(__isl_keep isl_basic_map *bmap) |
11915 | { |
11916 | isl_space *space; |
11917 | isl_basic_map *test; |
11918 | isl_basic_map *id; |
11919 | isl_bool sv; |
11920 | |
11921 | sv = isl_basic_map_plain_is_single_valued(bmap); |
11922 | if (sv < 0 || sv) |
11923 | return sv; |
11924 | |
11925 | test = isl_basic_map_reverse(bmap: isl_basic_map_copy(bmap)); |
11926 | test = isl_basic_map_apply_range(bmap1: test, bmap2: isl_basic_map_copy(bmap)); |
11927 | |
11928 | space = isl_basic_map_get_space(bmap); |
11929 | space = isl_space_map_from_set(space: isl_space_range(space)); |
11930 | id = isl_basic_map_identity(space); |
11931 | |
11932 | sv = isl_basic_map_is_subset(bmap1: test, bmap2: id); |
11933 | |
11934 | isl_basic_map_free(bmap: test); |
11935 | isl_basic_map_free(bmap: id); |
11936 | |
11937 | return sv; |
11938 | } |
11939 | |
11940 | /* Check if the given map is obviously single-valued. |
11941 | */ |
11942 | isl_bool isl_map_plain_is_single_valued(__isl_keep isl_map *map) |
11943 | { |
11944 | if (!map) |
11945 | return isl_bool_error; |
11946 | if (map->n == 0) |
11947 | return isl_bool_true; |
11948 | if (map->n >= 2) |
11949 | return isl_bool_false; |
11950 | |
11951 | return isl_basic_map_plain_is_single_valued(bmap: map->p[0]); |
11952 | } |
11953 | |
11954 | /* Check if the given map is single-valued. |
11955 | * We simply compute |
11956 | * |
11957 | * M \circ M^-1 |
11958 | * |
11959 | * and check if the result is a subset of the identity mapping. |
11960 | */ |
11961 | isl_bool isl_map_is_single_valued(__isl_keep isl_map *map) |
11962 | { |
11963 | isl_space *space; |
11964 | isl_map *test; |
11965 | isl_map *id; |
11966 | isl_bool sv; |
11967 | |
11968 | sv = isl_map_plain_is_single_valued(map); |
11969 | if (sv < 0 || sv) |
11970 | return sv; |
11971 | |
11972 | test = isl_map_reverse(map: isl_map_copy(map)); |
11973 | test = isl_map_apply_range(map1: test, map2: isl_map_copy(map)); |
11974 | |
11975 | space = isl_space_map_from_set(space: isl_space_range(space: isl_map_get_space(map))); |
11976 | id = isl_map_identity(space); |
11977 | |
11978 | sv = isl_map_is_subset(map1: test, map2: id); |
11979 | |
11980 | isl_map_free(map: test); |
11981 | isl_map_free(map: id); |
11982 | |
11983 | return sv; |
11984 | } |
11985 | |
11986 | isl_bool isl_map_is_injective(__isl_keep isl_map *map) |
11987 | { |
11988 | isl_bool in; |
11989 | |
11990 | map = isl_map_copy(map); |
11991 | map = isl_map_reverse(map); |
11992 | in = isl_map_is_single_valued(map); |
11993 | isl_map_free(map); |
11994 | |
11995 | return in; |
11996 | } |
11997 | |
11998 | /* Check if the given map is obviously injective. |
11999 | */ |
12000 | isl_bool isl_map_plain_is_injective(__isl_keep isl_map *map) |
12001 | { |
12002 | isl_bool in; |
12003 | |
12004 | map = isl_map_copy(map); |
12005 | map = isl_map_reverse(map); |
12006 | in = isl_map_plain_is_single_valued(map); |
12007 | isl_map_free(map); |
12008 | |
12009 | return in; |
12010 | } |
12011 | |
12012 | isl_bool isl_map_is_bijective(__isl_keep isl_map *map) |
12013 | { |
12014 | isl_bool sv; |
12015 | |
12016 | sv = isl_map_is_single_valued(map); |
12017 | if (sv < 0 || !sv) |
12018 | return sv; |
12019 | |
12020 | return isl_map_is_injective(map); |
12021 | } |
12022 | |
12023 | isl_bool isl_set_is_singleton(__isl_keep isl_set *set) |
12024 | { |
12025 | return isl_map_is_single_valued(map: set_to_map(set)); |
12026 | } |
12027 | |
12028 | /* Does "map" only map elements to themselves? |
12029 | * |
12030 | * If the domain and range spaces are different, then "map" |
12031 | * is considered not to be an identity relation, even if it is empty. |
12032 | * Otherwise, construct the maximal identity relation and |
12033 | * check whether "map" is a subset of this relation. |
12034 | */ |
12035 | isl_bool isl_map_is_identity(__isl_keep isl_map *map) |
12036 | { |
12037 | isl_map *id; |
12038 | isl_bool equal, is_identity; |
12039 | |
12040 | equal = isl_map_tuple_is_equal(map1: map, type1: isl_dim_in, map2: map, type2: isl_dim_out); |
12041 | if (equal < 0 || !equal) |
12042 | return equal; |
12043 | |
12044 | id = isl_map_identity(space: isl_map_get_space(map)); |
12045 | is_identity = isl_map_is_subset(map1: map, map2: id); |
12046 | isl_map_free(map: id); |
12047 | |
12048 | return is_identity; |
12049 | } |
12050 | |
12051 | int isl_map_is_translation(__isl_keep isl_map *map) |
12052 | { |
12053 | int ok; |
12054 | isl_set *delta; |
12055 | |
12056 | delta = isl_map_deltas(map: isl_map_copy(map)); |
12057 | ok = isl_set_is_singleton(set: delta); |
12058 | isl_set_free(set: delta); |
12059 | |
12060 | return ok; |
12061 | } |
12062 | |
12063 | static int unique(isl_int *p, unsigned pos, unsigned len) |
12064 | { |
12065 | if (isl_seq_first_non_zero(p, len: pos) != -1) |
12066 | return 0; |
12067 | if (isl_seq_first_non_zero(p: p + pos + 1, len: len - pos - 1) != -1) |
12068 | return 0; |
12069 | return 1; |
12070 | } |
12071 | |
12072 | isl_bool isl_basic_set_is_box(__isl_keep isl_basic_set *bset) |
12073 | { |
12074 | int i, j; |
12075 | isl_size nvar, n_div; |
12076 | unsigned ovar; |
12077 | |
12078 | n_div = isl_basic_set_dim(bset, type: isl_dim_div); |
12079 | if (n_div < 0) |
12080 | return isl_bool_error; |
12081 | if (n_div != 0) |
12082 | return isl_bool_false; |
12083 | |
12084 | nvar = isl_basic_set_dim(bset, type: isl_dim_set); |
12085 | if (nvar < 0) |
12086 | return isl_bool_error; |
12087 | ovar = isl_space_offset(space: bset->dim, type: isl_dim_set); |
12088 | for (j = 0; j < nvar; ++j) { |
12089 | int lower = 0, upper = 0; |
12090 | for (i = 0; i < bset->n_eq; ++i) { |
12091 | if (isl_int_is_zero(bset->eq[i][1 + ovar + j])) |
12092 | continue; |
12093 | if (!unique(p: bset->eq[i] + 1 + ovar, pos: j, len: nvar)) |
12094 | return isl_bool_false; |
12095 | break; |
12096 | } |
12097 | if (i < bset->n_eq) |
12098 | continue; |
12099 | for (i = 0; i < bset->n_ineq; ++i) { |
12100 | if (isl_int_is_zero(bset->ineq[i][1 + ovar + j])) |
12101 | continue; |
12102 | if (!unique(p: bset->ineq[i] + 1 + ovar, pos: j, len: nvar)) |
12103 | return isl_bool_false; |
12104 | if (isl_int_is_pos(bset->ineq[i][1 + ovar + j])) |
12105 | lower = 1; |
12106 | else |
12107 | upper = 1; |
12108 | } |
12109 | if (!lower || !upper) |
12110 | return isl_bool_false; |
12111 | } |
12112 | |
12113 | return isl_bool_true; |
12114 | } |
12115 | |
12116 | isl_bool isl_set_is_box(__isl_keep isl_set *set) |
12117 | { |
12118 | if (!set) |
12119 | return isl_bool_error; |
12120 | if (set->n != 1) |
12121 | return isl_bool_false; |
12122 | |
12123 | return isl_basic_set_is_box(bset: set->p[0]); |
12124 | } |
12125 | |
12126 | isl_bool isl_basic_set_is_wrapping(__isl_keep isl_basic_set *bset) |
12127 | { |
12128 | if (!bset) |
12129 | return isl_bool_error; |
12130 | |
12131 | return isl_space_is_wrapping(space: bset->dim); |
12132 | } |
12133 | |
12134 | isl_bool isl_set_is_wrapping(__isl_keep isl_set *set) |
12135 | { |
12136 | if (!set) |
12137 | return isl_bool_error; |
12138 | |
12139 | return isl_space_is_wrapping(space: set->dim); |
12140 | } |
12141 | |
12142 | /* Modify the space of "map" through a call to "change". |
12143 | * If "can_change" is set (not NULL), then first call it to check |
12144 | * if the modification is allowed, printing the error message "cannot_change" |
12145 | * if it is not. |
12146 | */ |
12147 | static __isl_give isl_map *isl_map_change_space(__isl_take isl_map *map, |
12148 | isl_bool (*can_change)(__isl_keep isl_map *map), |
12149 | const char *cannot_change, |
12150 | __isl_give isl_space *(*change)(__isl_take isl_space *space)) |
12151 | { |
12152 | isl_bool ok; |
12153 | isl_space *space; |
12154 | |
12155 | if (!map) |
12156 | return NULL; |
12157 | |
12158 | ok = can_change ? can_change(map) : isl_bool_true; |
12159 | if (ok < 0) |
12160 | return isl_map_free(map); |
12161 | if (!ok) |
12162 | isl_die(isl_map_get_ctx(map), isl_error_invalid, cannot_change, |
12163 | return isl_map_free(map)); |
12164 | |
12165 | space = change(isl_map_get_space(map)); |
12166 | map = isl_map_reset_space(map, space); |
12167 | |
12168 | return map; |
12169 | } |
12170 | |
12171 | /* Is the domain of "map" a wrapped relation? |
12172 | */ |
12173 | isl_bool isl_map_domain_is_wrapping(__isl_keep isl_map *map) |
12174 | { |
12175 | if (!map) |
12176 | return isl_bool_error; |
12177 | |
12178 | return isl_space_domain_is_wrapping(space: map->dim); |
12179 | } |
12180 | |
12181 | /* Does "map" have a wrapped relation in both domain and range? |
12182 | */ |
12183 | isl_bool isl_map_is_product(__isl_keep isl_map *map) |
12184 | { |
12185 | return isl_space_is_product(space: isl_map_peek_space(map)); |
12186 | } |
12187 | |
12188 | /* Is the range of "map" a wrapped relation? |
12189 | */ |
12190 | isl_bool isl_map_range_is_wrapping(__isl_keep isl_map *map) |
12191 | { |
12192 | if (!map) |
12193 | return isl_bool_error; |
12194 | |
12195 | return isl_space_range_is_wrapping(space: map->dim); |
12196 | } |
12197 | |
12198 | __isl_give isl_basic_set *isl_basic_map_wrap(__isl_take isl_basic_map *bmap) |
12199 | { |
12200 | isl_space *space; |
12201 | |
12202 | space = isl_basic_map_take_space(bmap); |
12203 | space = isl_space_wrap(space); |
12204 | bmap = isl_basic_map_restore_space(bmap, space); |
12205 | |
12206 | bmap = isl_basic_map_finalize(bmap); |
12207 | |
12208 | return bset_from_bmap(bmap); |
12209 | } |
12210 | |
12211 | /* Given a map A -> B, return the set (A -> B). |
12212 | */ |
12213 | __isl_give isl_set *isl_map_wrap(__isl_take isl_map *map) |
12214 | { |
12215 | return isl_map_change_space(map, NULL, NULL, change: &isl_space_wrap); |
12216 | } |
12217 | |
12218 | __isl_give isl_basic_map *isl_basic_set_unwrap(__isl_take isl_basic_set *bset) |
12219 | { |
12220 | bset = isl_basic_set_cow(bset); |
12221 | if (!bset) |
12222 | return NULL; |
12223 | |
12224 | bset->dim = isl_space_unwrap(space: bset->dim); |
12225 | if (!bset->dim) |
12226 | goto error; |
12227 | |
12228 | bset = isl_basic_set_finalize(bset); |
12229 | |
12230 | return bset_to_bmap(bset); |
12231 | error: |
12232 | isl_basic_set_free(bset); |
12233 | return NULL; |
12234 | } |
12235 | |
12236 | /* Given a set (A -> B), return the map A -> B. |
12237 | * Error out if "set" is not of the form (A -> B). |
12238 | */ |
12239 | __isl_give isl_map *isl_set_unwrap(__isl_take isl_set *set) |
12240 | { |
12241 | return isl_map_change_space(map: set, can_change: &isl_set_is_wrapping, |
12242 | cannot_change: "not a wrapping set" , change: &isl_space_unwrap); |
12243 | } |
12244 | |
12245 | __isl_give isl_basic_map *isl_basic_map_reset(__isl_take isl_basic_map *bmap, |
12246 | enum isl_dim_type type) |
12247 | { |
12248 | isl_space *space; |
12249 | |
12250 | space = isl_basic_map_take_space(bmap); |
12251 | space = isl_space_reset(space, type); |
12252 | bmap = isl_basic_map_restore_space(bmap, space); |
12253 | |
12254 | bmap = isl_basic_map_mark_final(bmap); |
12255 | |
12256 | return bmap; |
12257 | } |
12258 | |
12259 | __isl_give isl_map *isl_map_reset(__isl_take isl_map *map, |
12260 | enum isl_dim_type type) |
12261 | { |
12262 | int i; |
12263 | isl_space *space; |
12264 | |
12265 | if (!map) |
12266 | return NULL; |
12267 | |
12268 | if (!isl_space_is_named_or_nested(space: map->dim, type)) |
12269 | return map; |
12270 | |
12271 | map = isl_map_cow(map); |
12272 | if (!map) |
12273 | return NULL; |
12274 | |
12275 | for (i = 0; i < map->n; ++i) { |
12276 | map->p[i] = isl_basic_map_reset(bmap: map->p[i], type); |
12277 | if (!map->p[i]) |
12278 | goto error; |
12279 | } |
12280 | |
12281 | space = isl_map_take_space(map); |
12282 | space = isl_space_reset(space, type); |
12283 | map = isl_map_restore_space(map, space); |
12284 | |
12285 | return map; |
12286 | error: |
12287 | isl_map_free(map); |
12288 | return NULL; |
12289 | } |
12290 | |
12291 | __isl_give isl_basic_map *isl_basic_map_flatten(__isl_take isl_basic_map *bmap) |
12292 | { |
12293 | isl_space *space; |
12294 | |
12295 | space = isl_basic_map_take_space(bmap); |
12296 | space = isl_space_flatten(space); |
12297 | bmap = isl_basic_map_restore_space(bmap, space); |
12298 | |
12299 | bmap = isl_basic_map_mark_final(bmap); |
12300 | |
12301 | return bmap; |
12302 | } |
12303 | |
12304 | __isl_give isl_basic_set *isl_basic_set_flatten(__isl_take isl_basic_set *bset) |
12305 | { |
12306 | return bset_from_bmap(bmap: isl_basic_map_flatten(bmap: bset_to_bmap(bset))); |
12307 | } |
12308 | |
12309 | __isl_give isl_basic_map *isl_basic_map_flatten_domain( |
12310 | __isl_take isl_basic_map *bmap) |
12311 | { |
12312 | isl_space *space; |
12313 | |
12314 | space = isl_basic_map_take_space(bmap); |
12315 | space = isl_space_flatten_domain(space); |
12316 | bmap = isl_basic_map_restore_space(bmap, space); |
12317 | |
12318 | bmap = isl_basic_map_mark_final(bmap); |
12319 | |
12320 | return bmap; |
12321 | } |
12322 | |
12323 | __isl_give isl_basic_map *isl_basic_map_flatten_range( |
12324 | __isl_take isl_basic_map *bmap) |
12325 | { |
12326 | isl_space *space; |
12327 | |
12328 | space = isl_basic_map_take_space(bmap); |
12329 | space = isl_space_flatten_range(space); |
12330 | bmap = isl_basic_map_restore_space(bmap, space); |
12331 | |
12332 | bmap = isl_basic_map_mark_final(bmap); |
12333 | |
12334 | return bmap; |
12335 | } |
12336 | |
12337 | /* Remove any internal structure from the spaces of domain and range of "map". |
12338 | */ |
12339 | __isl_give isl_map *isl_map_flatten(__isl_take isl_map *map) |
12340 | { |
12341 | if (!map) |
12342 | return NULL; |
12343 | |
12344 | if (!map->dim->nested[0] && !map->dim->nested[1]) |
12345 | return map; |
12346 | |
12347 | return isl_map_change_space(map, NULL, NULL, change: &isl_space_flatten); |
12348 | } |
12349 | |
12350 | __isl_give isl_set *isl_set_flatten(__isl_take isl_set *set) |
12351 | { |
12352 | return set_from_map(isl_map_flatten(map: set_to_map(set))); |
12353 | } |
12354 | |
12355 | __isl_give isl_map *isl_set_flatten_map(__isl_take isl_set *set) |
12356 | { |
12357 | isl_space *space, *flat_space; |
12358 | isl_map *map; |
12359 | |
12360 | space = isl_set_get_space(set); |
12361 | flat_space = isl_space_flatten(space: isl_space_copy(space)); |
12362 | map = isl_map_identity(space: isl_space_join(left: isl_space_reverse(space), |
12363 | right: flat_space)); |
12364 | map = isl_map_intersect_domain(map, set); |
12365 | |
12366 | return map; |
12367 | } |
12368 | |
12369 | /* Remove any internal structure from the space of the domain of "map". |
12370 | */ |
12371 | __isl_give isl_map *isl_map_flatten_domain(__isl_take isl_map *map) |
12372 | { |
12373 | if (!map) |
12374 | return NULL; |
12375 | |
12376 | if (!map->dim->nested[0]) |
12377 | return map; |
12378 | |
12379 | return isl_map_change_space(map, NULL, NULL, change: &isl_space_flatten_domain); |
12380 | } |
12381 | |
12382 | /* Remove any internal structure from the space of the range of "map". |
12383 | */ |
12384 | __isl_give isl_map *isl_map_flatten_range(__isl_take isl_map *map) |
12385 | { |
12386 | if (!map) |
12387 | return NULL; |
12388 | |
12389 | if (!map->dim->nested[1]) |
12390 | return map; |
12391 | |
12392 | return isl_map_change_space(map, NULL, NULL, change: &isl_space_flatten_range); |
12393 | } |
12394 | |
12395 | /* Reorder the dimensions of "bmap" according to the given dim_map |
12396 | * and set the dimension specification to "space" and |
12397 | * perform Gaussian elimination on the result. |
12398 | */ |
12399 | __isl_give isl_basic_map *isl_basic_map_realign(__isl_take isl_basic_map *bmap, |
12400 | __isl_take isl_space *space, __isl_take struct isl_dim_map *dim_map) |
12401 | { |
12402 | isl_basic_map *res; |
12403 | unsigned flags; |
12404 | isl_size n_div; |
12405 | |
12406 | n_div = isl_basic_map_dim(bmap, type: isl_dim_div); |
12407 | if (n_div < 0 || !space || !dim_map) |
12408 | goto error; |
12409 | |
12410 | flags = bmap->flags; |
12411 | ISL_FL_CLR(flags, ISL_BASIC_MAP_FINAL); |
12412 | ISL_FL_CLR(flags, ISL_BASIC_MAP_SORTED); |
12413 | ISL_FL_CLR(flags, ISL_BASIC_MAP_NORMALIZED_DIVS); |
12414 | res = isl_basic_map_alloc_space(space, extra: n_div, n_eq: bmap->n_eq, n_ineq: bmap->n_ineq); |
12415 | res = isl_basic_map_add_constraints_dim_map(dst: res, src: bmap, dim_map); |
12416 | if (res) |
12417 | res->flags = flags; |
12418 | res = isl_basic_map_gauss(bmap: res, NULL); |
12419 | res = isl_basic_map_finalize(bmap: res); |
12420 | return res; |
12421 | error: |
12422 | isl_dim_map_free(dim_map); |
12423 | isl_basic_map_free(bmap); |
12424 | isl_space_free(space); |
12425 | return NULL; |
12426 | } |
12427 | |
12428 | /* Reorder the dimensions of "map" according to given reordering. |
12429 | */ |
12430 | __isl_give isl_map *isl_map_realign(__isl_take isl_map *map, |
12431 | __isl_take isl_reordering *r) |
12432 | { |
12433 | int i; |
12434 | struct isl_dim_map *dim_map; |
12435 | |
12436 | map = isl_map_cow(map); |
12437 | dim_map = isl_dim_map_from_reordering(exp: r); |
12438 | if (!map || !r || !dim_map) |
12439 | goto error; |
12440 | |
12441 | for (i = 0; i < map->n; ++i) { |
12442 | struct isl_dim_map *dim_map_i; |
12443 | isl_space *space; |
12444 | |
12445 | dim_map_i = isl_dim_map_extend(dim_map, bmap: map->p[i]); |
12446 | |
12447 | space = isl_reordering_get_space(r); |
12448 | map->p[i] = isl_basic_map_realign(bmap: map->p[i], space, dim_map: dim_map_i); |
12449 | |
12450 | if (!map->p[i]) |
12451 | goto error; |
12452 | } |
12453 | |
12454 | map = isl_map_reset_space(map, space: isl_reordering_get_space(r)); |
12455 | map = isl_map_unmark_normalized(map); |
12456 | |
12457 | isl_reordering_free(exp: r); |
12458 | isl_dim_map_free(dim_map); |
12459 | return map; |
12460 | error: |
12461 | isl_dim_map_free(dim_map); |
12462 | isl_map_free(map); |
12463 | isl_reordering_free(exp: r); |
12464 | return NULL; |
12465 | } |
12466 | |
12467 | __isl_give isl_set *isl_set_realign(__isl_take isl_set *set, |
12468 | __isl_take isl_reordering *r) |
12469 | { |
12470 | return set_from_map(isl_map_realign(map: set_to_map(set), r)); |
12471 | } |
12472 | |
12473 | __isl_give isl_map *isl_map_align_params(__isl_take isl_map *map, |
12474 | __isl_take isl_space *model) |
12475 | { |
12476 | isl_ctx *ctx; |
12477 | isl_bool aligned; |
12478 | |
12479 | if (!map || !model) |
12480 | goto error; |
12481 | |
12482 | ctx = isl_space_get_ctx(space: model); |
12483 | if (!isl_space_has_named_params(space: model)) |
12484 | isl_die(ctx, isl_error_invalid, |
12485 | "model has unnamed parameters" , goto error); |
12486 | if (isl_map_check_named_params(obj: map) < 0) |
12487 | goto error; |
12488 | aligned = isl_map_space_has_equal_params(map, space: model); |
12489 | if (aligned < 0) |
12490 | goto error; |
12491 | if (!aligned) { |
12492 | isl_space *space; |
12493 | isl_reordering *exp; |
12494 | |
12495 | space = isl_map_peek_space(map); |
12496 | exp = isl_parameter_alignment_reordering(alignee: space, aligner: model); |
12497 | map = isl_map_realign(map, r: exp); |
12498 | } |
12499 | |
12500 | isl_space_free(space: model); |
12501 | return map; |
12502 | error: |
12503 | isl_space_free(space: model); |
12504 | isl_map_free(map); |
12505 | return NULL; |
12506 | } |
12507 | |
12508 | __isl_give isl_set *isl_set_align_params(__isl_take isl_set *set, |
12509 | __isl_take isl_space *model) |
12510 | { |
12511 | return isl_map_align_params(map: set, model); |
12512 | } |
12513 | |
12514 | /* Align the parameters of "bmap" to those of "model", introducing |
12515 | * additional parameters if needed. |
12516 | */ |
12517 | __isl_give isl_basic_map *isl_basic_map_align_params( |
12518 | __isl_take isl_basic_map *bmap, __isl_take isl_space *model) |
12519 | { |
12520 | isl_ctx *ctx; |
12521 | isl_bool equal_params; |
12522 | isl_space *bmap_space; |
12523 | |
12524 | if (!bmap || !model) |
12525 | goto error; |
12526 | |
12527 | ctx = isl_space_get_ctx(space: model); |
12528 | if (!isl_space_has_named_params(space: model)) |
12529 | isl_die(ctx, isl_error_invalid, |
12530 | "model has unnamed parameters" , goto error); |
12531 | if (isl_basic_map_check_named_params(obj: bmap) < 0) |
12532 | goto error; |
12533 | bmap_space = isl_basic_map_peek_space(bmap); |
12534 | equal_params = isl_space_has_equal_params(space1: bmap_space, space2: model); |
12535 | if (equal_params < 0) |
12536 | goto error; |
12537 | if (!equal_params) { |
12538 | isl_reordering *exp; |
12539 | struct isl_dim_map *dim_map; |
12540 | |
12541 | exp = isl_parameter_alignment_reordering(alignee: bmap_space, aligner: model); |
12542 | dim_map = isl_dim_map_from_reordering(exp); |
12543 | bmap = isl_basic_map_realign(bmap, |
12544 | space: isl_reordering_get_space(r: exp), |
12545 | dim_map: isl_dim_map_extend(dim_map, bmap)); |
12546 | isl_reordering_free(exp); |
12547 | isl_dim_map_free(dim_map); |
12548 | } |
12549 | |
12550 | isl_space_free(space: model); |
12551 | return bmap; |
12552 | error: |
12553 | isl_space_free(space: model); |
12554 | isl_basic_map_free(bmap); |
12555 | return NULL; |
12556 | } |
12557 | |
12558 | /* Do "bset" and "space" have the same parameters? |
12559 | */ |
12560 | isl_bool isl_basic_set_space_has_equal_params(__isl_keep isl_basic_set *bset, |
12561 | __isl_keep isl_space *space) |
12562 | { |
12563 | isl_space *bset_space; |
12564 | |
12565 | bset_space = isl_basic_set_peek_space(bset); |
12566 | return isl_space_has_equal_params(space1: bset_space, space2: space); |
12567 | } |
12568 | |
12569 | /* Do "map" and "space" have the same parameters? |
12570 | */ |
12571 | isl_bool isl_map_space_has_equal_params(__isl_keep isl_map *map, |
12572 | __isl_keep isl_space *space) |
12573 | { |
12574 | isl_space *map_space; |
12575 | |
12576 | map_space = isl_map_peek_space(map); |
12577 | return isl_space_has_equal_params(space1: map_space, space2: space); |
12578 | } |
12579 | |
12580 | /* Do "set" and "space" have the same parameters? |
12581 | */ |
12582 | isl_bool isl_set_space_has_equal_params(__isl_keep isl_set *set, |
12583 | __isl_keep isl_space *space) |
12584 | { |
12585 | return isl_map_space_has_equal_params(map: set_to_map(set), space); |
12586 | } |
12587 | |
12588 | /* Align the parameters of "bset" to those of "model", introducing |
12589 | * additional parameters if needed. |
12590 | */ |
12591 | __isl_give isl_basic_set *isl_basic_set_align_params( |
12592 | __isl_take isl_basic_set *bset, __isl_take isl_space *model) |
12593 | { |
12594 | return isl_basic_map_align_params(bmap: bset, model); |
12595 | } |
12596 | |
12597 | /* Drop all parameters not referenced by "map". |
12598 | */ |
12599 | __isl_give isl_map *isl_map_drop_unused_params(__isl_take isl_map *map) |
12600 | { |
12601 | int i; |
12602 | isl_size n; |
12603 | |
12604 | n = isl_map_dim(map, type: isl_dim_param); |
12605 | if (isl_map_check_named_params(obj: map) < 0 || n < 0) |
12606 | return isl_map_free(map); |
12607 | |
12608 | for (i = n - 1; i >= 0; i--) { |
12609 | isl_bool involves; |
12610 | |
12611 | involves = isl_map_involves_dims(map, type: isl_dim_param, first: i, n: 1); |
12612 | if (involves < 0) |
12613 | return isl_map_free(map); |
12614 | if (!involves) |
12615 | map = isl_map_project_out(map, type: isl_dim_param, first: i, n: 1); |
12616 | } |
12617 | |
12618 | return map; |
12619 | } |
12620 | |
12621 | /* Drop all parameters not referenced by "set". |
12622 | */ |
12623 | __isl_give isl_set *isl_set_drop_unused_params( |
12624 | __isl_take isl_set *set) |
12625 | { |
12626 | return set_from_map(isl_map_drop_unused_params(map: set_to_map(set))); |
12627 | } |
12628 | |
12629 | /* Drop all parameters not referenced by "bmap". |
12630 | */ |
12631 | __isl_give isl_basic_map *isl_basic_map_drop_unused_params( |
12632 | __isl_take isl_basic_map *bmap) |
12633 | { |
12634 | isl_size nparam; |
12635 | int i; |
12636 | |
12637 | nparam = isl_basic_map_dim(bmap, type: isl_dim_param); |
12638 | if (nparam < 0 || isl_basic_map_check_named_params(obj: bmap) < 0) |
12639 | return isl_basic_map_free(bmap); |
12640 | |
12641 | for (i = nparam - 1; i >= 0; i--) { |
12642 | isl_bool involves; |
12643 | |
12644 | involves = isl_basic_map_involves_dims(bmap, |
12645 | type: isl_dim_param, first: i, n: 1); |
12646 | if (involves < 0) |
12647 | return isl_basic_map_free(bmap); |
12648 | if (!involves) |
12649 | bmap = isl_basic_map_drop(bmap, type: isl_dim_param, first: i, n: 1); |
12650 | } |
12651 | |
12652 | return bmap; |
12653 | } |
12654 | |
12655 | /* Drop all parameters not referenced by "bset". |
12656 | */ |
12657 | __isl_give isl_basic_set *isl_basic_set_drop_unused_params( |
12658 | __isl_take isl_basic_set *bset) |
12659 | { |
12660 | return bset_from_bmap(bmap: isl_basic_map_drop_unused_params( |
12661 | bmap: bset_to_bmap(bset))); |
12662 | } |
12663 | |
12664 | /* Given a tuple of identifiers "tuple" in a space that corresponds |
12665 | * to that of "set", if any of those identifiers appear as parameters |
12666 | * in "set", then equate those parameters with the corresponding |
12667 | * set dimensions and project out the parameters. |
12668 | * The result therefore has no such parameters. |
12669 | */ |
12670 | static __isl_give isl_set *equate_params(__isl_take isl_set *set, |
12671 | __isl_keep isl_multi_id *tuple) |
12672 | { |
12673 | int i; |
12674 | isl_size n; |
12675 | isl_space *set_space, *tuple_space; |
12676 | |
12677 | set_space = isl_set_peek_space(set); |
12678 | tuple_space = isl_multi_id_peek_space(multi: tuple); |
12679 | if (isl_space_check_equal_tuples(space1: tuple_space, space2: set_space) < 0) |
12680 | return isl_set_free(set); |
12681 | n = isl_multi_id_size(multi: tuple); |
12682 | if (n < 0) |
12683 | return isl_set_free(set); |
12684 | for (i = 0; i < n; ++i) { |
12685 | isl_id *id; |
12686 | int pos; |
12687 | |
12688 | id = isl_multi_id_get_at(multi: tuple, pos: i); |
12689 | if (!id) |
12690 | return isl_set_free(set); |
12691 | pos = isl_set_find_dim_by_id(set, type: isl_dim_param, id); |
12692 | isl_id_free(id); |
12693 | if (pos < 0) |
12694 | continue; |
12695 | set = isl_set_equate(set, type1: isl_dim_param, pos1: pos, type2: isl_dim_set, pos2: i); |
12696 | set = isl_set_project_out(set, type: isl_dim_param, first: pos, n: 1); |
12697 | } |
12698 | return set; |
12699 | } |
12700 | |
12701 | /* Bind the set dimensions of "set" to parameters with identifiers |
12702 | * specified by "tuple", living in the same space as "set". |
12703 | * |
12704 | * If no parameters with these identifiers appear in "set" already, |
12705 | * then the set dimensions are simply reinterpreted as parameters. |
12706 | * Otherwise, the parameters are first equated to the corresponding |
12707 | * set dimensions. |
12708 | */ |
12709 | __isl_give isl_set *isl_set_bind(__isl_take isl_set *set, |
12710 | __isl_take isl_multi_id *tuple) |
12711 | { |
12712 | isl_space *space; |
12713 | |
12714 | set = equate_params(set, tuple); |
12715 | space = isl_set_get_space(set); |
12716 | space = isl_space_bind_set(space, tuple); |
12717 | isl_multi_id_free(multi: tuple); |
12718 | set = isl_set_reset_space(set, space); |
12719 | |
12720 | return set; |
12721 | } |
12722 | |
12723 | /* Given a tuple of identifiers "tuple" in a space that corresponds |
12724 | * to the domain of "map", if any of those identifiers appear as parameters |
12725 | * in "map", then equate those parameters with the corresponding |
12726 | * input dimensions and project out the parameters. |
12727 | * The result therefore has no such parameters. |
12728 | */ |
12729 | static __isl_give isl_map *map_equate_params(__isl_take isl_map *map, |
12730 | __isl_keep isl_multi_id *tuple) |
12731 | { |
12732 | int i; |
12733 | isl_size n; |
12734 | isl_space *map_space, *tuple_space; |
12735 | |
12736 | map_space = isl_map_peek_space(map); |
12737 | tuple_space = isl_multi_id_peek_space(multi: tuple); |
12738 | if (isl_space_check_domain_tuples(space1: tuple_space, space2: map_space) < 0) |
12739 | return isl_map_free(map); |
12740 | n = isl_multi_id_size(multi: tuple); |
12741 | if (n < 0) |
12742 | return isl_map_free(map); |
12743 | for (i = 0; i < n; ++i) { |
12744 | isl_id *id; |
12745 | int pos; |
12746 | |
12747 | id = isl_multi_id_get_at(multi: tuple, pos: i); |
12748 | if (!id) |
12749 | return isl_map_free(map); |
12750 | pos = isl_map_find_dim_by_id(map, type: isl_dim_param, id); |
12751 | isl_id_free(id); |
12752 | if (pos < 0) |
12753 | continue; |
12754 | map = isl_map_equate(map, type1: isl_dim_param, pos1: pos, type2: isl_dim_in, pos2: i); |
12755 | map = isl_map_project_out(map, type: isl_dim_param, first: pos, n: 1); |
12756 | } |
12757 | return map; |
12758 | } |
12759 | |
12760 | /* Bind the input dimensions of "map" to parameters with identifiers |
12761 | * specified by "tuple", living in the domain space of "map". |
12762 | * |
12763 | * If no parameters with these identifiers appear in "map" already, |
12764 | * then the input dimensions are simply reinterpreted as parameters. |
12765 | * Otherwise, the parameters are first equated to the corresponding |
12766 | * input dimensions. |
12767 | */ |
12768 | __isl_give isl_set *isl_map_bind_domain(__isl_take isl_map *map, |
12769 | __isl_take isl_multi_id *tuple) |
12770 | { |
12771 | isl_space *space; |
12772 | isl_set *set; |
12773 | |
12774 | map = map_equate_params(map, tuple); |
12775 | space = isl_map_get_space(map); |
12776 | space = isl_space_bind_map_domain(space, tuple); |
12777 | isl_multi_id_free(multi: tuple); |
12778 | set = set_from_map(isl_map_reset_space(map, space)); |
12779 | |
12780 | return set; |
12781 | } |
12782 | |
12783 | /* Bind the output dimensions of "map" to parameters with identifiers |
12784 | * specified by "tuple", living in the range space of "map". |
12785 | * |
12786 | * Since binding is more easily implemented on the domain, |
12787 | * bind the input dimensions of the inverse of "map". |
12788 | */ |
12789 | __isl_give isl_set *isl_map_bind_range(__isl_take isl_map *map, |
12790 | __isl_take isl_multi_id *tuple) |
12791 | { |
12792 | return isl_map_bind_domain(map: isl_map_reverse(map), tuple); |
12793 | } |
12794 | |
12795 | /* Insert a domain corresponding to "tuple" |
12796 | * into the nullary or unary relation "set". |
12797 | * The result has an extra initial tuple and is therefore |
12798 | * either a unary or binary relation. |
12799 | * Any parameters with identifiers in "tuple" are reinterpreted |
12800 | * as the corresponding domain dimensions. |
12801 | */ |
12802 | static __isl_give isl_map *unbind_params_insert_domain( |
12803 | __isl_take isl_set *set, __isl_take isl_multi_id *tuple) |
12804 | { |
12805 | isl_space *space; |
12806 | isl_reordering *r; |
12807 | |
12808 | space = isl_set_peek_space(set); |
12809 | r = isl_reordering_unbind_params_insert_domain(space, tuple); |
12810 | isl_multi_id_free(multi: tuple); |
12811 | |
12812 | return isl_map_realign(map: set_to_map(set), r); |
12813 | } |
12814 | |
12815 | /* Construct a set with "tuple" as domain from the parameter domain "set". |
12816 | * Any parameters with identifiers in "tuple" are reinterpreted |
12817 | * as the corresponding set dimensions. |
12818 | */ |
12819 | __isl_give isl_set *isl_set_unbind_params(__isl_take isl_set *set, |
12820 | __isl_take isl_multi_id *tuple) |
12821 | { |
12822 | isl_bool is_params; |
12823 | |
12824 | is_params = isl_set_is_params(set); |
12825 | if (is_params < 0) |
12826 | set = isl_set_free(set); |
12827 | else if (!is_params) |
12828 | isl_die(isl_set_get_ctx(set), isl_error_invalid, |
12829 | "expecting parameter domain" , set = isl_set_free(set)); |
12830 | return set_from_map(unbind_params_insert_domain(set, tuple)); |
12831 | } |
12832 | |
12833 | /* Check that "set" is a proper set, i.e., that it is not a parameter domain. |
12834 | */ |
12835 | static isl_stat isl_set_check_is_set(__isl_keep isl_set *set) |
12836 | { |
12837 | isl_bool is_params; |
12838 | |
12839 | is_params = isl_set_is_params(set); |
12840 | if (is_params < 0) |
12841 | return isl_stat_error; |
12842 | else if (is_params) |
12843 | isl_die(isl_set_get_ctx(set), isl_error_invalid, |
12844 | "expecting proper set" , return isl_stat_error); |
12845 | |
12846 | return isl_stat_ok; |
12847 | } |
12848 | |
12849 | /* Construct a map with "domain" as domain and "set" as range. |
12850 | * Any parameters with identifiers in "domain" are reinterpreted |
12851 | * as the corresponding domain dimensions. |
12852 | */ |
12853 | __isl_give isl_map *isl_set_unbind_params_insert_domain( |
12854 | __isl_take isl_set *set, __isl_take isl_multi_id *domain) |
12855 | { |
12856 | if (isl_set_check_is_set(set) < 0) |
12857 | set = isl_set_free(set); |
12858 | return unbind_params_insert_domain(set, tuple: domain); |
12859 | } |
12860 | |
12861 | /* Construct a map with "domain" as domain and "set" as range. |
12862 | */ |
12863 | __isl_give isl_map *isl_set_insert_domain(__isl_take isl_set *set, |
12864 | __isl_take isl_space *domain) |
12865 | { |
12866 | isl_size dim; |
12867 | isl_space *space; |
12868 | isl_map *map; |
12869 | |
12870 | if (isl_set_check_is_set(set) < 0 || isl_space_check_is_set(space: domain) < 0) |
12871 | domain = isl_space_free(space: domain); |
12872 | dim = isl_space_dim(space: domain, type: isl_dim_set); |
12873 | if (dim < 0) |
12874 | domain = isl_space_free(space: domain); |
12875 | space = isl_set_get_space(set); |
12876 | domain = isl_space_replace_params(dst: domain, src: space); |
12877 | space = isl_space_map_from_domain_and_range(domain, range: space); |
12878 | |
12879 | map = isl_map_from_range(set); |
12880 | map = isl_map_add_dims(map, type: isl_dim_in, n: dim); |
12881 | map = isl_map_reset_space(map, space); |
12882 | |
12883 | return map; |
12884 | } |
12885 | |
12886 | __isl_give isl_mat *isl_basic_map_equalities_matrix( |
12887 | __isl_keep isl_basic_map *bmap, enum isl_dim_type c1, |
12888 | enum isl_dim_type c2, enum isl_dim_type c3, |
12889 | enum isl_dim_type c4, enum isl_dim_type c5) |
12890 | { |
12891 | enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 }; |
12892 | struct isl_mat *mat; |
12893 | int i, j, k; |
12894 | int pos; |
12895 | isl_size total; |
12896 | |
12897 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
12898 | if (total < 0) |
12899 | return NULL; |
12900 | mat = isl_mat_alloc(ctx: bmap->ctx, n_row: bmap->n_eq, n_col: total + 1); |
12901 | if (!mat) |
12902 | return NULL; |
12903 | for (i = 0; i < bmap->n_eq; ++i) |
12904 | for (j = 0, pos = 0; j < 5; ++j) { |
12905 | int off = isl_basic_map_offset(bmap, type: c[j]); |
12906 | isl_size dim = isl_basic_map_dim(bmap, type: c[j]); |
12907 | if (dim < 0) |
12908 | return isl_mat_free(mat); |
12909 | for (k = 0; k < dim; ++k) { |
12910 | isl_int_set(mat->row[i][pos], |
12911 | bmap->eq[i][off + k]); |
12912 | ++pos; |
12913 | } |
12914 | } |
12915 | |
12916 | return mat; |
12917 | } |
12918 | |
12919 | __isl_give isl_mat *isl_basic_map_inequalities_matrix( |
12920 | __isl_keep isl_basic_map *bmap, enum isl_dim_type c1, |
12921 | enum isl_dim_type c2, enum isl_dim_type c3, |
12922 | enum isl_dim_type c4, enum isl_dim_type c5) |
12923 | { |
12924 | enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 }; |
12925 | struct isl_mat *mat; |
12926 | int i, j, k; |
12927 | int pos; |
12928 | isl_size total; |
12929 | |
12930 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
12931 | if (total < 0) |
12932 | return NULL; |
12933 | mat = isl_mat_alloc(ctx: bmap->ctx, n_row: bmap->n_ineq, n_col: total + 1); |
12934 | if (!mat) |
12935 | return NULL; |
12936 | for (i = 0; i < bmap->n_ineq; ++i) |
12937 | for (j = 0, pos = 0; j < 5; ++j) { |
12938 | int off = isl_basic_map_offset(bmap, type: c[j]); |
12939 | isl_size dim = isl_basic_map_dim(bmap, type: c[j]); |
12940 | if (dim < 0) |
12941 | return isl_mat_free(mat); |
12942 | for (k = 0; k < dim; ++k) { |
12943 | isl_int_set(mat->row[i][pos], |
12944 | bmap->ineq[i][off + k]); |
12945 | ++pos; |
12946 | } |
12947 | } |
12948 | |
12949 | return mat; |
12950 | } |
12951 | |
12952 | __isl_give isl_basic_map *isl_basic_map_from_constraint_matrices( |
12953 | __isl_take isl_space *space, |
12954 | __isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1, |
12955 | enum isl_dim_type c2, enum isl_dim_type c3, |
12956 | enum isl_dim_type c4, enum isl_dim_type c5) |
12957 | { |
12958 | enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 }; |
12959 | isl_basic_map *bmap = NULL; |
12960 | isl_size dim; |
12961 | unsigned total; |
12962 | unsigned ; |
12963 | int i, j, k, l; |
12964 | int pos; |
12965 | |
12966 | dim = isl_space_dim(space, type: isl_dim_all); |
12967 | if (dim < 0 || !eq || !ineq) |
12968 | goto error; |
12969 | |
12970 | if (eq->n_col != ineq->n_col) |
12971 | isl_die(space->ctx, isl_error_invalid, |
12972 | "equalities and inequalities matrices should have " |
12973 | "same number of columns" , goto error); |
12974 | |
12975 | total = 1 + dim; |
12976 | |
12977 | if (eq->n_col < total) |
12978 | isl_die(space->ctx, isl_error_invalid, |
12979 | "number of columns too small" , goto error); |
12980 | |
12981 | extra = eq->n_col - total; |
12982 | |
12983 | bmap = isl_basic_map_alloc_space(space: isl_space_copy(space), extra, |
12984 | n_eq: eq->n_row, n_ineq: ineq->n_row); |
12985 | if (!bmap) |
12986 | goto error; |
12987 | for (i = 0; i < extra; ++i) { |
12988 | k = isl_basic_map_alloc_div(bmap); |
12989 | if (k < 0) |
12990 | goto error; |
12991 | isl_int_set_si(bmap->div[k][0], 0); |
12992 | } |
12993 | for (i = 0; i < eq->n_row; ++i) { |
12994 | l = isl_basic_map_alloc_equality(bmap); |
12995 | if (l < 0) |
12996 | goto error; |
12997 | for (j = 0, pos = 0; j < 5; ++j) { |
12998 | int off = isl_basic_map_offset(bmap, type: c[j]); |
12999 | isl_size dim = isl_basic_map_dim(bmap, type: c[j]); |
13000 | if (dim < 0) |
13001 | goto error; |
13002 | for (k = 0; k < dim; ++k) { |
13003 | isl_int_set(bmap->eq[l][off + k], |
13004 | eq->row[i][pos]); |
13005 | ++pos; |
13006 | } |
13007 | } |
13008 | } |
13009 | for (i = 0; i < ineq->n_row; ++i) { |
13010 | l = isl_basic_map_alloc_inequality(bmap); |
13011 | if (l < 0) |
13012 | goto error; |
13013 | for (j = 0, pos = 0; j < 5; ++j) { |
13014 | int off = isl_basic_map_offset(bmap, type: c[j]); |
13015 | isl_size dim = isl_basic_map_dim(bmap, type: c[j]); |
13016 | if (dim < 0) |
13017 | goto error; |
13018 | for (k = 0; k < dim; ++k) { |
13019 | isl_int_set(bmap->ineq[l][off + k], |
13020 | ineq->row[i][pos]); |
13021 | ++pos; |
13022 | } |
13023 | } |
13024 | } |
13025 | |
13026 | isl_space_free(space); |
13027 | isl_mat_free(mat: eq); |
13028 | isl_mat_free(mat: ineq); |
13029 | |
13030 | bmap = isl_basic_map_simplify(bmap); |
13031 | return isl_basic_map_finalize(bmap); |
13032 | error: |
13033 | isl_space_free(space); |
13034 | isl_mat_free(mat: eq); |
13035 | isl_mat_free(mat: ineq); |
13036 | isl_basic_map_free(bmap); |
13037 | return NULL; |
13038 | } |
13039 | |
13040 | __isl_give isl_mat *isl_basic_set_equalities_matrix( |
13041 | __isl_keep isl_basic_set *bset, enum isl_dim_type c1, |
13042 | enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4) |
13043 | { |
13044 | return isl_basic_map_equalities_matrix(bmap: bset_to_bmap(bset), |
13045 | c1, c2, c3, c4, c5: isl_dim_in); |
13046 | } |
13047 | |
13048 | __isl_give isl_mat *isl_basic_set_inequalities_matrix( |
13049 | __isl_keep isl_basic_set *bset, enum isl_dim_type c1, |
13050 | enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4) |
13051 | { |
13052 | return isl_basic_map_inequalities_matrix(bmap: bset_to_bmap(bset), |
13053 | c1, c2, c3, c4, c5: isl_dim_in); |
13054 | } |
13055 | |
13056 | __isl_give isl_basic_set *isl_basic_set_from_constraint_matrices( |
13057 | __isl_take isl_space *space, |
13058 | __isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1, |
13059 | enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4) |
13060 | { |
13061 | isl_basic_map *bmap; |
13062 | bmap = isl_basic_map_from_constraint_matrices(space, eq, ineq, |
13063 | c1, c2, c3, c4, c5: isl_dim_in); |
13064 | return bset_from_bmap(bmap); |
13065 | } |
13066 | |
13067 | isl_bool isl_basic_map_can_zip(__isl_keep isl_basic_map *bmap) |
13068 | { |
13069 | if (!bmap) |
13070 | return isl_bool_error; |
13071 | |
13072 | return isl_space_can_zip(space: bmap->dim); |
13073 | } |
13074 | |
13075 | isl_bool isl_map_can_zip(__isl_keep isl_map *map) |
13076 | { |
13077 | if (!map) |
13078 | return isl_bool_error; |
13079 | |
13080 | return isl_space_can_zip(space: map->dim); |
13081 | } |
13082 | |
13083 | /* Given a basic map (A -> B) -> (C -> D), return the corresponding basic map |
13084 | * (A -> C) -> (B -> D). |
13085 | */ |
13086 | __isl_give isl_basic_map *isl_basic_map_zip(__isl_take isl_basic_map *bmap) |
13087 | { |
13088 | unsigned pos; |
13089 | isl_size n_in; |
13090 | isl_size n1; |
13091 | isl_size n2; |
13092 | |
13093 | if (!bmap) |
13094 | return NULL; |
13095 | |
13096 | if (!isl_basic_map_can_zip(bmap)) |
13097 | isl_die(bmap->ctx, isl_error_invalid, |
13098 | "basic map cannot be zipped" , goto error); |
13099 | n_in = isl_space_dim(space: bmap->dim->nested[0], type: isl_dim_in); |
13100 | n1 = isl_space_dim(space: bmap->dim->nested[0], type: isl_dim_out); |
13101 | n2 = isl_space_dim(space: bmap->dim->nested[1], type: isl_dim_in); |
13102 | if (n_in < 0 || n1 < 0 || n2 < 0) |
13103 | return isl_basic_map_free(bmap); |
13104 | pos = isl_basic_map_offset(bmap, type: isl_dim_in) + n_in; |
13105 | bmap = isl_basic_map_cow(bmap); |
13106 | bmap = isl_basic_map_swap_vars(bmap, pos, n1, n2); |
13107 | if (!bmap) |
13108 | return NULL; |
13109 | bmap->dim = isl_space_zip(space: bmap->dim); |
13110 | if (!bmap->dim) |
13111 | goto error; |
13112 | bmap = isl_basic_map_mark_final(bmap); |
13113 | return bmap; |
13114 | error: |
13115 | isl_basic_map_free(bmap); |
13116 | return NULL; |
13117 | } |
13118 | |
13119 | /* Given a map (A -> B) -> (C -> D), return the corresponding map |
13120 | * (A -> C) -> (B -> D). |
13121 | */ |
13122 | __isl_give isl_map *isl_map_zip(__isl_take isl_map *map) |
13123 | { |
13124 | if (!map) |
13125 | return NULL; |
13126 | |
13127 | if (!isl_map_can_zip(map)) |
13128 | isl_die(map->ctx, isl_error_invalid, "map cannot be zipped" , |
13129 | goto error); |
13130 | |
13131 | return isl_map_transform(map, fn_space: &isl_space_zip, fn_bmap: &isl_basic_map_zip); |
13132 | error: |
13133 | isl_map_free(map); |
13134 | return NULL; |
13135 | } |
13136 | |
13137 | /* Can we apply isl_basic_map_curry to "bmap"? |
13138 | * That is, does it have a nested relation in its domain? |
13139 | */ |
13140 | isl_bool isl_basic_map_can_curry(__isl_keep isl_basic_map *bmap) |
13141 | { |
13142 | if (!bmap) |
13143 | return isl_bool_error; |
13144 | |
13145 | return isl_space_can_curry(space: bmap->dim); |
13146 | } |
13147 | |
13148 | /* Can we apply isl_map_curry to "map"? |
13149 | * That is, does it have a nested relation in its domain? |
13150 | */ |
13151 | isl_bool isl_map_can_curry(__isl_keep isl_map *map) |
13152 | { |
13153 | if (!map) |
13154 | return isl_bool_error; |
13155 | |
13156 | return isl_space_can_curry(space: map->dim); |
13157 | } |
13158 | |
13159 | /* Given a basic map (A -> B) -> C, return the corresponding basic map |
13160 | * A -> (B -> C). |
13161 | */ |
13162 | __isl_give isl_basic_map *isl_basic_map_curry(__isl_take isl_basic_map *bmap) |
13163 | { |
13164 | |
13165 | if (!bmap) |
13166 | return NULL; |
13167 | |
13168 | if (!isl_basic_map_can_curry(bmap)) |
13169 | isl_die(bmap->ctx, isl_error_invalid, |
13170 | "basic map cannot be curried" , goto error); |
13171 | bmap = isl_basic_map_cow(bmap); |
13172 | if (!bmap) |
13173 | return NULL; |
13174 | bmap->dim = isl_space_curry(space: bmap->dim); |
13175 | if (!bmap->dim) |
13176 | goto error; |
13177 | bmap = isl_basic_map_mark_final(bmap); |
13178 | return bmap; |
13179 | error: |
13180 | isl_basic_map_free(bmap); |
13181 | return NULL; |
13182 | } |
13183 | |
13184 | /* Given a map (A -> B) -> C, return the corresponding map |
13185 | * A -> (B -> C). |
13186 | */ |
13187 | __isl_give isl_map *isl_map_curry(__isl_take isl_map *map) |
13188 | { |
13189 | return isl_map_change_space(map, can_change: &isl_map_can_curry, |
13190 | cannot_change: "map cannot be curried" , change: &isl_space_curry); |
13191 | } |
13192 | |
13193 | /* Can isl_map_range_curry be applied to "map"? |
13194 | * That is, does it have a nested relation in its range, |
13195 | * the domain of which is itself a nested relation? |
13196 | */ |
13197 | isl_bool isl_map_can_range_curry(__isl_keep isl_map *map) |
13198 | { |
13199 | if (!map) |
13200 | return isl_bool_error; |
13201 | |
13202 | return isl_space_can_range_curry(space: map->dim); |
13203 | } |
13204 | |
13205 | /* Given a map A -> ((B -> C) -> D), return the corresponding map |
13206 | * A -> (B -> (C -> D)). |
13207 | */ |
13208 | __isl_give isl_map *isl_map_range_curry(__isl_take isl_map *map) |
13209 | { |
13210 | return isl_map_change_space(map, can_change: &isl_map_can_range_curry, |
13211 | cannot_change: "map range cannot be curried" , |
13212 | change: &isl_space_range_curry); |
13213 | } |
13214 | |
13215 | /* Can we apply isl_basic_map_uncurry to "bmap"? |
13216 | * That is, does it have a nested relation in its domain? |
13217 | */ |
13218 | isl_bool isl_basic_map_can_uncurry(__isl_keep isl_basic_map *bmap) |
13219 | { |
13220 | if (!bmap) |
13221 | return isl_bool_error; |
13222 | |
13223 | return isl_space_can_uncurry(space: bmap->dim); |
13224 | } |
13225 | |
13226 | /* Can we apply isl_map_uncurry to "map"? |
13227 | * That is, does it have a nested relation in its domain? |
13228 | */ |
13229 | isl_bool isl_map_can_uncurry(__isl_keep isl_map *map) |
13230 | { |
13231 | if (!map) |
13232 | return isl_bool_error; |
13233 | |
13234 | return isl_space_can_uncurry(space: map->dim); |
13235 | } |
13236 | |
13237 | /* Given a basic map A -> (B -> C), return the corresponding basic map |
13238 | * (A -> B) -> C. |
13239 | */ |
13240 | __isl_give isl_basic_map *isl_basic_map_uncurry(__isl_take isl_basic_map *bmap) |
13241 | { |
13242 | |
13243 | if (!bmap) |
13244 | return NULL; |
13245 | |
13246 | if (!isl_basic_map_can_uncurry(bmap)) |
13247 | isl_die(bmap->ctx, isl_error_invalid, |
13248 | "basic map cannot be uncurried" , |
13249 | return isl_basic_map_free(bmap)); |
13250 | bmap = isl_basic_map_cow(bmap); |
13251 | if (!bmap) |
13252 | return NULL; |
13253 | bmap->dim = isl_space_uncurry(space: bmap->dim); |
13254 | if (!bmap->dim) |
13255 | return isl_basic_map_free(bmap); |
13256 | bmap = isl_basic_map_mark_final(bmap); |
13257 | return bmap; |
13258 | } |
13259 | |
13260 | /* Given a map A -> (B -> C), return the corresponding map |
13261 | * (A -> B) -> C. |
13262 | */ |
13263 | __isl_give isl_map *isl_map_uncurry(__isl_take isl_map *map) |
13264 | { |
13265 | return isl_map_change_space(map, can_change: &isl_map_can_uncurry, |
13266 | cannot_change: "map cannot be uncurried" , change: &isl_space_uncurry); |
13267 | } |
13268 | |
13269 | __isl_give isl_set *isl_set_equate(__isl_take isl_set *set, |
13270 | enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) |
13271 | { |
13272 | return isl_map_equate(map: set, type1, pos1, type2, pos2); |
13273 | } |
13274 | |
13275 | /* Construct a basic map where the given dimensions are equal to each other. |
13276 | */ |
13277 | static __isl_give isl_basic_map *equator(__isl_take isl_space *space, |
13278 | enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) |
13279 | { |
13280 | isl_basic_map *bmap = NULL; |
13281 | int i; |
13282 | isl_size total; |
13283 | |
13284 | total = isl_space_dim(space, type: isl_dim_all); |
13285 | if (total < 0 || |
13286 | isl_space_check_range(space, type: type1, first: pos1, n: 1) < 0 || |
13287 | isl_space_check_range(space, type: type2, first: pos2, n: 1) < 0) |
13288 | goto error; |
13289 | |
13290 | if (type1 == type2 && pos1 == pos2) |
13291 | return isl_basic_map_universe(space); |
13292 | |
13293 | bmap = isl_basic_map_alloc_space(space: isl_space_copy(space), extra: 0, n_eq: 1, n_ineq: 0); |
13294 | i = isl_basic_map_alloc_equality(bmap); |
13295 | if (i < 0) |
13296 | goto error; |
13297 | isl_seq_clr(p: bmap->eq[i], len: 1 + total); |
13298 | pos1 += isl_basic_map_offset(bmap, type: type1); |
13299 | pos2 += isl_basic_map_offset(bmap, type: type2); |
13300 | isl_int_set_si(bmap->eq[i][pos1], -1); |
13301 | isl_int_set_si(bmap->eq[i][pos2], 1); |
13302 | bmap = isl_basic_map_finalize(bmap); |
13303 | isl_space_free(space); |
13304 | return bmap; |
13305 | error: |
13306 | isl_space_free(space); |
13307 | isl_basic_map_free(bmap); |
13308 | return NULL; |
13309 | } |
13310 | |
13311 | /* Add a constraint imposing that the given two dimensions are equal. |
13312 | */ |
13313 | __isl_give isl_basic_map *isl_basic_map_equate(__isl_take isl_basic_map *bmap, |
13314 | enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) |
13315 | { |
13316 | isl_basic_map *eq; |
13317 | |
13318 | eq = equator(space: isl_basic_map_get_space(bmap), type1, pos1, type2, pos2); |
13319 | |
13320 | bmap = isl_basic_map_intersect(bmap1: bmap, bmap2: eq); |
13321 | |
13322 | return bmap; |
13323 | } |
13324 | |
13325 | /* Add a constraint imposing that the given two dimensions are equal. |
13326 | */ |
13327 | __isl_give isl_map *isl_map_equate(__isl_take isl_map *map, |
13328 | enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) |
13329 | { |
13330 | isl_basic_map *bmap; |
13331 | |
13332 | bmap = equator(space: isl_map_get_space(map), type1, pos1, type2, pos2); |
13333 | |
13334 | map = isl_map_intersect(map1: map, map2: isl_map_from_basic_map(bmap)); |
13335 | |
13336 | return map; |
13337 | } |
13338 | |
13339 | /* Add a constraint imposing that the given two dimensions have opposite values. |
13340 | */ |
13341 | __isl_give isl_map *isl_map_oppose(__isl_take isl_map *map, |
13342 | enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) |
13343 | { |
13344 | isl_basic_map *bmap = NULL; |
13345 | int i; |
13346 | isl_size total; |
13347 | |
13348 | if (isl_map_check_range(obj: map, type: type1, first: pos1, n: 1) < 0) |
13349 | return isl_map_free(map); |
13350 | if (isl_map_check_range(obj: map, type: type2, first: pos2, n: 1) < 0) |
13351 | return isl_map_free(map); |
13352 | |
13353 | total = isl_map_dim(map, type: isl_dim_all); |
13354 | if (total < 0) |
13355 | return isl_map_free(map); |
13356 | bmap = isl_basic_map_alloc_space(space: isl_map_get_space(map), extra: 0, n_eq: 1, n_ineq: 0); |
13357 | i = isl_basic_map_alloc_equality(bmap); |
13358 | if (i < 0) |
13359 | goto error; |
13360 | isl_seq_clr(p: bmap->eq[i], len: 1 + total); |
13361 | pos1 += isl_basic_map_offset(bmap, type: type1); |
13362 | pos2 += isl_basic_map_offset(bmap, type: type2); |
13363 | isl_int_set_si(bmap->eq[i][pos1], 1); |
13364 | isl_int_set_si(bmap->eq[i][pos2], 1); |
13365 | bmap = isl_basic_map_finalize(bmap); |
13366 | |
13367 | map = isl_map_intersect(map1: map, map2: isl_map_from_basic_map(bmap)); |
13368 | |
13369 | return map; |
13370 | error: |
13371 | isl_basic_map_free(bmap); |
13372 | isl_map_free(map); |
13373 | return NULL; |
13374 | } |
13375 | |
13376 | /* Construct a constraint imposing that the value of the first dimension is |
13377 | * greater than or equal to that of the second. |
13378 | */ |
13379 | static __isl_give isl_constraint *constraint_order_ge( |
13380 | __isl_take isl_space *space, enum isl_dim_type type1, int pos1, |
13381 | enum isl_dim_type type2, int pos2) |
13382 | { |
13383 | isl_constraint *c; |
13384 | |
13385 | if (isl_space_check_range(space, type: type1, first: pos1, n: 1) < 0 || |
13386 | isl_space_check_range(space, type: type2, first: pos2, n: 1) < 0) |
13387 | space = isl_space_free(space); |
13388 | if (!space) |
13389 | return NULL; |
13390 | |
13391 | c = isl_constraint_alloc_inequality(ls: isl_local_space_from_space(space)); |
13392 | |
13393 | if (type1 == type2 && pos1 == pos2) |
13394 | return c; |
13395 | |
13396 | c = isl_constraint_set_coefficient_si(constraint: c, type: type1, pos: pos1, v: 1); |
13397 | c = isl_constraint_set_coefficient_si(constraint: c, type: type2, pos: pos2, v: -1); |
13398 | |
13399 | return c; |
13400 | } |
13401 | |
13402 | /* Add a constraint imposing that the value of the first dimension is |
13403 | * greater than or equal to that of the second. |
13404 | */ |
13405 | __isl_give isl_basic_map *isl_basic_map_order_ge(__isl_take isl_basic_map *bmap, |
13406 | enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) |
13407 | { |
13408 | isl_constraint *c; |
13409 | isl_space *space; |
13410 | |
13411 | if (type1 == type2 && pos1 == pos2) |
13412 | return bmap; |
13413 | space = isl_basic_map_get_space(bmap); |
13414 | c = constraint_order_ge(space, type1, pos1, type2, pos2); |
13415 | bmap = isl_basic_map_add_constraint(bmap, constraint: c); |
13416 | |
13417 | return bmap; |
13418 | } |
13419 | |
13420 | /* Add a constraint imposing that the value of the first dimension is |
13421 | * greater than or equal to that of the second. |
13422 | */ |
13423 | __isl_give isl_map *isl_map_order_ge(__isl_take isl_map *map, |
13424 | enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) |
13425 | { |
13426 | isl_constraint *c; |
13427 | isl_space *space; |
13428 | |
13429 | if (type1 == type2 && pos1 == pos2) |
13430 | return map; |
13431 | space = isl_map_get_space(map); |
13432 | c = constraint_order_ge(space, type1, pos1, type2, pos2); |
13433 | map = isl_map_add_constraint(map, constraint: c); |
13434 | |
13435 | return map; |
13436 | } |
13437 | |
13438 | /* Add a constraint imposing that the value of the first dimension is |
13439 | * less than or equal to that of the second. |
13440 | */ |
13441 | __isl_give isl_map *isl_map_order_le(__isl_take isl_map *map, |
13442 | enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) |
13443 | { |
13444 | return isl_map_order_ge(map, type1: type2, pos1: pos2, type2: type1, pos2: pos1); |
13445 | } |
13446 | |
13447 | /* Construct a basic map where the value of the first dimension is |
13448 | * greater than that of the second. |
13449 | */ |
13450 | static __isl_give isl_basic_map *greator(__isl_take isl_space *space, |
13451 | enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) |
13452 | { |
13453 | isl_basic_map *bmap = NULL; |
13454 | int i; |
13455 | isl_size total; |
13456 | |
13457 | if (isl_space_check_range(space, type: type1, first: pos1, n: 1) < 0 || |
13458 | isl_space_check_range(space, type: type2, first: pos2, n: 1) < 0) |
13459 | goto error; |
13460 | |
13461 | if (type1 == type2 && pos1 == pos2) |
13462 | return isl_basic_map_empty(space); |
13463 | |
13464 | bmap = isl_basic_map_alloc_space(space, extra: 0, n_eq: 0, n_ineq: 1); |
13465 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
13466 | i = isl_basic_map_alloc_inequality(bmap); |
13467 | if (total < 0 || i < 0) |
13468 | return isl_basic_map_free(bmap); |
13469 | isl_seq_clr(p: bmap->ineq[i], len: 1 + total); |
13470 | pos1 += isl_basic_map_offset(bmap, type: type1); |
13471 | pos2 += isl_basic_map_offset(bmap, type: type2); |
13472 | isl_int_set_si(bmap->ineq[i][pos1], 1); |
13473 | isl_int_set_si(bmap->ineq[i][pos2], -1); |
13474 | isl_int_set_si(bmap->ineq[i][0], -1); |
13475 | bmap = isl_basic_map_finalize(bmap); |
13476 | |
13477 | return bmap; |
13478 | error: |
13479 | isl_space_free(space); |
13480 | isl_basic_map_free(bmap); |
13481 | return NULL; |
13482 | } |
13483 | |
13484 | /* Add a constraint imposing that the value of the first dimension is |
13485 | * greater than that of the second. |
13486 | */ |
13487 | __isl_give isl_basic_map *isl_basic_map_order_gt(__isl_take isl_basic_map *bmap, |
13488 | enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) |
13489 | { |
13490 | isl_basic_map *gt; |
13491 | |
13492 | gt = greator(space: isl_basic_map_get_space(bmap), type1, pos1, type2, pos2); |
13493 | |
13494 | bmap = isl_basic_map_intersect(bmap1: bmap, bmap2: gt); |
13495 | |
13496 | return bmap; |
13497 | } |
13498 | |
13499 | /* Add a constraint imposing that the value of the first dimension is |
13500 | * greater than that of the second. |
13501 | */ |
13502 | __isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map, |
13503 | enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) |
13504 | { |
13505 | isl_basic_map *bmap; |
13506 | |
13507 | bmap = greator(space: isl_map_get_space(map), type1, pos1, type2, pos2); |
13508 | |
13509 | map = isl_map_intersect(map1: map, map2: isl_map_from_basic_map(bmap)); |
13510 | |
13511 | return map; |
13512 | } |
13513 | |
13514 | /* Add a constraint imposing that the value of the first dimension is |
13515 | * smaller than that of the second. |
13516 | */ |
13517 | __isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map, |
13518 | enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2) |
13519 | { |
13520 | return isl_map_order_gt(map, type1: type2, pos1: pos2, type2: type1, pos2: pos1); |
13521 | } |
13522 | |
13523 | __isl_give isl_aff *isl_basic_map_get_div(__isl_keep isl_basic_map *bmap, |
13524 | int pos) |
13525 | { |
13526 | isl_aff *div; |
13527 | isl_local_space *ls; |
13528 | |
13529 | if (!bmap) |
13530 | return NULL; |
13531 | |
13532 | if (!isl_basic_map_divs_known(bmap)) |
13533 | isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, |
13534 | "some divs are unknown" , return NULL); |
13535 | |
13536 | ls = isl_basic_map_get_local_space(bmap); |
13537 | div = isl_local_space_get_div(ls, pos); |
13538 | isl_local_space_free(ls); |
13539 | |
13540 | return div; |
13541 | } |
13542 | |
13543 | __isl_give isl_aff *isl_basic_set_get_div(__isl_keep isl_basic_set *bset, |
13544 | int pos) |
13545 | { |
13546 | return isl_basic_map_get_div(bmap: bset, pos); |
13547 | } |
13548 | |
13549 | /* Plug in "subs" for set dimension "pos" of "set". |
13550 | */ |
13551 | __isl_give isl_set *isl_set_substitute(__isl_take isl_set *set, |
13552 | unsigned pos, __isl_keep isl_aff *subs) |
13553 | { |
13554 | isl_multi_aff *ma; |
13555 | |
13556 | if (set && isl_set_plain_is_empty(set)) |
13557 | return set; |
13558 | |
13559 | ma = isl_multi_aff_identity_on_domain_space(space: isl_set_get_space(set)); |
13560 | ma = isl_multi_aff_set_aff(multi: ma, pos, el: isl_aff_copy(aff: subs)); |
13561 | return isl_set_preimage_multi_aff(set, ma); |
13562 | } |
13563 | |
13564 | /* Check if the range of "ma" is compatible with the domain or range |
13565 | * (depending on "type") of "bmap". |
13566 | */ |
13567 | static isl_stat check_basic_map_compatible_range_multi_aff( |
13568 | __isl_keep isl_basic_map *bmap, enum isl_dim_type type, |
13569 | __isl_keep isl_multi_aff *ma) |
13570 | { |
13571 | isl_bool m; |
13572 | isl_space *ma_space; |
13573 | |
13574 | ma_space = isl_multi_aff_get_space(multi: ma); |
13575 | |
13576 | m = isl_space_has_equal_params(space1: bmap->dim, space2: ma_space); |
13577 | if (m < 0) |
13578 | goto error; |
13579 | if (!m) |
13580 | isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, |
13581 | "parameters don't match" , goto error); |
13582 | m = isl_space_tuple_is_equal(space1: bmap->dim, type1: type, space2: ma_space, type2: isl_dim_out); |
13583 | if (m < 0) |
13584 | goto error; |
13585 | if (!m) |
13586 | isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, |
13587 | "spaces don't match" , goto error); |
13588 | |
13589 | isl_space_free(space: ma_space); |
13590 | return isl_stat_ok; |
13591 | error: |
13592 | isl_space_free(space: ma_space); |
13593 | return isl_stat_error; |
13594 | } |
13595 | |
13596 | /* Copy the divs from "ma" to "bmap", adding zeros for the "n_before" |
13597 | * coefficients before the transformed range of dimensions, |
13598 | * the "n_after" coefficients after the transformed range of dimensions |
13599 | * and the coefficients of the other divs in "bmap". |
13600 | */ |
13601 | static __isl_give isl_basic_map *set_ma_divs(__isl_take isl_basic_map *bmap, |
13602 | __isl_keep isl_multi_aff *ma, int n_before, int n_after, int n_div) |
13603 | { |
13604 | int i; |
13605 | isl_size n_param; |
13606 | isl_size n_set; |
13607 | isl_local_space *ls; |
13608 | |
13609 | if (n_div == 0) |
13610 | return bmap; |
13611 | |
13612 | ls = isl_aff_get_domain_local_space(aff: ma->u.p[0]); |
13613 | n_param = isl_local_space_dim(ls, type: isl_dim_param); |
13614 | n_set = isl_local_space_dim(ls, type: isl_dim_set); |
13615 | if (n_param < 0 || n_set < 0) |
13616 | return isl_basic_map_free(bmap); |
13617 | |
13618 | for (i = 0; i < n_div; ++i) { |
13619 | int o_bmap = 0, o_ls = 0; |
13620 | |
13621 | isl_seq_cpy(dst: bmap->div[i], src: ls->div->row[i], len: 1 + 1 + n_param); |
13622 | o_bmap += 1 + 1 + n_param; |
13623 | o_ls += 1 + 1 + n_param; |
13624 | isl_seq_clr(p: bmap->div[i] + o_bmap, len: n_before); |
13625 | o_bmap += n_before; |
13626 | isl_seq_cpy(dst: bmap->div[i] + o_bmap, |
13627 | src: ls->div->row[i] + o_ls, len: n_set); |
13628 | o_bmap += n_set; |
13629 | o_ls += n_set; |
13630 | isl_seq_clr(p: bmap->div[i] + o_bmap, len: n_after); |
13631 | o_bmap += n_after; |
13632 | isl_seq_cpy(dst: bmap->div[i] + o_bmap, |
13633 | src: ls->div->row[i] + o_ls, len: n_div); |
13634 | o_bmap += n_div; |
13635 | o_ls += n_div; |
13636 | isl_seq_clr(p: bmap->div[i] + o_bmap, len: bmap->n_div - n_div); |
13637 | bmap = isl_basic_map_add_div_constraints(bmap, pos: i); |
13638 | if (!bmap) |
13639 | goto error; |
13640 | } |
13641 | |
13642 | isl_local_space_free(ls); |
13643 | return bmap; |
13644 | error: |
13645 | isl_local_space_free(ls); |
13646 | return isl_basic_map_free(bmap); |
13647 | } |
13648 | |
13649 | /* How many stride constraints does "ma" enforce? |
13650 | * That is, how many of the affine expressions have a denominator |
13651 | * different from one? |
13652 | */ |
13653 | static int multi_aff_strides(__isl_keep isl_multi_aff *ma) |
13654 | { |
13655 | int i; |
13656 | int strides = 0; |
13657 | |
13658 | for (i = 0; i < ma->n; ++i) |
13659 | if (!isl_int_is_one(ma->u.p[i]->v->el[0])) |
13660 | strides++; |
13661 | |
13662 | return strides; |
13663 | } |
13664 | |
13665 | /* For each affine expression in ma of the form |
13666 | * |
13667 | * x_i = (f_i y + h_i)/m_i |
13668 | * |
13669 | * with m_i different from one, add a constraint to "bmap" |
13670 | * of the form |
13671 | * |
13672 | * f_i y + h_i = m_i alpha_i |
13673 | * |
13674 | * with alpha_i an additional existentially quantified variable. |
13675 | * |
13676 | * The input variables of "ma" correspond to a subset of the variables |
13677 | * of "bmap". There are "n_before" variables in "bmap" before this |
13678 | * subset and "n_after" variables after this subset. |
13679 | * The integer divisions of the affine expressions in "ma" are assumed |
13680 | * to have been aligned. There are "n_div_ma" of them and |
13681 | * they appear first in "bmap", straight after the "n_after" variables. |
13682 | */ |
13683 | static __isl_give isl_basic_map *add_ma_strides( |
13684 | __isl_take isl_basic_map *bmap, __isl_keep isl_multi_aff *ma, |
13685 | int n_before, int n_after, int n_div_ma) |
13686 | { |
13687 | int i, k; |
13688 | int div; |
13689 | isl_size total; |
13690 | isl_size n_param; |
13691 | isl_size n_in; |
13692 | |
13693 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
13694 | n_param = isl_multi_aff_dim(multi: ma, type: isl_dim_param); |
13695 | n_in = isl_multi_aff_dim(multi: ma, type: isl_dim_in); |
13696 | if (total < 0 || n_param < 0 || n_in < 0) |
13697 | return isl_basic_map_free(bmap); |
13698 | for (i = 0; i < ma->n; ++i) { |
13699 | int o_bmap = 0, o_ma = 1; |
13700 | |
13701 | if (isl_int_is_one(ma->u.p[i]->v->el[0])) |
13702 | continue; |
13703 | div = isl_basic_map_alloc_div(bmap); |
13704 | k = isl_basic_map_alloc_equality(bmap); |
13705 | if (div < 0 || k < 0) |
13706 | goto error; |
13707 | isl_int_set_si(bmap->div[div][0], 0); |
13708 | isl_seq_cpy(dst: bmap->eq[k] + o_bmap, |
13709 | src: ma->u.p[i]->v->el + o_ma, len: 1 + n_param); |
13710 | o_bmap += 1 + n_param; |
13711 | o_ma += 1 + n_param; |
13712 | isl_seq_clr(p: bmap->eq[k] + o_bmap, len: n_before); |
13713 | o_bmap += n_before; |
13714 | isl_seq_cpy(dst: bmap->eq[k] + o_bmap, |
13715 | src: ma->u.p[i]->v->el + o_ma, len: n_in); |
13716 | o_bmap += n_in; |
13717 | o_ma += n_in; |
13718 | isl_seq_clr(p: bmap->eq[k] + o_bmap, len: n_after); |
13719 | o_bmap += n_after; |
13720 | isl_seq_cpy(dst: bmap->eq[k] + o_bmap, |
13721 | src: ma->u.p[i]->v->el + o_ma, len: n_div_ma); |
13722 | o_bmap += n_div_ma; |
13723 | o_ma += n_div_ma; |
13724 | isl_seq_clr(p: bmap->eq[k] + o_bmap, len: 1 + total - o_bmap); |
13725 | isl_int_neg(bmap->eq[k][1 + total], ma->u.p[i]->v->el[0]); |
13726 | total++; |
13727 | } |
13728 | |
13729 | return bmap; |
13730 | error: |
13731 | isl_basic_map_free(bmap); |
13732 | return NULL; |
13733 | } |
13734 | |
13735 | /* Replace the domain or range space (depending on "type) of "space" by "set". |
13736 | */ |
13737 | static __isl_give isl_space *isl_space_set(__isl_take isl_space *space, |
13738 | enum isl_dim_type type, __isl_take isl_space *set) |
13739 | { |
13740 | if (type == isl_dim_in) { |
13741 | space = isl_space_range(space); |
13742 | space = isl_space_map_from_domain_and_range(domain: set, range: space); |
13743 | } else { |
13744 | space = isl_space_domain(space); |
13745 | space = isl_space_map_from_domain_and_range(domain: space, range: set); |
13746 | } |
13747 | |
13748 | return space; |
13749 | } |
13750 | |
13751 | /* Compute the preimage of the domain or range (depending on "type") |
13752 | * of "bmap" under the function represented by "ma". |
13753 | * In other words, plug in "ma" in the domain or range of "bmap". |
13754 | * The result is a basic map that lives in the same space as "bmap" |
13755 | * except that the domain or range has been replaced by |
13756 | * the domain space of "ma". |
13757 | * |
13758 | * If bmap is represented by |
13759 | * |
13760 | * A(p) + S u + B x + T v + C(divs) >= 0, |
13761 | * |
13762 | * where u and x are input and output dimensions if type == isl_dim_out |
13763 | * while x and v are input and output dimensions if type == isl_dim_in, |
13764 | * and ma is represented by |
13765 | * |
13766 | * x = D(p) + F(y) + G(divs') |
13767 | * |
13768 | * then the result is |
13769 | * |
13770 | * A(p) + B D(p) + S u + B F(y) + T v + B G(divs') + C(divs) >= 0 |
13771 | * |
13772 | * The divs in the input set are similarly adjusted. |
13773 | * In particular |
13774 | * |
13775 | * floor((a_i(p) + s u + b_i x + t v + c_i(divs))/n_i) |
13776 | * |
13777 | * becomes |
13778 | * |
13779 | * floor((a_i(p) + b_i D(p) + s u + b_i F(y) + t v + |
13780 | * B_i G(divs') + c_i(divs))/n_i) |
13781 | * |
13782 | * If bmap is not a rational map and if F(y) involves any denominators |
13783 | * |
13784 | * x_i = (f_i y + h_i)/m_i |
13785 | * |
13786 | * then additional constraints are added to ensure that we only |
13787 | * map back integer points. That is we enforce |
13788 | * |
13789 | * f_i y + h_i = m_i alpha_i |
13790 | * |
13791 | * with alpha_i an additional existentially quantified variable. |
13792 | * |
13793 | * We first copy over the divs from "ma". |
13794 | * Then we add the modified constraints and divs from "bmap". |
13795 | * Finally, we add the stride constraints, if needed. |
13796 | */ |
13797 | __isl_give isl_basic_map *isl_basic_map_preimage_multi_aff( |
13798 | __isl_take isl_basic_map *bmap, enum isl_dim_type type, |
13799 | __isl_take isl_multi_aff *ma) |
13800 | { |
13801 | int i, k; |
13802 | isl_space *space; |
13803 | isl_basic_map *res = NULL; |
13804 | isl_size n_before, n_after, n_div_bmap, n_div_ma; |
13805 | isl_int f, c1, c2, g; |
13806 | isl_bool rational; |
13807 | int strides; |
13808 | |
13809 | isl_int_init(f); |
13810 | isl_int_init(c1); |
13811 | isl_int_init(c2); |
13812 | isl_int_init(g); |
13813 | |
13814 | ma = isl_multi_aff_align_divs(maff: ma); |
13815 | if (!bmap || !ma) |
13816 | goto error; |
13817 | if (check_basic_map_compatible_range_multi_aff(bmap, type, ma) < 0) |
13818 | goto error; |
13819 | |
13820 | if (type == isl_dim_in) { |
13821 | n_before = 0; |
13822 | n_after = isl_basic_map_dim(bmap, type: isl_dim_out); |
13823 | } else { |
13824 | n_before = isl_basic_map_dim(bmap, type: isl_dim_in); |
13825 | n_after = 0; |
13826 | } |
13827 | n_div_bmap = isl_basic_map_dim(bmap, type: isl_dim_div); |
13828 | n_div_ma = ma->n ? isl_aff_dim(aff: ma->u.p[0], type: isl_dim_div) : 0; |
13829 | if (n_before < 0 || n_after < 0 || n_div_bmap < 0 || n_div_ma < 0) |
13830 | goto error; |
13831 | |
13832 | space = isl_multi_aff_get_domain_space(multi: ma); |
13833 | space = isl_space_set(space: isl_basic_map_get_space(bmap), type, set: space); |
13834 | rational = isl_basic_map_is_rational(bmap); |
13835 | strides = rational ? 0 : multi_aff_strides(ma); |
13836 | res = isl_basic_map_alloc_space(space, extra: n_div_ma + n_div_bmap + strides, |
13837 | n_eq: bmap->n_eq + strides, n_ineq: bmap->n_ineq + 2 * n_div_ma); |
13838 | if (rational) |
13839 | res = isl_basic_map_set_rational(bmap: res); |
13840 | |
13841 | for (i = 0; i < n_div_ma + n_div_bmap; ++i) |
13842 | if (isl_basic_map_alloc_div(bmap: res) < 0) |
13843 | goto error; |
13844 | |
13845 | res = set_ma_divs(bmap: res, ma, n_before, n_after, n_div: n_div_ma); |
13846 | if (!res) |
13847 | goto error; |
13848 | |
13849 | for (i = 0; i < bmap->n_eq; ++i) { |
13850 | k = isl_basic_map_alloc_equality(bmap: res); |
13851 | if (k < 0) |
13852 | goto error; |
13853 | if (isl_seq_preimage(dst: res->eq[k], src: bmap->eq[i], ma, n_before, |
13854 | n_after, n_div_ma, n_div_bmap, |
13855 | f, c1, c2, g, has_denom: 0) < 0) |
13856 | goto error; |
13857 | } |
13858 | |
13859 | for (i = 0; i < bmap->n_ineq; ++i) { |
13860 | k = isl_basic_map_alloc_inequality(bmap: res); |
13861 | if (k < 0) |
13862 | goto error; |
13863 | if (isl_seq_preimage(dst: res->ineq[k], src: bmap->ineq[i], ma, n_before, |
13864 | n_after, n_div_ma, n_div_bmap, |
13865 | f, c1, c2, g, has_denom: 0) < 0) |
13866 | goto error; |
13867 | } |
13868 | |
13869 | for (i = 0; i < bmap->n_div; ++i) { |
13870 | if (isl_int_is_zero(bmap->div[i][0])) { |
13871 | isl_int_set_si(res->div[n_div_ma + i][0], 0); |
13872 | continue; |
13873 | } |
13874 | if (isl_seq_preimage(dst: res->div[n_div_ma + i], src: bmap->div[i], ma, |
13875 | n_before, n_after, n_div_ma, n_div_bmap, |
13876 | f, c1, c2, g, has_denom: 1) < 0) |
13877 | goto error; |
13878 | } |
13879 | |
13880 | if (strides) |
13881 | res = add_ma_strides(bmap: res, ma, n_before, n_after, n_div_ma); |
13882 | |
13883 | isl_int_clear(f); |
13884 | isl_int_clear(c1); |
13885 | isl_int_clear(c2); |
13886 | isl_int_clear(g); |
13887 | isl_basic_map_free(bmap); |
13888 | isl_multi_aff_free(multi: ma); |
13889 | res = isl_basic_map_simplify(bmap: res); |
13890 | return isl_basic_map_finalize(bmap: res); |
13891 | error: |
13892 | isl_int_clear(f); |
13893 | isl_int_clear(c1); |
13894 | isl_int_clear(c2); |
13895 | isl_int_clear(g); |
13896 | isl_basic_map_free(bmap); |
13897 | isl_multi_aff_free(multi: ma); |
13898 | isl_basic_map_free(bmap: res); |
13899 | return NULL; |
13900 | } |
13901 | |
13902 | /* Compute the preimage of "bset" under the function represented by "ma". |
13903 | * In other words, plug in "ma" in "bset". The result is a basic set |
13904 | * that lives in the domain space of "ma". |
13905 | */ |
13906 | __isl_give isl_basic_set *isl_basic_set_preimage_multi_aff( |
13907 | __isl_take isl_basic_set *bset, __isl_take isl_multi_aff *ma) |
13908 | { |
13909 | return isl_basic_map_preimage_multi_aff(bmap: bset, type: isl_dim_set, ma); |
13910 | } |
13911 | |
13912 | /* Compute the preimage of the domain of "bmap" under the function |
13913 | * represented by "ma". |
13914 | * In other words, plug in "ma" in the domain of "bmap". |
13915 | * The result is a basic map that lives in the same space as "bmap" |
13916 | * except that the domain has been replaced by the domain space of "ma". |
13917 | */ |
13918 | __isl_give isl_basic_map *isl_basic_map_preimage_domain_multi_aff( |
13919 | __isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma) |
13920 | { |
13921 | return isl_basic_map_preimage_multi_aff(bmap, type: isl_dim_in, ma); |
13922 | } |
13923 | |
13924 | /* Compute the preimage of the range of "bmap" under the function |
13925 | * represented by "ma". |
13926 | * In other words, plug in "ma" in the range of "bmap". |
13927 | * The result is a basic map that lives in the same space as "bmap" |
13928 | * except that the range has been replaced by the domain space of "ma". |
13929 | */ |
13930 | __isl_give isl_basic_map *isl_basic_map_preimage_range_multi_aff( |
13931 | __isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma) |
13932 | { |
13933 | return isl_basic_map_preimage_multi_aff(bmap, type: isl_dim_out, ma); |
13934 | } |
13935 | |
13936 | /* Check if the range of "ma" is compatible with the domain or range |
13937 | * (depending on "type") of "map". |
13938 | * Return isl_stat_error if anything is wrong. |
13939 | */ |
13940 | static isl_stat check_map_compatible_range_multi_aff( |
13941 | __isl_keep isl_map *map, enum isl_dim_type type, |
13942 | __isl_keep isl_multi_aff *ma) |
13943 | { |
13944 | isl_bool m; |
13945 | isl_space *ma_space; |
13946 | |
13947 | ma_space = isl_multi_aff_get_space(multi: ma); |
13948 | m = isl_map_space_tuple_is_equal(map, type1: type, space: ma_space, type2: isl_dim_out); |
13949 | isl_space_free(space: ma_space); |
13950 | if (m < 0) |
13951 | return isl_stat_error; |
13952 | if (!m) |
13953 | isl_die(isl_map_get_ctx(map), isl_error_invalid, |
13954 | "spaces don't match" , return isl_stat_error); |
13955 | return isl_stat_ok; |
13956 | } |
13957 | |
13958 | /* Compute the preimage of the domain or range (depending on "type") |
13959 | * of "map" under the function represented by "ma". |
13960 | * In other words, plug in "ma" in the domain or range of "map". |
13961 | * The result is a map that lives in the same space as "map" |
13962 | * except that the domain or range has been replaced by |
13963 | * the domain space of "ma". |
13964 | * |
13965 | * The parameters are assumed to have been aligned. |
13966 | */ |
13967 | static __isl_give isl_map *map_preimage_multi_aff(__isl_take isl_map *map, |
13968 | enum isl_dim_type type, __isl_take isl_multi_aff *ma) |
13969 | { |
13970 | int i; |
13971 | isl_space *space; |
13972 | |
13973 | map = isl_map_cow(map); |
13974 | ma = isl_multi_aff_align_divs(maff: ma); |
13975 | if (!map || !ma) |
13976 | goto error; |
13977 | if (check_map_compatible_range_multi_aff(map, type, ma) < 0) |
13978 | goto error; |
13979 | |
13980 | for (i = 0; i < map->n; ++i) { |
13981 | map->p[i] = isl_basic_map_preimage_multi_aff(bmap: map->p[i], type, |
13982 | ma: isl_multi_aff_copy(multi: ma)); |
13983 | if (!map->p[i]) |
13984 | goto error; |
13985 | } |
13986 | |
13987 | space = isl_multi_aff_get_domain_space(multi: ma); |
13988 | space = isl_space_set(space: isl_map_get_space(map), type, set: space); |
13989 | |
13990 | isl_space_free(space: isl_map_take_space(map)); |
13991 | map = isl_map_restore_space(map, space); |
13992 | if (!map) |
13993 | goto error; |
13994 | |
13995 | isl_multi_aff_free(multi: ma); |
13996 | if (map->n > 1) |
13997 | ISL_F_CLR(map, ISL_MAP_DISJOINT); |
13998 | ISL_F_CLR(map, ISL_SET_NORMALIZED); |
13999 | return map; |
14000 | error: |
14001 | isl_multi_aff_free(multi: ma); |
14002 | isl_map_free(map); |
14003 | return NULL; |
14004 | } |
14005 | |
14006 | /* Compute the preimage of the domain or range (depending on "type") |
14007 | * of "map" under the function represented by "ma". |
14008 | * In other words, plug in "ma" in the domain or range of "map". |
14009 | * The result is a map that lives in the same space as "map" |
14010 | * except that the domain or range has been replaced by |
14011 | * the domain space of "ma". |
14012 | */ |
14013 | __isl_give isl_map *isl_map_preimage_multi_aff(__isl_take isl_map *map, |
14014 | enum isl_dim_type type, __isl_take isl_multi_aff *ma) |
14015 | { |
14016 | isl_bool aligned; |
14017 | |
14018 | if (!map || !ma) |
14019 | goto error; |
14020 | |
14021 | aligned = isl_map_space_has_equal_params(map, space: ma->space); |
14022 | if (aligned < 0) |
14023 | goto error; |
14024 | if (aligned) |
14025 | return map_preimage_multi_aff(map, type, ma); |
14026 | |
14027 | if (isl_map_check_named_params(obj: map) < 0) |
14028 | goto error; |
14029 | if (!isl_space_has_named_params(space: ma->space)) |
14030 | isl_die(map->ctx, isl_error_invalid, |
14031 | "unaligned unnamed parameters" , goto error); |
14032 | map = isl_map_align_params(map, model: isl_multi_aff_get_space(multi: ma)); |
14033 | ma = isl_multi_aff_align_params(multi: ma, model: isl_map_get_space(map)); |
14034 | |
14035 | return map_preimage_multi_aff(map, type, ma); |
14036 | error: |
14037 | isl_multi_aff_free(multi: ma); |
14038 | return isl_map_free(map); |
14039 | } |
14040 | |
14041 | /* Compute the preimage of "set" under the function represented by "ma". |
14042 | * In other words, plug in "ma" in "set". The result is a set |
14043 | * that lives in the domain space of "ma". |
14044 | */ |
14045 | __isl_give isl_set *isl_set_preimage_multi_aff(__isl_take isl_set *set, |
14046 | __isl_take isl_multi_aff *ma) |
14047 | { |
14048 | return isl_map_preimage_multi_aff(map: set, type: isl_dim_set, ma); |
14049 | } |
14050 | |
14051 | /* Compute the preimage of the domain of "map" under the function |
14052 | * represented by "ma". |
14053 | * In other words, plug in "ma" in the domain of "map". |
14054 | * The result is a map that lives in the same space as "map" |
14055 | * except that the domain has been replaced by the domain space of "ma". |
14056 | */ |
14057 | __isl_give isl_map *isl_map_preimage_domain_multi_aff(__isl_take isl_map *map, |
14058 | __isl_take isl_multi_aff *ma) |
14059 | { |
14060 | return isl_map_preimage_multi_aff(map, type: isl_dim_in, ma); |
14061 | } |
14062 | |
14063 | /* Compute the preimage of the range of "map" under the function |
14064 | * represented by "ma". |
14065 | * In other words, plug in "ma" in the range of "map". |
14066 | * The result is a map that lives in the same space as "map" |
14067 | * except that the range has been replaced by the domain space of "ma". |
14068 | */ |
14069 | __isl_give isl_map *isl_map_preimage_range_multi_aff(__isl_take isl_map *map, |
14070 | __isl_take isl_multi_aff *ma) |
14071 | { |
14072 | return isl_map_preimage_multi_aff(map, type: isl_dim_out, ma); |
14073 | } |
14074 | |
14075 | /* Compute the preimage of "map" under the function represented by "pma". |
14076 | * In other words, plug in "pma" in the domain or range of "map". |
14077 | * The result is a map that lives in the same space as "map", |
14078 | * except that the space of type "type" has been replaced by |
14079 | * the domain space of "pma". |
14080 | * |
14081 | * The parameters of "map" and "pma" are assumed to have been aligned. |
14082 | */ |
14083 | static __isl_give isl_map *isl_map_preimage_pw_multi_aff_aligned( |
14084 | __isl_take isl_map *map, enum isl_dim_type type, |
14085 | __isl_take isl_pw_multi_aff *pma) |
14086 | { |
14087 | int i; |
14088 | isl_map *res; |
14089 | |
14090 | if (!pma) |
14091 | goto error; |
14092 | |
14093 | if (pma->n == 0) { |
14094 | isl_pw_multi_aff_free(pma); |
14095 | res = isl_map_empty(space: isl_map_get_space(map)); |
14096 | isl_map_free(map); |
14097 | return res; |
14098 | } |
14099 | |
14100 | res = isl_map_preimage_multi_aff(map: isl_map_copy(map), type, |
14101 | ma: isl_multi_aff_copy(multi: pma->p[0].maff)); |
14102 | if (type == isl_dim_in) |
14103 | res = isl_map_intersect_domain(map: res, |
14104 | set: isl_map_copy(map: pma->p[0].set)); |
14105 | else |
14106 | res = isl_map_intersect_range(map: res, |
14107 | set: isl_map_copy(map: pma->p[0].set)); |
14108 | |
14109 | for (i = 1; i < pma->n; ++i) { |
14110 | isl_map *res_i; |
14111 | |
14112 | res_i = isl_map_preimage_multi_aff(map: isl_map_copy(map), type, |
14113 | ma: isl_multi_aff_copy(multi: pma->p[i].maff)); |
14114 | if (type == isl_dim_in) |
14115 | res_i = isl_map_intersect_domain(map: res_i, |
14116 | set: isl_map_copy(map: pma->p[i].set)); |
14117 | else |
14118 | res_i = isl_map_intersect_range(map: res_i, |
14119 | set: isl_map_copy(map: pma->p[i].set)); |
14120 | res = isl_map_union(map1: res, map2: res_i); |
14121 | } |
14122 | |
14123 | isl_pw_multi_aff_free(pma); |
14124 | isl_map_free(map); |
14125 | return res; |
14126 | error: |
14127 | isl_pw_multi_aff_free(pma); |
14128 | isl_map_free(map); |
14129 | return NULL; |
14130 | } |
14131 | |
14132 | /* Compute the preimage of "map" under the function represented by "pma". |
14133 | * In other words, plug in "pma" in the domain or range of "map". |
14134 | * The result is a map that lives in the same space as "map", |
14135 | * except that the space of type "type" has been replaced by |
14136 | * the domain space of "pma". |
14137 | */ |
14138 | __isl_give isl_map *isl_map_preimage_pw_multi_aff(__isl_take isl_map *map, |
14139 | enum isl_dim_type type, __isl_take isl_pw_multi_aff *pma) |
14140 | { |
14141 | isl_bool aligned; |
14142 | |
14143 | if (!map || !pma) |
14144 | goto error; |
14145 | |
14146 | aligned = isl_map_space_has_equal_params(map, space: pma->dim); |
14147 | if (aligned < 0) |
14148 | goto error; |
14149 | if (aligned) |
14150 | return isl_map_preimage_pw_multi_aff_aligned(map, type, pma); |
14151 | |
14152 | if (isl_map_check_named_params(obj: map) < 0) |
14153 | goto error; |
14154 | if (isl_pw_multi_aff_check_named_params(pma) < 0) |
14155 | goto error; |
14156 | map = isl_map_align_params(map, model: isl_pw_multi_aff_get_space(pma)); |
14157 | pma = isl_pw_multi_aff_align_params(pma, model: isl_map_get_space(map)); |
14158 | |
14159 | return isl_map_preimage_pw_multi_aff_aligned(map, type, pma); |
14160 | error: |
14161 | isl_pw_multi_aff_free(pma); |
14162 | return isl_map_free(map); |
14163 | } |
14164 | |
14165 | /* Compute the preimage of "set" under the function represented by "pma". |
14166 | * In other words, plug in "pma" in "set". The result is a set |
14167 | * that lives in the domain space of "pma". |
14168 | */ |
14169 | __isl_give isl_set *isl_set_preimage_pw_multi_aff(__isl_take isl_set *set, |
14170 | __isl_take isl_pw_multi_aff *pma) |
14171 | { |
14172 | return isl_map_preimage_pw_multi_aff(map: set, type: isl_dim_set, pma); |
14173 | } |
14174 | |
14175 | /* Compute the preimage of the domain of "map" under the function |
14176 | * represented by "pma". |
14177 | * In other words, plug in "pma" in the domain of "map". |
14178 | * The result is a map that lives in the same space as "map", |
14179 | * except that domain space has been replaced by the domain space of "pma". |
14180 | */ |
14181 | __isl_give isl_map *isl_map_preimage_domain_pw_multi_aff( |
14182 | __isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma) |
14183 | { |
14184 | return isl_map_preimage_pw_multi_aff(map, type: isl_dim_in, pma); |
14185 | } |
14186 | |
14187 | /* Compute the preimage of the range of "map" under the function |
14188 | * represented by "pma". |
14189 | * In other words, plug in "pma" in the range of "map". |
14190 | * The result is a map that lives in the same space as "map", |
14191 | * except that range space has been replaced by the domain space of "pma". |
14192 | */ |
14193 | __isl_give isl_map *isl_map_preimage_range_pw_multi_aff( |
14194 | __isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma) |
14195 | { |
14196 | return isl_map_preimage_pw_multi_aff(map, type: isl_dim_out, pma); |
14197 | } |
14198 | |
14199 | /* Compute the preimage of "map" under the function represented by "mpa". |
14200 | * In other words, plug in "mpa" in the domain or range of "map". |
14201 | * The result is a map that lives in the same space as "map", |
14202 | * except that the space of type "type" has been replaced by |
14203 | * the domain space of "mpa". |
14204 | * |
14205 | * If the map does not involve any constraints that refer to the |
14206 | * dimensions of the substituted space, then the only possible |
14207 | * effect of "mpa" on the map is to map the space to a different space. |
14208 | * We create a separate isl_multi_aff to effectuate this change |
14209 | * in order to avoid spurious splitting of the map along the pieces |
14210 | * of "mpa". |
14211 | * If "mpa" has a non-trivial explicit domain, however, |
14212 | * then the full substitution should be performed. |
14213 | */ |
14214 | __isl_give isl_map *isl_map_preimage_multi_pw_aff(__isl_take isl_map *map, |
14215 | enum isl_dim_type type, __isl_take isl_multi_pw_aff *mpa) |
14216 | { |
14217 | isl_size n; |
14218 | isl_bool full; |
14219 | isl_pw_multi_aff *pma; |
14220 | |
14221 | n = isl_map_dim(map, type); |
14222 | if (n < 0 || !mpa) |
14223 | goto error; |
14224 | |
14225 | full = isl_map_involves_dims(map, type, first: 0, n); |
14226 | if (full >= 0 && !full) |
14227 | full = isl_multi_pw_aff_has_non_trivial_domain(multi: mpa); |
14228 | if (full < 0) |
14229 | goto error; |
14230 | if (!full) { |
14231 | isl_space *space; |
14232 | isl_multi_aff *ma; |
14233 | |
14234 | space = isl_multi_pw_aff_get_space(multi: mpa); |
14235 | isl_multi_pw_aff_free(multi: mpa); |
14236 | ma = isl_multi_aff_zero(space); |
14237 | return isl_map_preimage_multi_aff(map, type, ma); |
14238 | } |
14239 | |
14240 | pma = isl_pw_multi_aff_from_multi_pw_aff(mpa); |
14241 | return isl_map_preimage_pw_multi_aff(map, type, pma); |
14242 | error: |
14243 | isl_map_free(map); |
14244 | isl_multi_pw_aff_free(multi: mpa); |
14245 | return NULL; |
14246 | } |
14247 | |
14248 | /* Compute the preimage of "map" under the function represented by "mpa". |
14249 | * In other words, plug in "mpa" in the domain "map". |
14250 | * The result is a map that lives in the same space as "map", |
14251 | * except that domain space has been replaced by the domain space of "mpa". |
14252 | */ |
14253 | __isl_give isl_map *isl_map_preimage_domain_multi_pw_aff( |
14254 | __isl_take isl_map *map, __isl_take isl_multi_pw_aff *mpa) |
14255 | { |
14256 | return isl_map_preimage_multi_pw_aff(map, type: isl_dim_in, mpa); |
14257 | } |
14258 | |
14259 | /* Compute the preimage of "set" by the function represented by "mpa". |
14260 | * In other words, plug in "mpa" in "set". |
14261 | */ |
14262 | __isl_give isl_set *isl_set_preimage_multi_pw_aff(__isl_take isl_set *set, |
14263 | __isl_take isl_multi_pw_aff *mpa) |
14264 | { |
14265 | return isl_map_preimage_multi_pw_aff(map: set, type: isl_dim_set, mpa); |
14266 | } |
14267 | |
14268 | /* Return a copy of the equality constraints of "bset" as a matrix. |
14269 | */ |
14270 | __isl_give isl_mat *( |
14271 | __isl_keep isl_basic_set *bset) |
14272 | { |
14273 | isl_ctx *ctx; |
14274 | isl_size total; |
14275 | |
14276 | total = isl_basic_set_dim(bset, type: isl_dim_all); |
14277 | if (total < 0) |
14278 | return NULL; |
14279 | |
14280 | ctx = isl_basic_set_get_ctx(bset); |
14281 | return isl_mat_sub_alloc6(ctx, row: bset->eq, first_row: 0, n_row: bset->n_eq, first_col: 0, n_col: 1 + total); |
14282 | } |
14283 | |
14284 | /* Are the "n" "coefficients" starting at "first" of the integer division |
14285 | * expressions at position "pos1" in "bmap1" and "pos2" in "bmap2" equal |
14286 | * to each other? |
14287 | * The "coefficient" at position 0 is the denominator. |
14288 | * The "coefficient" at position 1 is the constant term. |
14289 | */ |
14290 | isl_bool isl_basic_map_equal_div_expr_part(__isl_keep isl_basic_map *bmap1, |
14291 | int pos1, __isl_keep isl_basic_map *bmap2, int pos2, |
14292 | unsigned first, unsigned n) |
14293 | { |
14294 | if (isl_basic_map_check_range(obj: bmap1, type: isl_dim_div, first: pos1, n: 1) < 0) |
14295 | return isl_bool_error; |
14296 | if (isl_basic_map_check_range(obj: bmap2, type: isl_dim_div, first: pos2, n: 1) < 0) |
14297 | return isl_bool_error; |
14298 | return isl_seq_eq(p1: bmap1->div[pos1] + first, |
14299 | p2: bmap2->div[pos2] + first, len: n); |
14300 | } |
14301 | |
14302 | /* Are the integer division expressions at position "pos1" in "bmap1" and |
14303 | * "pos2" in "bmap2" equal to each other, except that the constant terms |
14304 | * are different? |
14305 | */ |
14306 | isl_bool isl_basic_map_equal_div_expr_except_constant( |
14307 | __isl_keep isl_basic_map *bmap1, int pos1, |
14308 | __isl_keep isl_basic_map *bmap2, int pos2) |
14309 | { |
14310 | isl_bool equal; |
14311 | isl_size total, total2; |
14312 | |
14313 | total = isl_basic_map_dim(bmap: bmap1, type: isl_dim_all); |
14314 | total2 = isl_basic_map_dim(bmap: bmap2, type: isl_dim_all); |
14315 | if (total < 0 || total2 < 0) |
14316 | return isl_bool_error; |
14317 | if (total != total2) |
14318 | isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid, |
14319 | "incomparable div expressions" , return isl_bool_error); |
14320 | equal = isl_basic_map_equal_div_expr_part(bmap1, pos1, bmap2, pos2, |
14321 | first: 0, n: 1); |
14322 | if (equal < 0 || !equal) |
14323 | return equal; |
14324 | equal = isl_basic_map_equal_div_expr_part(bmap1, pos1, bmap2, pos2, |
14325 | first: 1, n: 1); |
14326 | if (equal < 0 || equal) |
14327 | return isl_bool_not(b: equal); |
14328 | return isl_basic_map_equal_div_expr_part(bmap1, pos1, bmap2, pos2, |
14329 | first: 2, n: total); |
14330 | } |
14331 | |
14332 | /* Replace the numerator of the constant term of the integer division |
14333 | * expression at position "div" in "bmap" by "value". |
14334 | * The caller guarantees that this does not change the meaning |
14335 | * of the input. |
14336 | */ |
14337 | __isl_give isl_basic_map *isl_basic_map_set_div_expr_constant_num_si_inplace( |
14338 | __isl_take isl_basic_map *bmap, int div, int value) |
14339 | { |
14340 | if (isl_basic_map_check_range(obj: bmap, type: isl_dim_div, first: div, n: 1) < 0) |
14341 | return isl_basic_map_free(bmap); |
14342 | |
14343 | isl_int_set_si(bmap->div[div][1], value); |
14344 | |
14345 | return bmap; |
14346 | } |
14347 | |
14348 | /* Is the point "inner" internal to inequality constraint "ineq" |
14349 | * of "bset"? |
14350 | * The point is considered to be internal to the inequality constraint, |
14351 | * if it strictly lies on the positive side of the inequality constraint, |
14352 | * or if it lies on the constraint and the constraint is lexico-positive. |
14353 | */ |
14354 | static isl_bool is_internal(__isl_keep isl_vec *inner, |
14355 | __isl_keep isl_basic_set *bset, int ineq) |
14356 | { |
14357 | isl_ctx *ctx; |
14358 | int pos; |
14359 | isl_size total; |
14360 | |
14361 | if (!inner || !bset) |
14362 | return isl_bool_error; |
14363 | |
14364 | ctx = isl_basic_set_get_ctx(bset); |
14365 | isl_seq_inner_product(p1: inner->el, p2: bset->ineq[ineq], len: inner->size, |
14366 | prod: &ctx->normalize_gcd); |
14367 | if (!isl_int_is_zero(ctx->normalize_gcd)) |
14368 | return isl_int_is_nonneg(ctx->normalize_gcd); |
14369 | |
14370 | total = isl_basic_set_dim(bset, type: isl_dim_all); |
14371 | if (total < 0) |
14372 | return isl_bool_error; |
14373 | pos = isl_seq_first_non_zero(p: bset->ineq[ineq] + 1, len: total); |
14374 | return isl_int_is_pos(bset->ineq[ineq][1 + pos]); |
14375 | } |
14376 | |
14377 | /* Tighten the inequality constraints of "bset" that are outward with respect |
14378 | * to the point "vec". |
14379 | * That is, tighten the constraints that are not satisfied by "vec". |
14380 | * |
14381 | * "vec" is a point internal to some superset S of "bset" that is used |
14382 | * to make the subsets of S disjoint, by tightening one half of the constraints |
14383 | * that separate two subsets. In particular, the constraints of S |
14384 | * are all satisfied by "vec" and should not be tightened. |
14385 | * Of the internal constraints, those that have "vec" on the outside |
14386 | * are tightened. The shared facet is included in the adjacent subset |
14387 | * with the opposite constraint. |
14388 | * For constraints that saturate "vec", this criterion cannot be used |
14389 | * to determine which of the two sides should be tightened. |
14390 | * Instead, the sign of the first non-zero coefficient is used |
14391 | * to make this choice. Note that this second criterion is never used |
14392 | * on the constraints of S since "vec" is interior to "S". |
14393 | */ |
14394 | __isl_give isl_basic_set *isl_basic_set_tighten_outward( |
14395 | __isl_take isl_basic_set *bset, __isl_keep isl_vec *vec) |
14396 | { |
14397 | int j; |
14398 | |
14399 | bset = isl_basic_set_cow(bset); |
14400 | if (!bset) |
14401 | return NULL; |
14402 | for (j = 0; j < bset->n_ineq; ++j) { |
14403 | isl_bool internal; |
14404 | |
14405 | internal = is_internal(inner: vec, bset, ineq: j); |
14406 | if (internal < 0) |
14407 | return isl_basic_set_free(bset); |
14408 | if (internal) |
14409 | continue; |
14410 | isl_int_sub_ui(bset->ineq[j][0], bset->ineq[j][0], 1); |
14411 | } |
14412 | |
14413 | return bset; |
14414 | } |
14415 | |
14416 | /* Replace the variables x of type "type" starting at "first" in "bmap" |
14417 | * by x' with x = M x' with M the matrix trans. |
14418 | * That is, replace the corresponding coefficients c by c M. |
14419 | * |
14420 | * The transformation matrix should be a square matrix. |
14421 | */ |
14422 | __isl_give isl_basic_map *isl_basic_map_transform_dims( |
14423 | __isl_take isl_basic_map *bmap, enum isl_dim_type type, unsigned first, |
14424 | __isl_take isl_mat *trans) |
14425 | { |
14426 | unsigned pos; |
14427 | |
14428 | bmap = isl_basic_map_cow(bmap); |
14429 | if (!bmap || !trans) |
14430 | goto error; |
14431 | |
14432 | if (trans->n_row != trans->n_col) |
14433 | isl_die(trans->ctx, isl_error_invalid, |
14434 | "expecting square transformation matrix" , goto error); |
14435 | if (isl_basic_map_check_range(obj: bmap, type, first, n: trans->n_row) < 0) |
14436 | goto error; |
14437 | |
14438 | pos = isl_basic_map_offset(bmap, type) + first; |
14439 | |
14440 | if (isl_mat_sub_transform(row: bmap->eq, n_row: bmap->n_eq, first_col: pos, |
14441 | mat: isl_mat_copy(mat: trans)) < 0) |
14442 | goto error; |
14443 | if (isl_mat_sub_transform(row: bmap->ineq, n_row: bmap->n_ineq, first_col: pos, |
14444 | mat: isl_mat_copy(mat: trans)) < 0) |
14445 | goto error; |
14446 | if (isl_mat_sub_transform(row: bmap->div, n_row: bmap->n_div, first_col: 1 + pos, |
14447 | mat: isl_mat_copy(mat: trans)) < 0) |
14448 | goto error; |
14449 | |
14450 | ISL_F_CLR(bmap, ISL_BASIC_MAP_SORTED); |
14451 | ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS); |
14452 | |
14453 | isl_mat_free(mat: trans); |
14454 | return bmap; |
14455 | error: |
14456 | isl_mat_free(mat: trans); |
14457 | isl_basic_map_free(bmap); |
14458 | return NULL; |
14459 | } |
14460 | |
14461 | /* Replace the variables x of type "type" starting at "first" in "bset" |
14462 | * by x' with x = M x' with M the matrix trans. |
14463 | * That is, replace the corresponding coefficients c by c M. |
14464 | * |
14465 | * The transformation matrix should be a square matrix. |
14466 | */ |
14467 | __isl_give isl_basic_set *isl_basic_set_transform_dims( |
14468 | __isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned first, |
14469 | __isl_take isl_mat *trans) |
14470 | { |
14471 | return isl_basic_map_transform_dims(bmap: bset, type, first, trans); |
14472 | } |
14473 | |