isl_map_transitive_closure: extract out construction of extended path
[isl.git] / isl_transitive_closure.c
blobc55b979ad834503f811fab5d996d953091c513e7
1 /*
2 * Copyright 2010 INRIA Saclay
4 * Use of this software is governed by the GNU LGPLv2.1 license
6 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
7 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
8 * 91893 Orsay, France
9 */
11 #include "isl_map.h"
12 #include "isl_map_private.h"
13 #include "isl_seq.h"
16 * The transitive closure implementation is based on the paper
17 * "Computing the Transitive Closure of a Union of Affine Integer
18 * Tuple Relations" by Anna Beletska, Denis Barthou, Wlodzimierz Bielecki and
19 * Albert Cohen.
22 /* Given a set of n offsets v_i (the rows of "steps"), construct a relation
23 * of the given dimension specification (Z^{n+1} -> Z^{n+1})
24 * that maps an element x to any element that can be reached
25 * by taking a non-negative number of steps along any of
26 * the extended offsets v'_i = [v_i 1].
27 * That is, construct
29 * { [x] -> [y] : exists k_i >= 0, y = x + \sum_i k_i v'_i }
31 * For any element in this relation, the number of steps taken
32 * is equal to the difference in the final coordinates.
34 static __isl_give isl_map *path_along_steps(__isl_take isl_dim *dim,
35 __isl_keep isl_mat *steps)
37 int i, j, k;
38 struct isl_basic_map *path = NULL;
39 unsigned d;
40 unsigned n;
41 unsigned nparam;
43 if (!dim || !steps)
44 goto error;
46 d = isl_dim_size(dim, isl_dim_in);
47 n = steps->n_row;
48 nparam = isl_dim_size(dim, isl_dim_param);
50 path = isl_basic_map_alloc_dim(isl_dim_copy(dim), n, d, n);
52 for (i = 0; i < n; ++i) {
53 k = isl_basic_map_alloc_div(path);
54 if (k < 0)
55 goto error;
56 isl_assert(steps->ctx, i == k, goto error);
57 isl_int_set_si(path->div[k][0], 0);
60 for (i = 0; i < d; ++i) {
61 k = isl_basic_map_alloc_equality(path);
62 if (k < 0)
63 goto error;
64 isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path));
65 isl_int_set_si(path->eq[k][1 + nparam + i], 1);
66 isl_int_set_si(path->eq[k][1 + nparam + d + i], -1);
67 if (i == d - 1)
68 for (j = 0; j < n; ++j)
69 isl_int_set_si(path->eq[k][1 + nparam + 2 * d + j], 1);
70 else
71 for (j = 0; j < n; ++j)
72 isl_int_set(path->eq[k][1 + nparam + 2 * d + j],
73 steps->row[j][i]);
76 for (i = 0; i < n; ++i) {
77 k = isl_basic_map_alloc_inequality(path);
78 if (k < 0)
79 goto error;
80 isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path));
81 isl_int_set_si(path->ineq[k][1 + nparam + 2 * d + i], 1);
84 isl_dim_free(dim);
86 path = isl_basic_map_simplify(path);
87 path = isl_basic_map_finalize(path);
88 return isl_map_from_basic_map(path);
89 error:
90 isl_dim_free(dim);
91 isl_basic_map_free(path);
92 return NULL;
95 #define IMPURE 0
96 #define PURE_PARAM 1
97 #define PURE_VAR 2
99 /* Return PURE_PARAM if only the coefficients of the parameters are non-zero.
100 * Return PURE_VAR if only the coefficients of the set variables are non-zero.
101 * Return IMPURE otherwise.
103 static int purity(__isl_keep isl_basic_set *bset, isl_int *c)
105 unsigned d;
106 unsigned n_div;
107 unsigned nparam;
109 n_div = isl_basic_set_dim(bset, isl_dim_div);
110 d = isl_basic_set_dim(bset, isl_dim_set);
111 nparam = isl_basic_set_dim(bset, isl_dim_param);
113 if (isl_seq_first_non_zero(c + 1 + nparam + d, n_div) != -1)
114 return IMPURE;
115 if (isl_seq_first_non_zero(c + 1, nparam) == -1)
116 return PURE_VAR;
117 if (isl_seq_first_non_zero(c + 1 + nparam, d) == -1)
118 return PURE_PARAM;
119 return IMPURE;
122 /* Given a set of offsets "delta", construct a relation of the
123 * given dimension specification (Z^{n+1} -> Z^{n+1}) that
124 * is an overapproximation of the relations that
125 * maps an element x to any element that can be reached
126 * by taking a non-negative number of steps along any of
127 * the elements in "delta".
128 * That is, construct an approximation of
130 * { [x] -> [y] : exists f \in \delta, k \in Z :
131 * y = x + k [f, 1] and k >= 0 }
133 * For any element in this relation, the number of steps taken
134 * is equal to the difference in the final coordinates.
136 * In particular, let delta be defined as
138 * \delta = [p] -> { [x] : A x + a >= and B p + b >= 0 and
139 * C x + C'p + c >= 0 }
141 * then the relation is constructed as
143 * { [x] -> [y] : exists [f, k] \in Z^{n+1} : y = x + f and
144 * A f + k a >= 0 and B p + b >= 0 and k >= 1 }
145 * union { [x] -> [x] }
147 * Existentially quantified variables in \delta are currently ignored.
148 * This is safe, but leads to an additional overapproximation.
150 static __isl_give isl_map *path_along_delta(__isl_take isl_dim *dim,
151 __isl_take isl_basic_set *delta)
153 isl_basic_map *path = NULL;
154 unsigned d;
155 unsigned n_div;
156 unsigned nparam;
157 unsigned off;
158 int i, k;
160 if (!delta)
161 goto error;
162 n_div = isl_basic_set_dim(delta, isl_dim_div);
163 d = isl_basic_set_dim(delta, isl_dim_set);
164 nparam = isl_basic_set_dim(delta, isl_dim_param);
165 path = isl_basic_map_alloc_dim(isl_dim_copy(dim), n_div + d + 1,
166 d + 1 + delta->n_eq, delta->n_ineq + 1);
167 off = 1 + nparam + 2 * (d + 1) + n_div;
169 for (i = 0; i < n_div + d + 1; ++i) {
170 k = isl_basic_map_alloc_div(path);
171 if (k < 0)
172 goto error;
173 isl_int_set_si(path->div[k][0], 0);
176 for (i = 0; i < d + 1; ++i) {
177 k = isl_basic_map_alloc_equality(path);
178 if (k < 0)
179 goto error;
180 isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path));
181 isl_int_set_si(path->eq[k][1 + nparam + i], 1);
182 isl_int_set_si(path->eq[k][1 + nparam + d + 1 + i], -1);
183 isl_int_set_si(path->eq[k][off + i], 1);
186 for (i = 0; i < delta->n_eq; ++i) {
187 int p = purity(delta, delta->eq[i]);
188 if (p == IMPURE)
189 continue;
190 k = isl_basic_map_alloc_equality(path);
191 if (k < 0)
192 goto error;
193 isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path));
194 if (p == PURE_VAR) {
195 isl_seq_cpy(path->eq[k] + off,
196 delta->eq[i] + 1 + nparam, d);
197 isl_int_set(path->eq[k][off + d], delta->eq[i][0]);
198 } else
199 isl_seq_cpy(path->eq[k], delta->eq[i], 1 + nparam);
202 for (i = 0; i < delta->n_ineq; ++i) {
203 int p = purity(delta, delta->ineq[i]);
204 if (p == IMPURE)
205 continue;
206 k = isl_basic_map_alloc_inequality(path);
207 if (k < 0)
208 goto error;
209 isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path));
210 if (p == PURE_VAR) {
211 isl_seq_cpy(path->ineq[k] + off,
212 delta->ineq[i] + 1 + nparam, d);
213 isl_int_set(path->ineq[k][off + d], delta->ineq[i][0]);
214 } else
215 isl_seq_cpy(path->ineq[k], delta->ineq[i], 1 + nparam);
218 k = isl_basic_map_alloc_inequality(path);
219 if (k < 0)
220 goto error;
221 isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path));
222 isl_int_set_si(path->ineq[k][0], -1);
223 isl_int_set_si(path->ineq[k][off + d], 1);
225 isl_basic_set_free(delta);
226 path = isl_basic_map_finalize(path);
227 return isl_basic_map_union(path,
228 isl_basic_map_identity(isl_dim_domain(dim)));
229 error:
230 isl_dim_free(dim);
231 isl_basic_set_free(delta);
232 isl_basic_map_free(path);
233 return NULL;
236 /* Given a dimenion specification Z^{n+1} -> Z^{n+1} and a parameter "param",
237 * construct a map that equates the parameter to the difference
238 * in the final coordinates and imposes that this difference is positive.
239 * That is, construct
241 * { [x,x_s] -> [y,y_s] : k = y_s - x_s > 0 }
243 static __isl_give isl_map *equate_parameter_to_length(__isl_take isl_dim *dim,
244 unsigned param)
246 struct isl_basic_map *bmap;
247 unsigned d;
248 unsigned nparam;
249 int k;
251 d = isl_dim_size(dim, isl_dim_in);
252 nparam = isl_dim_size(dim, isl_dim_param);
253 bmap = isl_basic_map_alloc_dim(dim, 0, 1, 1);
254 k = isl_basic_map_alloc_equality(bmap);
255 if (k < 0)
256 goto error;
257 isl_seq_clr(bmap->eq[k], 1 + isl_basic_map_total_dim(bmap));
258 isl_int_set_si(bmap->eq[k][1 + param], -1);
259 isl_int_set_si(bmap->eq[k][1 + nparam + d - 1], -1);
260 isl_int_set_si(bmap->eq[k][1 + nparam + d + d - 1], 1);
262 k = isl_basic_map_alloc_inequality(bmap);
263 if (k < 0)
264 goto error;
265 isl_seq_clr(bmap->ineq[k], 1 + isl_basic_map_total_dim(bmap));
266 isl_int_set_si(bmap->ineq[k][1 + param], 1);
267 isl_int_set_si(bmap->ineq[k][0], -1);
269 bmap = isl_basic_map_finalize(bmap);
270 return isl_map_from_basic_map(bmap);
271 error:
272 isl_basic_map_free(bmap);
273 return NULL;
276 /* Check whether "path" is acyclic, where the last coordinates of domain
277 * and range of path encode the number of steps taken.
278 * That is, check whether
280 * { d | d = y - x and (x,y) in path }
282 * does not contain any element with positive last coordinate (positive length)
283 * and zero remaining coordinates (cycle).
285 static int is_acyclic(__isl_take isl_map *path)
287 int i;
288 int acyclic;
289 unsigned dim;
290 struct isl_set *delta;
292 delta = isl_map_deltas(path);
293 dim = isl_set_dim(delta, isl_dim_set);
294 for (i = 0; i < dim; ++i) {
295 if (i == dim -1)
296 delta = isl_set_lower_bound_si(delta, isl_dim_set, i, 1);
297 else
298 delta = isl_set_fix_si(delta, isl_dim_set, i, 0);
301 acyclic = isl_set_is_empty(delta);
302 isl_set_free(delta);
304 return acyclic;
307 /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D
308 * and a dimension specification (Z^{n+1} -> Z^{n+1}),
309 * construct a map that is an overapproximation of the map
310 * that takes an element from the space D \times Z to another
311 * element from the same space, such that the first n coordinates of the
312 * difference between them is a sum of differences between images
313 * and pre-images in one of the R_i and such that the last coordinate
314 * is equal to the number of steps taken.
315 * That is, let
317 * \Delta_i = { y - x | (x, y) in R_i }
319 * then the constructed map is an overapproximation of
321 * { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
322 * d = (\sum_i k_i \delta_i, \sum_i k_i) }
324 * The elements of the singleton \Delta_i's are collected as the
325 * rows of the steps matrix. For all these \Delta_i's together,
326 * a single path is constructed.
327 * For each of the other \Delta_i's, we compute an overapproximation
328 * of the paths along elements of \Delta_i.
329 * Since each of these paths performs an addition, composition is
330 * symmetric and we can simply compose all resulting paths in any order.
332 static __isl_give isl_map *construct_extended_path(__isl_take isl_dim *dim,
333 __isl_keep isl_map *map, int *project)
335 struct isl_mat *steps = NULL;
336 struct isl_map *path = NULL;
337 unsigned d;
338 int i, j, n;
340 d = isl_map_dim(map, isl_dim_in);
342 path = isl_map_identity(isl_dim_domain(isl_dim_copy(dim)));
344 steps = isl_mat_alloc(map->ctx, map->n, d);
345 if (!steps)
346 goto error;
348 n = 0;
349 for (i = 0; i < map->n; ++i) {
350 struct isl_basic_set *delta;
352 delta = isl_basic_map_deltas(isl_basic_map_copy(map->p[i]));
354 for (j = 0; j < d; ++j) {
355 int fixed;
357 fixed = isl_basic_set_fast_dim_is_fixed(delta, j,
358 &steps->row[n][j]);
359 if (fixed < 0) {
360 isl_basic_set_free(delta);
361 goto error;
363 if (!fixed)
364 break;
368 if (j < d) {
369 path = isl_map_apply_range(path,
370 path_along_delta(isl_dim_copy(dim), delta));
371 } else {
372 isl_basic_set_free(delta);
373 ++n;
377 if (n > 0) {
378 steps->n_row = n;
379 path = isl_map_apply_range(path,
380 path_along_steps(isl_dim_copy(dim), steps));
383 if (project && *project) {
384 *project = is_acyclic(isl_map_copy(path));
385 if (*project < 0)
386 goto error;
389 isl_dim_free(dim);
390 isl_mat_free(steps);
391 return path;
392 error:
393 isl_dim_free(dim);
394 isl_mat_free(steps);
395 isl_map_free(path);
396 return NULL;
399 /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D,
400 * construct a map that is an overapproximation of the map
401 * that takes an element from the space D to another
402 * element from the same space, such that the difference between
403 * them is a strictly positive sum of differences between images
404 * and pre-images in one of the R_i.
405 * The number of differences in the sum is equated to parameter "param".
406 * That is, let
408 * \Delta_i = { y - x | (x, y) in R_i }
410 * then the constructed map is an overapproximation of
412 * { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
413 * d = \sum_i k_i \delta_i and k = \sum_i k_i > 0 }
415 * We first construct an extended mapping with an extra coordinate
416 * that indicates the number of steps taken. In particular,
417 * the difference in the last coordinate is equal to the number
418 * of steps taken to move from a domain element to the corresponding
419 * image element(s).
420 * In the final step, this difference is equated to the parameter "param"
421 * and made positive. The extra coordinates are subsequently projected out.
423 static __isl_give isl_map *construct_path(__isl_keep isl_map *map,
424 unsigned param, int *project)
426 struct isl_map *path = NULL;
427 struct isl_map *diff;
428 struct isl_dim *dim = NULL;
429 unsigned d;
431 if (!map)
432 return NULL;
434 dim = isl_map_get_dim(map);
436 d = isl_dim_size(dim, isl_dim_in);
437 dim = isl_dim_add(dim, isl_dim_in, 1);
438 dim = isl_dim_add(dim, isl_dim_out, 1);
440 path = construct_extended_path(isl_dim_copy(dim), map, project);
442 diff = equate_parameter_to_length(dim, param);
443 path = isl_map_intersect(path, diff);
444 path = isl_map_project_out(path, isl_dim_in, d, 1);
445 path = isl_map_project_out(path, isl_dim_out, d, 1);
447 return path;
450 /* Shift variable at position "pos" up by one.
451 * That is, replace the corresponding variable v by v - 1.
453 static __isl_give isl_basic_map *basic_map_shift_pos(
454 __isl_take isl_basic_map *bmap, unsigned pos)
456 int i;
458 bmap = isl_basic_map_cow(bmap);
459 if (!bmap)
460 return NULL;
462 for (i = 0; i < bmap->n_eq; ++i)
463 isl_int_sub(bmap->eq[i][0], bmap->eq[i][0], bmap->eq[i][pos]);
465 for (i = 0; i < bmap->n_ineq; ++i)
466 isl_int_sub(bmap->ineq[i][0],
467 bmap->ineq[i][0], bmap->ineq[i][pos]);
469 for (i = 0; i < bmap->n_div; ++i) {
470 if (isl_int_is_zero(bmap->div[i][0]))
471 continue;
472 isl_int_sub(bmap->div[i][1],
473 bmap->div[i][1], bmap->div[i][1 + pos]);
476 return bmap;
479 /* Shift variable at position "pos" up by one.
480 * That is, replace the corresponding variable v by v - 1.
482 static __isl_give isl_map *map_shift_pos(__isl_take isl_map *map, unsigned pos)
484 int i;
486 map = isl_map_cow(map);
487 if (!map)
488 return NULL;
490 for (i = 0; i < map->n; ++i) {
491 map->p[i] = basic_map_shift_pos(map->p[i], pos);
492 if (!map->p[i])
493 goto error;
495 ISL_F_CLR(map, ISL_MAP_NORMALIZED);
496 return map;
497 error:
498 isl_map_free(map);
499 return NULL;
502 /* Check whether the overapproximation of the power of "map" is exactly
503 * the power of "map". Let R be "map" and A_k the overapproximation.
504 * The approximation is exact if
506 * A_1 = R
507 * A_k = A_{k-1} \circ R k >= 2
509 * Since A_k is known to be an overapproximation, we only need to check
511 * A_1 \subset R
512 * A_k \subset A_{k-1} \circ R k >= 2
515 static int check_power_exactness(__isl_take isl_map *map,
516 __isl_take isl_map *app, unsigned param)
518 int exact;
519 isl_map *app_1;
520 isl_map *app_2;
522 app_1 = isl_map_fix_si(isl_map_copy(app), isl_dim_param, param, 1);
524 exact = isl_map_is_subset(app_1, map);
525 isl_map_free(app_1);
527 if (!exact || exact < 0) {
528 isl_map_free(app);
529 isl_map_free(map);
530 return exact;
533 app_2 = isl_map_lower_bound_si(isl_map_copy(app),
534 isl_dim_param, param, 2);
535 app_1 = map_shift_pos(app, 1 + param);
536 app_1 = isl_map_apply_range(map, app_1);
538 exact = isl_map_is_subset(app_2, app_1);
540 isl_map_free(app_1);
541 isl_map_free(app_2);
543 return exact;
546 /* Check whether the overapproximation of the power of "map" is exactly
547 * the power of "map", possibly after projecting out the power (if "project"
548 * is set).
550 * If "project" is set and if "steps" can only result in acyclic paths,
551 * then we check
553 * A = R \cup (A \circ R)
555 * where A is the overapproximation with the power projected out, i.e.,
556 * an overapproximation of the transitive closure.
557 * More specifically, since A is known to be an overapproximation, we check
559 * A \subset R \cup (A \circ R)
561 * Otherwise, we check if the power is exact.
563 static int check_exactness(__isl_take isl_map *map, __isl_take isl_map *app,
564 unsigned param, int project)
566 isl_map *test;
567 int exact;
569 if (!project)
570 return check_power_exactness(map, app, param);
572 map = isl_map_project_out(map, isl_dim_param, param, 1);
573 app = isl_map_project_out(app, isl_dim_param, param, 1);
575 test = isl_map_apply_range(isl_map_copy(map), isl_map_copy(app));
576 test = isl_map_union(test, isl_map_copy(map));
578 exact = isl_map_is_subset(app, test);
580 isl_map_free(app);
581 isl_map_free(test);
583 isl_map_free(map);
585 return exact;
586 error:
587 isl_map_free(app);
588 isl_map_free(map);
589 return -1;
592 /* Compute the positive powers of "map", or an overapproximation.
593 * The power is given by parameter "param". If the result is exact,
594 * then *exact is set to 1.
595 * If project is set, then we are actually interested in the transitive
596 * closure, so we can use a more relaxed exactness check.
598 static __isl_give isl_map *map_power(__isl_take isl_map *map, unsigned param,
599 int *exact, int project)
601 struct isl_set *domain = NULL;
602 struct isl_set *range = NULL;
603 struct isl_map *app = NULL;
604 struct isl_map *path = NULL;
606 if (exact)
607 *exact = 1;
609 map = isl_map_remove_empty_parts(map);
610 if (!map)
611 return NULL;
613 if (isl_map_fast_is_empty(map))
614 return map;
616 isl_assert(map->ctx, param < isl_map_dim(map, isl_dim_param), goto error);
617 isl_assert(map->ctx,
618 isl_map_dim(map, isl_dim_in) == isl_map_dim(map, isl_dim_out),
619 goto error);
621 domain = isl_map_domain(isl_map_copy(map));
622 domain = isl_set_coalesce(domain);
623 range = isl_map_range(isl_map_copy(map));
624 range = isl_set_coalesce(range);
625 app = isl_map_from_domain_and_range(isl_set_copy(domain),
626 isl_set_copy(range));
628 path = construct_path(map, param, exact ? &project : NULL);
629 app = isl_map_intersect(app, isl_map_copy(path));
631 if (exact &&
632 (*exact = check_exactness(isl_map_copy(map), isl_map_copy(app),
633 param, project)) < 0)
634 goto error;
636 isl_set_free(domain);
637 isl_set_free(range);
638 isl_map_free(path);
639 isl_map_free(map);
640 return app;
641 error:
642 isl_set_free(domain);
643 isl_set_free(range);
644 isl_map_free(path);
645 isl_map_free(map);
646 isl_map_free(app);
647 return NULL;
650 /* Compute the positive powers of "map", or an overapproximation.
651 * The power is given by parameter "param". If the result is exact,
652 * then *exact is set to 1.
654 __isl_give isl_map *isl_map_power(__isl_take isl_map *map, unsigned param,
655 int *exact)
657 return map_power(map, param, exact, 0);
660 /* Compute the transitive closure of "map", or an overapproximation.
661 * If the result is exact, then *exact is set to 1.
662 * Simply compute the powers of map and then project out the parameter
663 * describing the power.
665 __isl_give isl_map *isl_map_transitive_closure(__isl_take isl_map *map,
666 int *exact)
668 unsigned param;
670 if (!map)
671 goto error;
673 param = isl_map_dim(map, isl_dim_param);
674 map = isl_map_add(map, isl_dim_param, 1);
675 map = map_power(map, param, exact, 1);
676 map = isl_map_project_out(map, isl_dim_param, param, 1);
678 return map;
679 error:
680 isl_map_free(map);
681 return NULL;