isl_map_transitive_closure: construct paths that can be composed
[isl.git] / isl_transitive_closure.c
blob938ee280d5883b0457943256736ed311ad8f0a05
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"
15 * The transitive closure implementation is based on the paper
16 * "Computing the Transitive Closure of a Union of Affine Integer
17 * Tuple Relations" by Anna Beletska, Denis Barthou, Wlodzimierz Bielecki and
18 * Albert Cohen.
21 /* Given a union of translations (uniform dependences), return a matrix
22 * with as many rows as there are disjuncts in the union and as many
23 * columns as there are input dimensions (which should be equal to
24 * the number of output dimensions).
25 * Each row contains the translation performed by the corresponding disjunct.
26 * If "map" turns out not to be a union of translations, then the contents
27 * of the returned matrix are undefined and *ok is set to 0.
29 static __isl_give isl_mat *extract_steps(__isl_keep isl_map *map, int *ok)
31 int i, j;
32 struct isl_mat *steps;
33 unsigned dim = isl_map_dim(map, isl_dim_in);
35 *ok = 1;
37 steps = isl_mat_alloc(map->ctx, map->n, dim);
38 if (!steps)
39 return NULL;
41 for (i = 0; i < map->n; ++i) {
42 struct isl_basic_set *delta;
44 delta = isl_basic_map_deltas(isl_basic_map_copy(map->p[i]));
46 for (j = 0; j < dim; ++j) {
47 int fixed;
49 fixed = isl_basic_set_fast_dim_is_fixed(delta, j,
50 &steps->row[i][j]);
51 if (fixed < 0) {
52 isl_basic_set_free(delta);
53 goto error;
55 if (!fixed)
56 break;
59 isl_basic_set_free(delta);
61 if (j < dim)
62 break;
65 if (i < map->n)
66 *ok = 0;
68 return steps;
69 error:
70 isl_mat_free(steps);
71 return NULL;
74 /* Given a set of n offsets v_i (the rows of "steps"), construct a relation
75 * of the given dimension specification (Z^{n+1} -> Z^{n+1})
76 * that maps an element x to any element that can be reached
77 * by taking a non-negative number of steps along any of
78 * the extended offsets v'_i = [v_i 1].
79 * That is, construct
81 * { [x] -> [y] : exists k_i >= 0, y = x + \sum_i k_i v'_i }
83 * For any element in this relation, the number of steps taken
84 * is equal to the difference in the final coordinates.
86 static __isl_give isl_map *path_along_steps(__isl_take isl_dim *dim,
87 __isl_keep isl_mat *steps)
89 int i, j, k;
90 struct isl_basic_map *path = NULL;
91 unsigned d;
92 unsigned n;
93 unsigned nparam;
95 if (!dim || !steps)
96 goto error;
98 d = isl_dim_size(dim, isl_dim_in);
99 n = steps->n_row;
100 nparam = isl_dim_size(dim, isl_dim_param);
102 path = isl_basic_map_alloc_dim(isl_dim_copy(dim), n, d, n);
104 for (i = 0; i < n; ++i) {
105 k = isl_basic_map_alloc_div(path);
106 if (k < 0)
107 goto error;
108 isl_assert(steps->ctx, i == k, goto error);
109 isl_int_set_si(path->div[k][0], 0);
112 for (i = 0; i < d; ++i) {
113 k = isl_basic_map_alloc_equality(path);
114 if (k < 0)
115 goto error;
116 isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path));
117 isl_int_set_si(path->eq[k][1 + nparam + i], 1);
118 isl_int_set_si(path->eq[k][1 + nparam + d + i], -1);
119 if (i == d - 1)
120 for (j = 0; j < n; ++j)
121 isl_int_set_si(path->eq[k][1 + nparam + 2 * d + j], 1);
122 else
123 for (j = 0; j < n; ++j)
124 isl_int_set(path->eq[k][1 + nparam + 2 * d + j],
125 steps->row[j][i]);
128 for (i = 0; i < n; ++i) {
129 k = isl_basic_map_alloc_inequality(path);
130 if (k < 0)
131 goto error;
132 isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path));
133 isl_int_set_si(path->ineq[k][1 + nparam + 2 * d + i], 1);
136 isl_dim_free(dim);
138 path = isl_basic_map_simplify(path);
139 path = isl_basic_map_finalize(path);
140 return isl_map_from_basic_map(path);
141 error:
142 isl_dim_free(dim);
143 isl_basic_map_free(path);
144 return NULL;
147 /* Given a dimenion specification Z^{n+1} -> Z^{n+1} and a parameter "param",
148 * construct a map that equates the parameter to the difference
149 * in the final coordinates and imposes that this difference is positive.
150 * That is, construct
152 * { [x,x_s] -> [y,y_s] : k = y_s - x_s > 0 }
154 static __isl_give isl_map *equate_parameter_to_length(__isl_take isl_dim *dim,
155 unsigned param)
157 struct isl_basic_map *bmap;
158 unsigned d;
159 unsigned nparam;
160 int k;
162 d = isl_dim_size(dim, isl_dim_in);
163 nparam = isl_dim_size(dim, isl_dim_param);
164 bmap = isl_basic_map_alloc_dim(dim, 0, 1, 1);
165 k = isl_basic_map_alloc_equality(bmap);
166 if (k < 0)
167 goto error;
168 isl_seq_clr(bmap->eq[k], 1 + isl_basic_map_total_dim(bmap));
169 isl_int_set_si(bmap->eq[k][1 + param], -1);
170 isl_int_set_si(bmap->eq[k][1 + nparam + d - 1], -1);
171 isl_int_set_si(bmap->eq[k][1 + nparam + d + d - 1], 1);
173 k = isl_basic_map_alloc_inequality(bmap);
174 if (k < 0)
175 goto error;
176 isl_seq_clr(bmap->ineq[k], 1 + isl_basic_map_total_dim(bmap));
177 isl_int_set_si(bmap->ineq[k][1 + param], 1);
178 isl_int_set_si(bmap->ineq[k][0], -1);
180 bmap = isl_basic_map_finalize(bmap);
181 return isl_map_from_basic_map(bmap);
182 error:
183 isl_basic_map_free(bmap);
184 return NULL;
187 /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D,
188 * construct a map that is an overapproximation of the map
189 * that takes an element from the space D to another
190 * element from the same space, such that the difference between
191 * them is a strictly positive sum of differences between images
192 * and pre-images in one of the R_i.
193 * The number of differences in the sum is equated to parameter "param".
194 * That is, let
196 * \Delta_i = { y - x | (x, y) in R_i }
198 * then the constructed map is an overapproximation of
200 * { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
201 * d = \sum_i k_i and k = \sum_i k_i > 0 }
203 * We first construct an extended mapping with an extra coordinate
204 * that indicates the number of steps taken. In particular,
205 * the difference in the last coordinate is equal to the number
206 * of steps taken to move from a domain element to the corresponding
207 * image element(s).
208 * In the final step, this difference is equated to the parameter "param"
209 * and made positive. The extra coordinates are subsequently projected out.
211 * If any of the \Delta_i contains more than one element, then
212 * we currently simply return a universal map { (x) -> (y) }.
214 static __isl_give isl_map *construct_path(__isl_keep isl_map *map,
215 unsigned param)
217 struct isl_mat *steps = NULL;
218 struct isl_map *path = NULL;
219 struct isl_map *diff;
220 struct isl_dim *dim;
221 unsigned d;
222 int ok;
224 if (!map)
225 return NULL;
227 steps = extract_steps(map, &ok);
228 if (!steps)
229 return NULL;
230 if (!ok) {
231 isl_mat_free(steps);
232 return isl_map_universe(isl_map_get_dim(map));
235 dim = isl_map_get_dim(map);
237 d = isl_dim_size(dim, isl_dim_in);
238 dim = isl_dim_add(dim, isl_dim_in, 1);
239 dim = isl_dim_add(dim, isl_dim_out, 1);
240 path = path_along_steps(isl_dim_copy(dim), steps);
241 diff = equate_parameter_to_length(dim, param);
243 path = isl_map_intersect(path, diff);
244 path = isl_map_project_out(path, isl_dim_in, d, 1);
245 path = isl_map_project_out(path, isl_dim_out, d, 1);
247 isl_mat_free(steps);
248 return path;
251 /* Check whether "path" is acyclic.
252 * That is, check whether
254 * { d | d = y - x and (x,y) in path }
256 * does not contain the origin.
258 static int is_acyclic(__isl_take isl_map *path)
260 int i;
261 int acyclic;
262 unsigned dim;
263 struct isl_set *delta;
265 delta = isl_map_deltas(path);
266 dim = isl_set_dim(delta, isl_dim_set);
267 for (i = 0; i < dim; ++i)
268 delta = isl_set_fix_si(delta, isl_dim_set, i, 0);
270 acyclic = isl_set_is_empty(delta);
271 isl_set_free(delta);
273 return acyclic;
276 /* Shift variable at position "pos" up by one.
277 * That is, replace the corresponding variable v by v - 1.
279 static __isl_give isl_basic_map *basic_map_shift_pos(
280 __isl_take isl_basic_map *bmap, unsigned pos)
282 int i;
284 bmap = isl_basic_map_cow(bmap);
285 if (!bmap)
286 return NULL;
288 for (i = 0; i < bmap->n_eq; ++i)
289 isl_int_sub(bmap->eq[i][0], bmap->eq[i][0], bmap->eq[i][pos]);
291 for (i = 0; i < bmap->n_ineq; ++i)
292 isl_int_sub(bmap->ineq[i][0],
293 bmap->ineq[i][0], bmap->ineq[i][pos]);
295 for (i = 0; i < bmap->n_div; ++i) {
296 if (isl_int_is_zero(bmap->div[i][0]))
297 continue;
298 isl_int_sub(bmap->div[i][1],
299 bmap->div[i][1], bmap->div[i][1 + pos]);
302 return bmap;
305 /* Shift variable at position "pos" up by one.
306 * That is, replace the corresponding variable v by v - 1.
308 static __isl_give isl_map *map_shift_pos(__isl_take isl_map *map, unsigned pos)
310 int i;
312 map = isl_map_cow(map);
313 if (!map)
314 return NULL;
316 for (i = 0; i < map->n; ++i) {
317 map->p[i] = basic_map_shift_pos(map->p[i], pos);
318 if (!map->p[i])
319 goto error;
321 ISL_F_CLR(map, ISL_MAP_NORMALIZED);
322 return map;
323 error:
324 isl_map_free(map);
325 return NULL;
328 /* Check whether the overapproximation of the power of "map" is exactly
329 * the power of "map". Let R be "map" and A_k the overapproximation.
330 * The approximation is exact if
332 * A_1 = R
333 * A_k = A_{k-1} \circ R k >= 2
335 * Since A_k is known to be an overapproximation, we only need to check
337 * A_1 \subset R
338 * A_k \subset A_{k-1} \circ R k >= 2
341 static int check_power_exactness(__isl_take isl_map *map,
342 __isl_take isl_map *app, unsigned param)
344 int exact;
345 isl_map *app_1;
346 isl_map *app_2;
348 app_1 = isl_map_fix_si(isl_map_copy(app), isl_dim_param, param, 1);
350 exact = isl_map_is_subset(app_1, map);
351 isl_map_free(app_1);
353 if (!exact || exact < 0) {
354 isl_map_free(app);
355 isl_map_free(map);
356 return exact;
359 app_2 = isl_map_lower_bound_si(isl_map_copy(app),
360 isl_dim_param, param, 2);
361 app_1 = map_shift_pos(app, 1 + param);
362 app_1 = isl_map_apply_range(map, app_1);
364 exact = isl_map_is_subset(app_2, app_1);
366 isl_map_free(app_1);
367 isl_map_free(app_2);
369 return exact;
372 /* Check whether the overapproximation of the power of "map" is exactly
373 * the power of "map", possibly after projecting out the power (if "project"
374 * is set).
376 * If "project" is set and if "steps" can only result in acyclic paths,
377 * then we check
379 * A = R \cup (A \circ R)
381 * where A is the overapproximation with the power projected out, i.e.,
382 * an overapproximation of the transitive closure.
383 * More specifically, since A is known to be an overapproximation, we check
385 * A \subset R \cup (A \circ R)
387 * Otherwise, we check if the power is exact.
389 static int check_exactness(__isl_take isl_map *map, __isl_take isl_map *app,
390 __isl_take isl_map *path, unsigned param, int project)
392 isl_map *test;
393 int exact;
395 if (project) {
396 project = is_acyclic(path);
397 if (project < 0)
398 goto error;
399 } else
400 isl_map_free(path);
402 if (!project)
403 return check_power_exactness(map, app, param);
405 map = isl_map_project_out(map, isl_dim_param, param, 1);
406 app = isl_map_project_out(app, isl_dim_param, param, 1);
408 test = isl_map_apply_range(isl_map_copy(map), isl_map_copy(app));
409 test = isl_map_union(test, isl_map_copy(map));
411 exact = isl_map_is_subset(app, test);
413 isl_map_free(app);
414 isl_map_free(test);
416 isl_map_free(map);
418 return exact;
419 error:
420 isl_map_free(app);
421 isl_map_free(map);
422 return -1;
425 /* Compute the positive powers of "map", or an overapproximation.
426 * The power is given by parameter "param". If the result is exact,
427 * then *exact is set to 1.
428 * If project is set, then we are actually interested in the transitive
429 * closure, so we can use a more relaxed exactness check.
431 static __isl_give isl_map *map_power(__isl_take isl_map *map, unsigned param,
432 int *exact, int project)
434 struct isl_set *domain = NULL;
435 struct isl_set *range = NULL;
436 struct isl_map *app = NULL;
437 struct isl_map *path = NULL;
439 if (exact)
440 *exact = 1;
442 map = isl_map_remove_empty_parts(map);
443 if (!map)
444 return NULL;
446 if (isl_map_fast_is_empty(map))
447 return map;
449 isl_assert(map->ctx, param < isl_map_dim(map, isl_dim_param), goto error);
450 isl_assert(map->ctx,
451 isl_map_dim(map, isl_dim_in) == isl_map_dim(map, isl_dim_out),
452 goto error);
454 domain = isl_map_domain(isl_map_copy(map));
455 domain = isl_set_coalesce(domain);
456 range = isl_map_range(isl_map_copy(map));
457 range = isl_set_coalesce(range);
458 app = isl_map_from_domain_and_range(isl_set_copy(domain),
459 isl_set_copy(range));
461 path = construct_path(map, param);
462 app = isl_map_intersect(app, isl_map_copy(path));
464 if (exact &&
465 (*exact = check_exactness(isl_map_copy(map), isl_map_copy(app),
466 isl_map_copy(path), param, project)) < 0)
467 goto error;
469 isl_set_free(domain);
470 isl_set_free(range);
471 isl_map_free(path);
472 isl_map_free(map);
473 return app;
474 error:
475 isl_set_free(domain);
476 isl_set_free(range);
477 isl_map_free(path);
478 isl_map_free(map);
479 isl_map_free(app);
480 return NULL;
483 /* Compute the positive powers of "map", or an overapproximation.
484 * The power is given by parameter "param". If the result is exact,
485 * then *exact is set to 1.
487 __isl_give isl_map *isl_map_power(__isl_take isl_map *map, unsigned param,
488 int *exact)
490 return map_power(map, param, exact, 0);
493 /* Compute the transitive closure of "map", or an overapproximation.
494 * If the result is exact, then *exact is set to 1.
495 * Simply compute the powers of map and then project out the parameter
496 * describing the power.
498 __isl_give isl_map *isl_map_transitive_closure(__isl_take isl_map *map,
499 int *exact)
501 unsigned param;
503 if (!map)
504 goto error;
506 param = isl_map_dim(map, isl_dim_param);
507 map = isl_map_add(map, isl_dim_param, 1);
508 map = map_power(map, param, exact, 1);
509 map = isl_map_project_out(map, isl_dim_param, param, 1);
511 return map;
512 error:
513 isl_map_free(map);
514 return NULL;