isl_transitive_closure.c: fix typo in comment
[isl.git] / isl_transitive_closure.c
blobeecdbe543059446945bef41b36299a5f2b659973
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 that maps a element x to any
76 * element that can be reached by taking a positive number of steps
77 * along any of the offsets, where the number of steps k is equal to
78 * parameter "param". That is, construct
80 * { [x] -> [y] : exists k_i >= 0, y = x + \sum_i k_i v_i, k = \sum_i k_i > 0 }
82 * If strict is non-negative, then at least one step should be taken
83 * along the given offset v_strict, i.e., k_strict > 0.
85 static __isl_give isl_map *path_along_steps(__isl_take isl_dim *dim,
86 __isl_keep isl_mat *steps, unsigned param, int strict)
88 int i, j, k;
89 struct isl_basic_map *path = NULL;
90 unsigned d;
91 unsigned n;
92 unsigned nparam;
94 if (!dim || !steps)
95 goto error;
97 d = isl_dim_size(dim, isl_dim_in);
98 n = steps->n_row;
99 nparam = isl_dim_size(dim, isl_dim_param);
101 path = isl_basic_map_alloc_dim(isl_dim_copy(dim), n, d + 1, n + 1);
103 for (i = 0; i < n; ++i) {
104 k = isl_basic_map_alloc_div(path);
105 if (k < 0)
106 goto error;
107 isl_assert(steps->ctx, i == k, goto error);
108 isl_int_set_si(path->div[k][0], 0);
111 for (i = 0; i < d; ++i) {
112 k = isl_basic_map_alloc_equality(path);
113 if (k < 0)
114 goto error;
115 isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path));
116 isl_int_set_si(path->eq[k][1 + nparam + i], 1);
117 isl_int_set_si(path->eq[k][1 + nparam + d + i], -1);
118 for (j = 0; j < n; ++j)
119 isl_int_set(path->eq[k][1 + nparam + 2 * d + j],
120 steps->row[j][i]);
123 k = isl_basic_map_alloc_equality(path);
124 if (k < 0)
125 goto error;
126 isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path));
127 isl_int_set_si(path->eq[k][1 + param], -1);
128 for (j = 0; j < n; ++j)
129 isl_int_set_si(path->eq[k][1 + nparam + 2 * d + j], 1);
131 for (i = 0; i < n; ++i) {
132 k = isl_basic_map_alloc_inequality(path);
133 if (k < 0)
134 goto error;
135 isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path));
136 isl_int_set_si(path->ineq[k][1 + nparam + 2 * d + i], 1);
137 if (i == strict)
138 isl_int_set_si(path->ineq[k][0], -1);
141 k = isl_basic_map_alloc_inequality(path);
142 if (k < 0)
143 goto error;
144 isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path));
145 isl_int_set_si(path->ineq[k][1 + param], 1);
146 isl_int_set_si(path->ineq[k][0], -1);
148 isl_dim_free(dim);
150 path = isl_basic_map_simplify(path);
151 path = isl_basic_map_finalize(path);
152 return isl_map_from_basic_map(path);
153 error:
154 isl_dim_free(dim);
155 isl_basic_map_free(path);
156 return NULL;
159 /* Check whether the overapproximation of the power of "map" is exactly
160 * the power of "map". In particular, for each path of a given length
161 * that starts of in domain or range and ends up in the range,
162 * check whether there is at least one path of the same length
163 * with a valid first segment, i.e., one in "map".
164 * If "project" is set, then we drop the condition that the lengths
165 * should be the same.
167 * "domain" and "range" are the domain and range of "map"
168 * "steps" represents the translations of "map"
169 * "path" is a path along "steps"
171 * "domain", "range", "steps" and "path" have been precomputed by the calling
172 * function.
174 static int check_path_exactness(__isl_take isl_map *map,
175 __isl_take isl_set *domain, __isl_take isl_set *range,
176 __isl_take isl_map *path, __isl_keep isl_mat *steps, unsigned param,
177 int project)
179 isl_map *test;
180 int ok;
181 int i;
183 if (!map)
184 goto error;
186 test = isl_map_empty(isl_map_get_dim(map));
187 for (i = 0; i < map->n; ++i) {
188 struct isl_map *path_i;
189 struct isl_set *dom_i;
190 path_i = path_along_steps(isl_map_get_dim(map), steps, param, i);
191 dom_i = isl_set_from_basic_set(
192 isl_basic_map_domain(isl_basic_map_copy(map->p[i])));
193 path_i = isl_map_intersect_domain(path_i, dom_i);
194 test = isl_map_union(test, path_i);
196 isl_map_free(map);
197 test = isl_map_intersect_range(test, isl_set_copy(range));
199 domain = isl_set_union(domain, isl_set_copy(range));
200 path = isl_map_intersect_domain(path, domain);
201 path = isl_map_intersect_range(path, range);
203 if (project) {
204 path = isl_map_project_out(path, isl_dim_param, param, 1);
205 test = isl_map_project_out(test, isl_dim_param, param, 1);
208 ok = isl_map_is_subset(path, test);
210 isl_map_free(path);
211 isl_map_free(test);
213 return ok;
214 error:
215 isl_map_free(map);
216 isl_set_free(domain);
217 isl_set_free(range);
218 isl_map_free(path);
219 return -1;
222 /* Check whether any path of length at least one along "steps" is acyclic.
223 * That is, check whether
225 * \sum_i k_i \delta_i = 0
226 * \sum_i k_i >= 1
227 * k_i >= 0
229 * with \delta_i the rows of "steps", is infeasible.
231 static int is_acyclic(__isl_keep isl_mat *steps)
233 int acyclic;
234 int i, j, k;
235 struct isl_basic_set *test;
237 if (!steps)
238 return -1;
240 test = isl_basic_set_alloc(steps->ctx, 0, steps->n_row, 0,
241 steps->n_col, steps->n_row + 1);
243 for (i = 0; i < steps->n_col; ++i) {
244 k = isl_basic_set_alloc_equality(test);
245 if (k < 0)
246 goto error;
247 isl_int_set_si(test->eq[k][0], 0);
248 for (j = 0; j < steps->n_row; ++j)
249 isl_int_set(test->eq[k][1 + j], steps->row[j][i]);
251 for (j = 0; j < steps->n_row; ++j) {
252 k = isl_basic_set_alloc_inequality(test);
253 if (k < 0)
254 goto error;
255 isl_seq_clr(test->ineq[k], 1 + steps->n_row);
256 isl_int_set_si(test->ineq[k][1 + j], 1);
259 k = isl_basic_set_alloc_inequality(test);
260 if (k < 0)
261 goto error;
262 isl_int_set_si(test->ineq[k][0], -1);
263 for (j = 0; j < steps->n_row; ++j)
264 isl_int_set_si(test->ineq[k][1 + j], 1);
266 acyclic = isl_basic_set_is_empty(test);
268 isl_basic_set_free(test);
269 return acyclic;
270 error:
271 isl_basic_set_free(test);
272 return -1;
275 /* Check whether the overapproximation of the power of "map" is exactly
276 * the power of "map", possibly after projecting out the power (if "project"
277 * is set).
279 * If "project" is not set, then we simply check for each power if there
280 * is a path of the given length with valid initial segment.
281 * If "project" is set, then we check if "steps" can only result in acyclic
282 * paths. If so, we only need to check that there is a path of _some_
283 * length >= 1. Otherwise, we perform the standard check, i.e., whether
284 * there is a path of the given length.
286 static int check_exactness(__isl_take isl_map *map, __isl_take isl_set *domain,
287 __isl_take isl_set *range, __isl_take isl_map *path,
288 __isl_keep isl_mat *steps, unsigned param, int project)
290 int acyclic;
292 if (!project)
293 return check_path_exactness(map, domain, range, path, steps,
294 param, 0);
296 acyclic = is_acyclic(steps);
297 if (acyclic < 0)
298 goto error;
300 return check_path_exactness(map, domain, range, path, steps,
301 param, acyclic);
302 error:
303 isl_map_free(map);
304 isl_set_free(domain);
305 isl_set_free(range);
306 isl_map_free(path);
307 return -1;
310 /* Compute the positive powers of "map", or an overapproximation.
311 * The power is given by parameter "param". If the result is exact,
312 * then *exact is set to 1.
313 * If project is set, then we are actually interested in the transitive
314 * closure, so we can use a more relaxed exactness check.
316 static __isl_give isl_map *map_power(__isl_take isl_map *map, unsigned param,
317 int *exact, int project)
319 struct isl_mat *steps = NULL;
320 struct isl_set *domain = NULL;
321 struct isl_set *range = NULL;
322 struct isl_map *app = NULL;
323 struct isl_map *path = NULL;
324 int ok;
326 if (exact)
327 *exact = 1;
329 map = isl_map_remove_empty_parts(map);
330 if (!map)
331 return NULL;
333 if (isl_map_fast_is_empty(map))
334 return map;
336 isl_assert(map->ctx, param < isl_map_dim(map, isl_dim_param), goto error);
337 isl_assert(map->ctx,
338 isl_map_dim(map, isl_dim_in) == isl_map_dim(map, isl_dim_out),
339 goto error);
341 domain = isl_map_domain(isl_map_copy(map));
342 range = isl_map_range(isl_map_copy(map));
343 app = isl_map_from_domain_and_range(isl_set_copy(domain),
344 isl_set_copy(range));
346 steps = extract_steps(map, &ok);
347 if (!ok)
348 goto not_exact;
350 path = path_along_steps(isl_map_get_dim(map), steps, param, -1);
351 app = isl_map_intersect(app, isl_map_copy(path));
353 if (exact &&
354 (*exact = check_exactness(isl_map_copy(map), isl_set_copy(domain),
355 isl_set_copy(range), isl_map_copy(path),
356 steps, param, project)) < 0)
357 goto error;
359 if (0) {
360 not_exact:
361 if (exact)
362 *exact = 0;
364 isl_set_free(domain);
365 isl_set_free(range);
366 isl_mat_free(steps);
367 isl_map_free(path);
368 isl_map_free(map);
369 return app;
370 error:
371 isl_set_free(domain);
372 isl_set_free(range);
373 isl_mat_free(steps);
374 isl_map_free(path);
375 isl_map_free(map);
376 isl_map_free(app);
377 return NULL;
380 /* Compute the positive powers of "map", or an overapproximation.
381 * The power is given by parameter "param". If the result is exact,
382 * then *exact is set to 1.
384 __isl_give isl_map *isl_map_power(__isl_take isl_map *map, unsigned param,
385 int *exact)
387 return map_power(map, param, exact, 0);
390 /* Compute the transitive closure of "map", or an overapproximation.
391 * If the result is exact, then *exact is set to 1.
392 * Simply compute the powers of map and then project out the parameter
393 * describing the power.
395 __isl_give isl_map *isl_map_transitive_closure(__isl_take isl_map *map,
396 int *exact)
398 unsigned param;
400 if (!map)
401 goto error;
403 param = isl_map_dim(map, isl_dim_param);
404 map = isl_map_add(map, isl_dim_param, 1);
405 map = map_power(map, param, exact, 1);
406 map = isl_map_project_out(map, isl_dim_param, param, 1);
408 return map;
409 error:
410 isl_map_free(map);
411 return NULL;