• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2010      INRIA Saclay
3  *
4  * Use of this software is governed by the MIT license
5  *
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  */
10 
11 #include <isl_ctx_private.h>
12 #include <isl_map_private.h>
13 #include <isl/map.h>
14 #include <isl_seq.h>
15 #include <isl_space_private.h>
16 #include <isl_lp_private.h>
17 #include <isl/union_map.h>
18 #include <isl_mat_private.h>
19 #include <isl_vec_private.h>
20 #include <isl_options_private.h>
21 #include <isl_tarjan.h>
22 
isl_map_is_transitively_closed(__isl_keep isl_map * map)23 isl_bool isl_map_is_transitively_closed(__isl_keep isl_map *map)
24 {
25 	isl_map *map2;
26 	isl_bool closed;
27 
28 	map2 = isl_map_apply_range(isl_map_copy(map), isl_map_copy(map));
29 	closed = isl_map_is_subset(map2, map);
30 	isl_map_free(map2);
31 
32 	return closed;
33 }
34 
isl_union_map_is_transitively_closed(__isl_keep isl_union_map * umap)35 isl_bool isl_union_map_is_transitively_closed(__isl_keep isl_union_map *umap)
36 {
37 	isl_union_map *umap2;
38 	isl_bool closed;
39 
40 	umap2 = isl_union_map_apply_range(isl_union_map_copy(umap),
41 					  isl_union_map_copy(umap));
42 	closed = isl_union_map_is_subset(umap2, umap);
43 	isl_union_map_free(umap2);
44 
45 	return closed;
46 }
47 
48 /* Given a map that represents a path with the length of the path
49  * encoded as the difference between the last output coordindate
50  * and the last input coordinate, set this length to either
51  * exactly "length" (if "exactly" is set) or at least "length"
52  * (if "exactly" is not set).
53  */
set_path_length(__isl_take isl_map * map,int exactly,int length)54 static __isl_give isl_map *set_path_length(__isl_take isl_map *map,
55 	int exactly, int length)
56 {
57 	isl_space *space;
58 	struct isl_basic_map *bmap;
59 	isl_size d;
60 	isl_size nparam;
61 	isl_size total;
62 	int k;
63 	isl_int *c;
64 
65 	if (!map)
66 		return NULL;
67 
68 	space = isl_map_get_space(map);
69 	d = isl_space_dim(space, isl_dim_in);
70 	nparam = isl_space_dim(space, isl_dim_param);
71 	total = isl_space_dim(space, isl_dim_all);
72 	if (d < 0 || nparam < 0 || total < 0)
73 		space = isl_space_free(space);
74 	bmap = isl_basic_map_alloc_space(space, 0, 1, 1);
75 	if (exactly) {
76 		k = isl_basic_map_alloc_equality(bmap);
77 		if (k < 0)
78 			goto error;
79 		c = bmap->eq[k];
80 	} else {
81 		k = isl_basic_map_alloc_inequality(bmap);
82 		if (k < 0)
83 			goto error;
84 		c = bmap->ineq[k];
85 	}
86 	isl_seq_clr(c, 1 + total);
87 	isl_int_set_si(c[0], -length);
88 	isl_int_set_si(c[1 + nparam + d - 1], -1);
89 	isl_int_set_si(c[1 + nparam + d + d - 1], 1);
90 
91 	bmap = isl_basic_map_finalize(bmap);
92 	map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
93 
94 	return map;
95 error:
96 	isl_basic_map_free(bmap);
97 	isl_map_free(map);
98 	return NULL;
99 }
100 
101 /* Check whether the overapproximation of the power of "map" is exactly
102  * the power of "map".  Let R be "map" and A_k the overapproximation.
103  * The approximation is exact if
104  *
105  *	A_1 = R
106  *	A_k = A_{k-1} \circ R			k >= 2
107  *
108  * Since A_k is known to be an overapproximation, we only need to check
109  *
110  *	A_1 \subset R
111  *	A_k \subset A_{k-1} \circ R		k >= 2
112  *
113  * In practice, "app" has an extra input and output coordinate
114  * to encode the length of the path.  So, we first need to add
115  * this coordinate to "map" and set the length of the path to
116  * one.
117  */
check_power_exactness(__isl_take isl_map * map,__isl_take isl_map * app)118 static isl_bool check_power_exactness(__isl_take isl_map *map,
119 	__isl_take isl_map *app)
120 {
121 	isl_bool exact;
122 	isl_map *app_1;
123 	isl_map *app_2;
124 
125 	map = isl_map_add_dims(map, isl_dim_in, 1);
126 	map = isl_map_add_dims(map, isl_dim_out, 1);
127 	map = set_path_length(map, 1, 1);
128 
129 	app_1 = set_path_length(isl_map_copy(app), 1, 1);
130 
131 	exact = isl_map_is_subset(app_1, map);
132 	isl_map_free(app_1);
133 
134 	if (!exact || exact < 0) {
135 		isl_map_free(app);
136 		isl_map_free(map);
137 		return exact;
138 	}
139 
140 	app_1 = set_path_length(isl_map_copy(app), 0, 1);
141 	app_2 = set_path_length(app, 0, 2);
142 	app_1 = isl_map_apply_range(map, app_1);
143 
144 	exact = isl_map_is_subset(app_2, app_1);
145 
146 	isl_map_free(app_1);
147 	isl_map_free(app_2);
148 
149 	return exact;
150 }
151 
152 /* Check whether the overapproximation of the power of "map" is exactly
153  * the power of "map", possibly after projecting out the power (if "project"
154  * is set).
155  *
156  * If "project" is set and if "steps" can only result in acyclic paths,
157  * then we check
158  *
159  *	A = R \cup (A \circ R)
160  *
161  * where A is the overapproximation with the power projected out, i.e.,
162  * an overapproximation of the transitive closure.
163  * More specifically, since A is known to be an overapproximation, we check
164  *
165  *	A \subset R \cup (A \circ R)
166  *
167  * Otherwise, we check if the power is exact.
168  *
169  * Note that "app" has an extra input and output coordinate to encode
170  * the length of the part.  If we are only interested in the transitive
171  * closure, then we can simply project out these coordinates first.
172  */
check_exactness(__isl_take isl_map * map,__isl_take isl_map * app,int project)173 static isl_bool check_exactness(__isl_take isl_map *map,
174 	__isl_take isl_map *app, int project)
175 {
176 	isl_map *test;
177 	isl_bool exact;
178 	isl_size d;
179 
180 	if (!project)
181 		return check_power_exactness(map, app);
182 
183 	d = isl_map_dim(map, isl_dim_in);
184 	if (d < 0)
185 		app = isl_map_free(app);
186 	app = set_path_length(app, 0, 1);
187 	app = isl_map_project_out(app, isl_dim_in, d, 1);
188 	app = isl_map_project_out(app, isl_dim_out, d, 1);
189 
190 	app = isl_map_reset_space(app, isl_map_get_space(map));
191 
192 	test = isl_map_apply_range(isl_map_copy(map), isl_map_copy(app));
193 	test = isl_map_union(test, isl_map_copy(map));
194 
195 	exact = isl_map_is_subset(app, test);
196 
197 	isl_map_free(app);
198 	isl_map_free(test);
199 
200 	isl_map_free(map);
201 
202 	return exact;
203 }
204 
205 /*
206  * The transitive closure implementation is based on the paper
207  * "Computing the Transitive Closure of a Union of Affine Integer
208  * Tuple Relations" by Anna Beletska, Denis Barthou, Wlodzimierz Bielecki and
209  * Albert Cohen.
210  */
211 
212 /* Given a set of n offsets v_i (the rows of "steps"), construct a relation
213  * of the given dimension specification (Z^{n+1} -> Z^{n+1})
214  * that maps an element x to any element that can be reached
215  * by taking a non-negative number of steps along any of
216  * the extended offsets v'_i = [v_i 1].
217  * That is, construct
218  *
219  * { [x] -> [y] : exists k_i >= 0, y = x + \sum_i k_i v'_i }
220  *
221  * For any element in this relation, the number of steps taken
222  * is equal to the difference in the final coordinates.
223  */
path_along_steps(__isl_take isl_space * space,__isl_keep isl_mat * steps)224 static __isl_give isl_map *path_along_steps(__isl_take isl_space *space,
225 	__isl_keep isl_mat *steps)
226 {
227 	int i, j, k;
228 	struct isl_basic_map *path = NULL;
229 	isl_size d;
230 	unsigned n;
231 	isl_size nparam;
232 	isl_size total;
233 
234 	d = isl_space_dim(space, isl_dim_in);
235 	nparam = isl_space_dim(space, isl_dim_param);
236 	if (d < 0 || nparam < 0 || !steps)
237 		goto error;
238 
239 	n = steps->n_row;
240 
241 	path = isl_basic_map_alloc_space(isl_space_copy(space), n, d, n);
242 
243 	for (i = 0; i < n; ++i) {
244 		k = isl_basic_map_alloc_div(path);
245 		if (k < 0)
246 			goto error;
247 		isl_assert(steps->ctx, i == k, goto error);
248 		isl_int_set_si(path->div[k][0], 0);
249 	}
250 
251 	total = isl_basic_map_dim(path, isl_dim_all);
252 	if (total < 0)
253 		goto error;
254 	for (i = 0; i < d; ++i) {
255 		k = isl_basic_map_alloc_equality(path);
256 		if (k < 0)
257 			goto error;
258 		isl_seq_clr(path->eq[k], 1 + total);
259 		isl_int_set_si(path->eq[k][1 + nparam + i], 1);
260 		isl_int_set_si(path->eq[k][1 + nparam + d + i], -1);
261 		if (i == d - 1)
262 			for (j = 0; j < n; ++j)
263 				isl_int_set_si(path->eq[k][1 + nparam + 2 * d + j], 1);
264 		else
265 			for (j = 0; j < n; ++j)
266 				isl_int_set(path->eq[k][1 + nparam + 2 * d + j],
267 					    steps->row[j][i]);
268 	}
269 
270 	for (i = 0; i < n; ++i) {
271 		k = isl_basic_map_alloc_inequality(path);
272 		if (k < 0)
273 			goto error;
274 		isl_seq_clr(path->ineq[k], 1 + total);
275 		isl_int_set_si(path->ineq[k][1 + nparam + 2 * d + i], 1);
276 	}
277 
278 	isl_space_free(space);
279 
280 	path = isl_basic_map_simplify(path);
281 	path = isl_basic_map_finalize(path);
282 	return isl_map_from_basic_map(path);
283 error:
284 	isl_space_free(space);
285 	isl_basic_map_free(path);
286 	return NULL;
287 }
288 
289 #define IMPURE		0
290 #define PURE_PARAM	1
291 #define PURE_VAR	2
292 #define MIXED		3
293 
294 /* Check whether the parametric constant term of constraint c is never
295  * positive in "bset".
296  */
parametric_constant_never_positive(__isl_keep isl_basic_set * bset,isl_int * c,int * div_purity)297 static isl_bool parametric_constant_never_positive(
298 	__isl_keep isl_basic_set *bset, isl_int *c, int *div_purity)
299 {
300 	isl_size d;
301 	isl_size n_div;
302 	isl_size nparam;
303 	isl_size total;
304 	int i;
305 	int k;
306 	isl_bool empty;
307 
308 	n_div = isl_basic_set_dim(bset, isl_dim_div);
309 	d = isl_basic_set_dim(bset, isl_dim_set);
310 	nparam = isl_basic_set_dim(bset, isl_dim_param);
311 	total = isl_basic_set_dim(bset, isl_dim_all);
312 	if (n_div < 0 || d < 0 || nparam < 0 || total < 0)
313 		return isl_bool_error;
314 
315 	bset = isl_basic_set_copy(bset);
316 	bset = isl_basic_set_cow(bset);
317 	bset = isl_basic_set_extend_constraints(bset, 0, 1);
318 	k = isl_basic_set_alloc_inequality(bset);
319 	if (k < 0)
320 		goto error;
321 	isl_seq_clr(bset->ineq[k], 1 + total);
322 	isl_seq_cpy(bset->ineq[k], c, 1 + nparam);
323 	for (i = 0; i < n_div; ++i) {
324 		if (div_purity[i] != PURE_PARAM)
325 			continue;
326 		isl_int_set(bset->ineq[k][1 + nparam + d + i],
327 			    c[1 + nparam + d + i]);
328 	}
329 	isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1);
330 	empty = isl_basic_set_is_empty(bset);
331 	isl_basic_set_free(bset);
332 
333 	return empty;
334 error:
335 	isl_basic_set_free(bset);
336 	return isl_bool_error;
337 }
338 
339 /* Return PURE_PARAM if only the coefficients of the parameters are non-zero.
340  * Return PURE_VAR if only the coefficients of the set variables are non-zero.
341  * Return MIXED if only the coefficients of the parameters and the set
342  * 	variables are non-zero and if moreover the parametric constant
343  * 	can never attain positive values.
344  * Return IMPURE otherwise.
345  */
purity(__isl_keep isl_basic_set * bset,isl_int * c,int * div_purity,int eq)346 static int purity(__isl_keep isl_basic_set *bset, isl_int *c, int *div_purity,
347 	int eq)
348 {
349 	isl_size d;
350 	isl_size n_div;
351 	isl_size nparam;
352 	isl_bool empty;
353 	int i;
354 	int p = 0, v = 0;
355 
356 	n_div = isl_basic_set_dim(bset, isl_dim_div);
357 	d = isl_basic_set_dim(bset, isl_dim_set);
358 	nparam = isl_basic_set_dim(bset, isl_dim_param);
359 	if (n_div < 0 || d < 0 || nparam < 0)
360 		return -1;
361 
362 	for (i = 0; i < n_div; ++i) {
363 		if (isl_int_is_zero(c[1 + nparam + d + i]))
364 			continue;
365 		switch (div_purity[i]) {
366 		case PURE_PARAM: p = 1; break;
367 		case PURE_VAR: v = 1; break;
368 		default: return IMPURE;
369 		}
370 	}
371 	if (!p && isl_seq_first_non_zero(c + 1, nparam) == -1)
372 		return PURE_VAR;
373 	if (!v && isl_seq_first_non_zero(c + 1 + nparam, d) == -1)
374 		return PURE_PARAM;
375 
376 	empty = parametric_constant_never_positive(bset, c, div_purity);
377 	if (eq && empty >= 0 && !empty) {
378 		isl_seq_neg(c, c, 1 + nparam + d + n_div);
379 		empty = parametric_constant_never_positive(bset, c, div_purity);
380 	}
381 
382 	return empty < 0 ? -1 : empty ? MIXED : IMPURE;
383 }
384 
385 /* Return an array of integers indicating the type of each div in bset.
386  * If the div is (recursively) defined in terms of only the parameters,
387  * then the type is PURE_PARAM.
388  * If the div is (recursively) defined in terms of only the set variables,
389  * then the type is PURE_VAR.
390  * Otherwise, the type is IMPURE.
391  */
get_div_purity(__isl_keep isl_basic_set * bset)392 static __isl_give int *get_div_purity(__isl_keep isl_basic_set *bset)
393 {
394 	int i, j;
395 	int *div_purity;
396 	isl_size d;
397 	isl_size n_div;
398 	isl_size nparam;
399 
400 	n_div = isl_basic_set_dim(bset, isl_dim_div);
401 	d = isl_basic_set_dim(bset, isl_dim_set);
402 	nparam = isl_basic_set_dim(bset, isl_dim_param);
403 	if (n_div < 0 || d < 0 || nparam < 0)
404 		return NULL;
405 
406 	div_purity = isl_alloc_array(bset->ctx, int, n_div);
407 	if (n_div && !div_purity)
408 		return NULL;
409 
410 	for (i = 0; i < bset->n_div; ++i) {
411 		int p = 0, v = 0;
412 		if (isl_int_is_zero(bset->div[i][0])) {
413 			div_purity[i] = IMPURE;
414 			continue;
415 		}
416 		if (isl_seq_first_non_zero(bset->div[i] + 2, nparam) != -1)
417 			p = 1;
418 		if (isl_seq_first_non_zero(bset->div[i] + 2 + nparam, d) != -1)
419 			v = 1;
420 		for (j = 0; j < i; ++j) {
421 			if (isl_int_is_zero(bset->div[i][2 + nparam + d + j]))
422 				continue;
423 			switch (div_purity[j]) {
424 			case PURE_PARAM: p = 1; break;
425 			case PURE_VAR: v = 1; break;
426 			default: p = v = 1; break;
427 			}
428 		}
429 		div_purity[i] = v ? p ? IMPURE : PURE_VAR : PURE_PARAM;
430 	}
431 
432 	return div_purity;
433 }
434 
435 /* Given a path with the as yet unconstrained length at div position "pos",
436  * check if setting the length to zero results in only the identity
437  * mapping.
438  */
empty_path_is_identity(__isl_keep isl_basic_map * path,unsigned pos)439 static isl_bool empty_path_is_identity(__isl_keep isl_basic_map *path,
440 	unsigned pos)
441 {
442 	isl_basic_map *test = NULL;
443 	isl_basic_map *id = NULL;
444 	isl_bool is_id;
445 
446 	test = isl_basic_map_copy(path);
447 	test = isl_basic_map_fix_si(test, isl_dim_div, pos, 0);
448 	id = isl_basic_map_identity(isl_basic_map_get_space(path));
449 	is_id = isl_basic_map_is_equal(test, id);
450 	isl_basic_map_free(test);
451 	isl_basic_map_free(id);
452 	return is_id;
453 }
454 
455 /* If any of the constraints is found to be impure then this function
456  * sets *impurity to 1.
457  *
458  * If impurity is NULL then we are dealing with a non-parametric set
459  * and so the constraints are obviously PURE_VAR.
460  */
add_delta_constraints(__isl_take isl_basic_map * path,__isl_keep isl_basic_set * delta,unsigned off,unsigned nparam,unsigned d,int * div_purity,int eq,int * impurity)461 static __isl_give isl_basic_map *add_delta_constraints(
462 	__isl_take isl_basic_map *path,
463 	__isl_keep isl_basic_set *delta, unsigned off, unsigned nparam,
464 	unsigned d, int *div_purity, int eq, int *impurity)
465 {
466 	int i, k;
467 	int n = eq ? delta->n_eq : delta->n_ineq;
468 	isl_int **delta_c = eq ? delta->eq : delta->ineq;
469 	isl_size n_div, total;
470 
471 	n_div = isl_basic_set_dim(delta, isl_dim_div);
472 	total = isl_basic_map_dim(path, isl_dim_all);
473 	if (n_div < 0 || total < 0)
474 		return isl_basic_map_free(path);
475 
476 	for (i = 0; i < n; ++i) {
477 		isl_int *path_c;
478 		int p = PURE_VAR;
479 		if (impurity)
480 			p = purity(delta, delta_c[i], div_purity, eq);
481 		if (p < 0)
482 			goto error;
483 		if (p != PURE_VAR && p != PURE_PARAM && !*impurity)
484 			*impurity = 1;
485 		if (p == IMPURE)
486 			continue;
487 		if (eq && p != MIXED) {
488 			k = isl_basic_map_alloc_equality(path);
489 			if (k < 0)
490 				goto error;
491 			path_c = path->eq[k];
492 		} else {
493 			k = isl_basic_map_alloc_inequality(path);
494 			if (k < 0)
495 				goto error;
496 			path_c = path->ineq[k];
497 		}
498 		isl_seq_clr(path_c, 1 + total);
499 		if (p == PURE_VAR) {
500 			isl_seq_cpy(path_c + off,
501 				    delta_c[i] + 1 + nparam, d);
502 			isl_int_set(path_c[off + d], delta_c[i][0]);
503 		} else if (p == PURE_PARAM) {
504 			isl_seq_cpy(path_c, delta_c[i], 1 + nparam);
505 		} else {
506 			isl_seq_cpy(path_c + off,
507 				    delta_c[i] + 1 + nparam, d);
508 			isl_seq_cpy(path_c, delta_c[i], 1 + nparam);
509 		}
510 		isl_seq_cpy(path_c + off - n_div,
511 			    delta_c[i] + 1 + nparam + d, n_div);
512 	}
513 
514 	return path;
515 error:
516 	isl_basic_map_free(path);
517 	return NULL;
518 }
519 
520 /* Given a set of offsets "delta", construct a relation of the
521  * given dimension specification (Z^{n+1} -> Z^{n+1}) that
522  * is an overapproximation of the relations that
523  * maps an element x to any element that can be reached
524  * by taking a non-negative number of steps along any of
525  * the elements in "delta".
526  * That is, construct an approximation of
527  *
528  *	{ [x] -> [y] : exists f \in \delta, k \in Z :
529  *					y = x + k [f, 1] and k >= 0 }
530  *
531  * For any element in this relation, the number of steps taken
532  * is equal to the difference in the final coordinates.
533  *
534  * In particular, let delta be defined as
535  *
536  *	\delta = [p] -> { [x] : A x + a >= 0 and B p + b >= 0 and
537  *				C x + C'p + c >= 0 and
538  *				D x + D'p + d >= 0 }
539  *
540  * where the constraints C x + C'p + c >= 0 are such that the parametric
541  * constant term of each constraint j, "C_j x + C'_j p + c_j",
542  * can never attain positive values, then the relation is constructed as
543  *
544  *	{ [x] -> [y] : exists [f, k] \in Z^{n+1} : y = x + f and
545  *			A f + k a >= 0 and B p + b >= 0 and
546  *			C f + C'p + c >= 0 and k >= 1 }
547  *	union { [x] -> [x] }
548  *
549  * If the zero-length paths happen to correspond exactly to the identity
550  * mapping, then we return
551  *
552  *	{ [x] -> [y] : exists [f, k] \in Z^{n+1} : y = x + f and
553  *			A f + k a >= 0 and B p + b >= 0 and
554  *			C f + C'p + c >= 0 and k >= 0 }
555  *
556  * instead.
557  *
558  * Existentially quantified variables in \delta are handled by
559  * classifying them as independent of the parameters, purely
560  * parameter dependent and others.  Constraints containing
561  * any of the other existentially quantified variables are removed.
562  * This is safe, but leads to an additional overapproximation.
563  *
564  * If there are any impure constraints, then we also eliminate
565  * the parameters from \delta, resulting in a set
566  *
567  *	\delta' = { [x] : E x + e >= 0 }
568  *
569  * and add the constraints
570  *
571  *			E f + k e >= 0
572  *
573  * to the constructed relation.
574  */
path_along_delta(__isl_take isl_space * space,__isl_take isl_basic_set * delta)575 static __isl_give isl_map *path_along_delta(__isl_take isl_space *space,
576 	__isl_take isl_basic_set *delta)
577 {
578 	isl_basic_map *path = NULL;
579 	isl_size d;
580 	isl_size n_div;
581 	isl_size nparam;
582 	isl_size total;
583 	unsigned off;
584 	int i, k;
585 	isl_bool is_id;
586 	int *div_purity = NULL;
587 	int impurity = 0;
588 
589 	n_div = isl_basic_set_dim(delta, isl_dim_div);
590 	d = isl_basic_set_dim(delta, isl_dim_set);
591 	nparam = isl_basic_set_dim(delta, isl_dim_param);
592 	if (n_div < 0 || d < 0 || nparam < 0)
593 		goto error;
594 	path = isl_basic_map_alloc_space(isl_space_copy(space), n_div + d + 1,
595 			d + 1 + delta->n_eq, delta->n_eq + delta->n_ineq + 1);
596 	off = 1 + nparam + 2 * (d + 1) + n_div;
597 
598 	for (i = 0; i < n_div + d + 1; ++i) {
599 		k = isl_basic_map_alloc_div(path);
600 		if (k < 0)
601 			goto error;
602 		isl_int_set_si(path->div[k][0], 0);
603 	}
604 
605 	total = isl_basic_map_dim(path, isl_dim_all);
606 	if (total < 0)
607 		goto error;
608 	for (i = 0; i < d + 1; ++i) {
609 		k = isl_basic_map_alloc_equality(path);
610 		if (k < 0)
611 			goto error;
612 		isl_seq_clr(path->eq[k], 1 + total);
613 		isl_int_set_si(path->eq[k][1 + nparam + i], 1);
614 		isl_int_set_si(path->eq[k][1 + nparam + d + 1 + i], -1);
615 		isl_int_set_si(path->eq[k][off + i], 1);
616 	}
617 
618 	div_purity = get_div_purity(delta);
619 	if (n_div && !div_purity)
620 		goto error;
621 
622 	path = add_delta_constraints(path, delta, off, nparam, d,
623 				     div_purity, 1, &impurity);
624 	path = add_delta_constraints(path, delta, off, nparam, d,
625 				     div_purity, 0, &impurity);
626 	if (impurity) {
627 		isl_space *space = isl_basic_set_get_space(delta);
628 		delta = isl_basic_set_project_out(delta,
629 						  isl_dim_param, 0, nparam);
630 		delta = isl_basic_set_add_dims(delta, isl_dim_param, nparam);
631 		delta = isl_basic_set_reset_space(delta, space);
632 		if (!delta)
633 			goto error;
634 		path = isl_basic_map_extend_constraints(path, delta->n_eq,
635 							delta->n_ineq + 1);
636 		path = add_delta_constraints(path, delta, off, nparam, d,
637 					     NULL, 1, NULL);
638 		path = add_delta_constraints(path, delta, off, nparam, d,
639 					     NULL, 0, NULL);
640 		path = isl_basic_map_gauss(path, NULL);
641 	}
642 
643 	is_id = empty_path_is_identity(path, n_div + d);
644 	if (is_id < 0)
645 		goto error;
646 
647 	k = isl_basic_map_alloc_inequality(path);
648 	if (k < 0)
649 		goto error;
650 	isl_seq_clr(path->ineq[k], 1 + total);
651 	if (!is_id)
652 		isl_int_set_si(path->ineq[k][0], -1);
653 	isl_int_set_si(path->ineq[k][off + d], 1);
654 
655 	free(div_purity);
656 	isl_basic_set_free(delta);
657 	path = isl_basic_map_finalize(path);
658 	if (is_id) {
659 		isl_space_free(space);
660 		return isl_map_from_basic_map(path);
661 	}
662 	return isl_basic_map_union(path, isl_basic_map_identity(space));
663 error:
664 	free(div_purity);
665 	isl_space_free(space);
666 	isl_basic_set_free(delta);
667 	isl_basic_map_free(path);
668 	return NULL;
669 }
670 
671 /* Given a dimension specification Z^{n+1} -> Z^{n+1} and a parameter "param",
672  * construct a map that equates the parameter to the difference
673  * in the final coordinates and imposes that this difference is positive.
674  * That is, construct
675  *
676  *	{ [x,x_s] -> [y,y_s] : k = y_s - x_s > 0 }
677  */
equate_parameter_to_length(__isl_take isl_space * space,unsigned param)678 static __isl_give isl_map *equate_parameter_to_length(
679 	__isl_take isl_space *space, unsigned param)
680 {
681 	struct isl_basic_map *bmap;
682 	isl_size d;
683 	isl_size nparam;
684 	isl_size total;
685 	int k;
686 
687 	d = isl_space_dim(space, isl_dim_in);
688 	nparam = isl_space_dim(space, isl_dim_param);
689 	total = isl_space_dim(space, isl_dim_all);
690 	if (d < 0 || nparam < 0 || total < 0)
691 		space = isl_space_free(space);
692 	bmap = isl_basic_map_alloc_space(space, 0, 1, 1);
693 	k = isl_basic_map_alloc_equality(bmap);
694 	if (k < 0)
695 		goto error;
696 	isl_seq_clr(bmap->eq[k], 1 + total);
697 	isl_int_set_si(bmap->eq[k][1 + param], -1);
698 	isl_int_set_si(bmap->eq[k][1 + nparam + d - 1], -1);
699 	isl_int_set_si(bmap->eq[k][1 + nparam + d + d - 1], 1);
700 
701 	k = isl_basic_map_alloc_inequality(bmap);
702 	if (k < 0)
703 		goto error;
704 	isl_seq_clr(bmap->ineq[k], 1 + total);
705 	isl_int_set_si(bmap->ineq[k][1 + param], 1);
706 	isl_int_set_si(bmap->ineq[k][0], -1);
707 
708 	bmap = isl_basic_map_finalize(bmap);
709 	return isl_map_from_basic_map(bmap);
710 error:
711 	isl_basic_map_free(bmap);
712 	return NULL;
713 }
714 
715 /* Check whether "path" is acyclic, where the last coordinates of domain
716  * and range of path encode the number of steps taken.
717  * That is, check whether
718  *
719  *	{ d | d = y - x and (x,y) in path }
720  *
721  * does not contain any element with positive last coordinate (positive length)
722  * and zero remaining coordinates (cycle).
723  */
is_acyclic(__isl_take isl_map * path)724 static isl_bool is_acyclic(__isl_take isl_map *path)
725 {
726 	int i;
727 	isl_bool acyclic;
728 	isl_size dim;
729 	struct isl_set *delta;
730 
731 	delta = isl_map_deltas(path);
732 	dim = isl_set_dim(delta, isl_dim_set);
733 	if (dim < 0)
734 		delta = isl_set_free(delta);
735 	for (i = 0; i < dim; ++i) {
736 		if (i == dim -1)
737 			delta = isl_set_lower_bound_si(delta, isl_dim_set, i, 1);
738 		else
739 			delta = isl_set_fix_si(delta, isl_dim_set, i, 0);
740 	}
741 
742 	acyclic = isl_set_is_empty(delta);
743 	isl_set_free(delta);
744 
745 	return acyclic;
746 }
747 
748 /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D
749  * and a dimension specification (Z^{n+1} -> Z^{n+1}),
750  * construct a map that is an overapproximation of the map
751  * that takes an element from the space D \times Z to another
752  * element from the same space, such that the first n coordinates of the
753  * difference between them is a sum of differences between images
754  * and pre-images in one of the R_i and such that the last coordinate
755  * is equal to the number of steps taken.
756  * That is, let
757  *
758  *	\Delta_i = { y - x | (x, y) in R_i }
759  *
760  * then the constructed map is an overapproximation of
761  *
762  *	{ (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
763  *				d = (\sum_i k_i \delta_i, \sum_i k_i) }
764  *
765  * The elements of the singleton \Delta_i's are collected as the
766  * rows of the steps matrix.  For all these \Delta_i's together,
767  * a single path is constructed.
768  * For each of the other \Delta_i's, we compute an overapproximation
769  * of the paths along elements of \Delta_i.
770  * Since each of these paths performs an addition, composition is
771  * symmetric and we can simply compose all resulting paths in any order.
772  */
construct_extended_path(__isl_take isl_space * space,__isl_keep isl_map * map,int * project)773 static __isl_give isl_map *construct_extended_path(__isl_take isl_space *space,
774 	__isl_keep isl_map *map, int *project)
775 {
776 	struct isl_mat *steps = NULL;
777 	struct isl_map *path = NULL;
778 	isl_size d;
779 	int i, j, n;
780 
781 	d = isl_map_dim(map, isl_dim_in);
782 	if (d < 0)
783 		goto error;
784 
785 	path = isl_map_identity(isl_space_copy(space));
786 
787 	steps = isl_mat_alloc(map->ctx, map->n, d);
788 	if (!steps)
789 		goto error;
790 
791 	n = 0;
792 	for (i = 0; i < map->n; ++i) {
793 		struct isl_basic_set *delta;
794 
795 		delta = isl_basic_map_deltas(isl_basic_map_copy(map->p[i]));
796 
797 		for (j = 0; j < d; ++j) {
798 			isl_bool fixed;
799 
800 			fixed = isl_basic_set_plain_dim_is_fixed(delta, j,
801 							    &steps->row[n][j]);
802 			if (fixed < 0) {
803 				isl_basic_set_free(delta);
804 				goto error;
805 			}
806 			if (!fixed)
807 				break;
808 		}
809 
810 
811 		if (j < d) {
812 			path = isl_map_apply_range(path,
813 				path_along_delta(isl_space_copy(space), delta));
814 			path = isl_map_coalesce(path);
815 		} else {
816 			isl_basic_set_free(delta);
817 			++n;
818 		}
819 	}
820 
821 	if (n > 0) {
822 		steps->n_row = n;
823 		path = isl_map_apply_range(path,
824 				path_along_steps(isl_space_copy(space), steps));
825 	}
826 
827 	if (project && *project) {
828 		*project = is_acyclic(isl_map_copy(path));
829 		if (*project < 0)
830 			goto error;
831 	}
832 
833 	isl_space_free(space);
834 	isl_mat_free(steps);
835 	return path;
836 error:
837 	isl_space_free(space);
838 	isl_mat_free(steps);
839 	isl_map_free(path);
840 	return NULL;
841 }
842 
isl_set_overlaps(__isl_keep isl_set * set1,__isl_keep isl_set * set2)843 static isl_bool isl_set_overlaps(__isl_keep isl_set *set1,
844 	__isl_keep isl_set *set2)
845 {
846 	return isl_bool_not(isl_set_is_disjoint(set1, set2));
847 }
848 
849 /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D
850  * and a dimension specification (Z^{n+1} -> Z^{n+1}),
851  * construct a map that is an overapproximation of the map
852  * that takes an element from the dom R \times Z to an
853  * element from ran R \times Z, such that the first n coordinates of the
854  * difference between them is a sum of differences between images
855  * and pre-images in one of the R_i and such that the last coordinate
856  * is equal to the number of steps taken.
857  * That is, let
858  *
859  *	\Delta_i = { y - x | (x, y) in R_i }
860  *
861  * then the constructed map is an overapproximation of
862  *
863  *	{ (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
864  *				d = (\sum_i k_i \delta_i, \sum_i k_i) and
865  *				x in dom R and x + d in ran R and
866  *				\sum_i k_i >= 1 }
867  */
construct_component(__isl_take isl_space * space,__isl_keep isl_map * map,isl_bool * exact,int project)868 static __isl_give isl_map *construct_component(__isl_take isl_space *space,
869 	__isl_keep isl_map *map, isl_bool *exact, int project)
870 {
871 	struct isl_set *domain = NULL;
872 	struct isl_set *range = NULL;
873 	struct isl_map *app = NULL;
874 	struct isl_map *path = NULL;
875 	isl_bool overlaps;
876 	int check;
877 
878 	domain = isl_map_domain(isl_map_copy(map));
879 	domain = isl_set_coalesce(domain);
880 	range = isl_map_range(isl_map_copy(map));
881 	range = isl_set_coalesce(range);
882 	overlaps = isl_set_overlaps(domain, range);
883 	if (overlaps < 0 || !overlaps) {
884 		isl_set_free(domain);
885 		isl_set_free(range);
886 		isl_space_free(space);
887 
888 		if (overlaps < 0)
889 			map = NULL;
890 		map = isl_map_copy(map);
891 		map = isl_map_add_dims(map, isl_dim_in, 1);
892 		map = isl_map_add_dims(map, isl_dim_out, 1);
893 		map = set_path_length(map, 1, 1);
894 		return map;
895 	}
896 	app = isl_map_from_domain_and_range(domain, range);
897 	app = isl_map_add_dims(app, isl_dim_in, 1);
898 	app = isl_map_add_dims(app, isl_dim_out, 1);
899 
900 	check = exact && *exact == isl_bool_true;
901 	path = construct_extended_path(isl_space_copy(space), map,
902 					check ? &project : NULL);
903 	app = isl_map_intersect(app, path);
904 
905 	if (check &&
906 	    (*exact = check_exactness(isl_map_copy(map), isl_map_copy(app),
907 				      project)) < 0)
908 		goto error;
909 
910 	isl_space_free(space);
911 	app = set_path_length(app, 0, 1);
912 	return app;
913 error:
914 	isl_space_free(space);
915 	isl_map_free(app);
916 	return NULL;
917 }
918 
919 /* Call construct_component and, if "project" is set, project out
920  * the final coordinates.
921  */
construct_projected_component(__isl_take isl_space * space,__isl_keep isl_map * map,isl_bool * exact,int project)922 static __isl_give isl_map *construct_projected_component(
923 	__isl_take isl_space *space,
924 	__isl_keep isl_map *map, isl_bool *exact, int project)
925 {
926 	isl_map *app;
927 	unsigned d;
928 
929 	if (!space)
930 		return NULL;
931 	d = isl_space_dim(space, isl_dim_in);
932 
933 	app = construct_component(space, map, exact, project);
934 	if (project) {
935 		app = isl_map_project_out(app, isl_dim_in, d - 1, 1);
936 		app = isl_map_project_out(app, isl_dim_out, d - 1, 1);
937 	}
938 	return app;
939 }
940 
941 /* Compute an extended version, i.e., with path lengths, of
942  * an overapproximation of the transitive closure of "bmap"
943  * with path lengths greater than or equal to zero and with
944  * domain and range equal to "dom".
945  */
q_closure(__isl_take isl_space * space,__isl_take isl_set * dom,__isl_keep isl_basic_map * bmap,isl_bool * exact)946 static __isl_give isl_map *q_closure(__isl_take isl_space *space,
947 	__isl_take isl_set *dom, __isl_keep isl_basic_map *bmap,
948 	isl_bool *exact)
949 {
950 	int project = 1;
951 	isl_map *path;
952 	isl_map *map;
953 	isl_map *app;
954 
955 	dom = isl_set_add_dims(dom, isl_dim_set, 1);
956 	app = isl_map_from_domain_and_range(dom, isl_set_copy(dom));
957 	map = isl_map_from_basic_map(isl_basic_map_copy(bmap));
958 	path = construct_extended_path(space, map, &project);
959 	app = isl_map_intersect(app, path);
960 
961 	if ((*exact = check_exactness(map, isl_map_copy(app), project)) < 0)
962 		goto error;
963 
964 	return app;
965 error:
966 	isl_map_free(app);
967 	return NULL;
968 }
969 
970 /* Check whether qc has any elements of length at least one
971  * with domain and/or range outside of dom and ran.
972  */
has_spurious_elements(__isl_keep isl_map * qc,__isl_keep isl_set * dom,__isl_keep isl_set * ran)973 static isl_bool has_spurious_elements(__isl_keep isl_map *qc,
974 	__isl_keep isl_set *dom, __isl_keep isl_set *ran)
975 {
976 	isl_set *s;
977 	isl_bool subset;
978 	isl_size d;
979 
980 	d = isl_map_dim(qc, isl_dim_in);
981 	if (d < 0 || !dom || !ran)
982 		return isl_bool_error;
983 
984 	qc = isl_map_copy(qc);
985 	qc = set_path_length(qc, 0, 1);
986 	qc = isl_map_project_out(qc, isl_dim_in, d - 1, 1);
987 	qc = isl_map_project_out(qc, isl_dim_out, d - 1, 1);
988 
989 	s = isl_map_domain(isl_map_copy(qc));
990 	subset = isl_set_is_subset(s, dom);
991 	isl_set_free(s);
992 	if (subset < 0)
993 		goto error;
994 	if (!subset) {
995 		isl_map_free(qc);
996 		return isl_bool_true;
997 	}
998 
999 	s = isl_map_range(qc);
1000 	subset = isl_set_is_subset(s, ran);
1001 	isl_set_free(s);
1002 
1003 	return isl_bool_not(subset);
1004 error:
1005 	isl_map_free(qc);
1006 	return isl_bool_error;
1007 }
1008 
1009 #define LEFT	2
1010 #define RIGHT	1
1011 
1012 /* For each basic map in "map", except i, check whether it combines
1013  * with the transitive closure that is reflexive on C combines
1014  * to the left and to the right.
1015  *
1016  * In particular, if
1017  *
1018  *	dom map_j \subseteq C
1019  *
1020  * then right[j] is set to 1.  Otherwise, if
1021  *
1022  *	ran map_i \cap dom map_j = \emptyset
1023  *
1024  * then right[j] is set to 0.  Otherwise, composing to the right
1025  * is impossible.
1026  *
1027  * Similar, for composing to the left, we have if
1028  *
1029  *	ran map_j \subseteq C
1030  *
1031  * then left[j] is set to 1.  Otherwise, if
1032  *
1033  *	dom map_i \cap ran map_j = \emptyset
1034  *
1035  * then left[j] is set to 0.  Otherwise, composing to the left
1036  * is impossible.
1037  *
1038  * The return value is or'd with LEFT if composing to the left
1039  * is possible and with RIGHT if composing to the right is possible.
1040  */
composability(__isl_keep isl_set * C,int i,isl_set ** dom,isl_set ** ran,int * left,int * right,__isl_keep isl_map * map)1041 static int composability(__isl_keep isl_set *C, int i,
1042 	isl_set **dom, isl_set **ran, int *left, int *right,
1043 	__isl_keep isl_map *map)
1044 {
1045 	int j;
1046 	int ok;
1047 
1048 	ok = LEFT | RIGHT;
1049 	for (j = 0; j < map->n && ok; ++j) {
1050 		isl_bool overlaps, subset;
1051 		if (j == i)
1052 			continue;
1053 
1054 		if (ok & RIGHT) {
1055 			if (!dom[j])
1056 				dom[j] = isl_set_from_basic_set(
1057 					isl_basic_map_domain(
1058 						isl_basic_map_copy(map->p[j])));
1059 			if (!dom[j])
1060 				return -1;
1061 			overlaps = isl_set_overlaps(ran[i], dom[j]);
1062 			if (overlaps < 0)
1063 				return -1;
1064 			if (!overlaps)
1065 				right[j] = 0;
1066 			else {
1067 				subset = isl_set_is_subset(dom[j], C);
1068 				if (subset < 0)
1069 					return -1;
1070 				if (subset)
1071 					right[j] = 1;
1072 				else
1073 					ok &= ~RIGHT;
1074 			}
1075 		}
1076 
1077 		if (ok & LEFT) {
1078 			if (!ran[j])
1079 				ran[j] = isl_set_from_basic_set(
1080 					isl_basic_map_range(
1081 						isl_basic_map_copy(map->p[j])));
1082 			if (!ran[j])
1083 				return -1;
1084 			overlaps = isl_set_overlaps(dom[i], ran[j]);
1085 			if (overlaps < 0)
1086 				return -1;
1087 			if (!overlaps)
1088 				left[j] = 0;
1089 			else {
1090 				subset = isl_set_is_subset(ran[j], C);
1091 				if (subset < 0)
1092 					return -1;
1093 				if (subset)
1094 					left[j] = 1;
1095 				else
1096 					ok &= ~LEFT;
1097 			}
1098 		}
1099 	}
1100 
1101 	return ok;
1102 }
1103 
anonymize(__isl_take isl_map * map)1104 static __isl_give isl_map *anonymize(__isl_take isl_map *map)
1105 {
1106 	map = isl_map_reset(map, isl_dim_in);
1107 	map = isl_map_reset(map, isl_dim_out);
1108 	return map;
1109 }
1110 
1111 /* Return a map that is a union of the basic maps in "map", except i,
1112  * composed to left and right with qc based on the entries of "left"
1113  * and "right".
1114  */
compose(__isl_keep isl_map * map,int i,__isl_take isl_map * qc,int * left,int * right)1115 static __isl_give isl_map *compose(__isl_keep isl_map *map, int i,
1116 	__isl_take isl_map *qc, int *left, int *right)
1117 {
1118 	int j;
1119 	isl_map *comp;
1120 
1121 	comp = isl_map_empty(isl_map_get_space(map));
1122 	for (j = 0; j < map->n; ++j) {
1123 		isl_map *map_j;
1124 
1125 		if (j == i)
1126 			continue;
1127 
1128 		map_j = isl_map_from_basic_map(isl_basic_map_copy(map->p[j]));
1129 		map_j = anonymize(map_j);
1130 		if (left && left[j])
1131 			map_j = isl_map_apply_range(map_j, isl_map_copy(qc));
1132 		if (right && right[j])
1133 			map_j = isl_map_apply_range(isl_map_copy(qc), map_j);
1134 		comp = isl_map_union(comp, map_j);
1135 	}
1136 
1137 	comp = isl_map_compute_divs(comp);
1138 	comp = isl_map_coalesce(comp);
1139 
1140 	isl_map_free(qc);
1141 
1142 	return comp;
1143 }
1144 
1145 /* Compute the transitive closure of "map" incrementally by
1146  * computing
1147  *
1148  *	map_i^+ \cup qc^+
1149  *
1150  * or
1151  *
1152  *	map_i^+ \cup ((id \cup map_i^) \circ qc^+)
1153  *
1154  * or
1155  *
1156  *	map_i^+ \cup (qc^+ \circ (id \cup map_i^))
1157  *
1158  * depending on whether left or right are NULL.
1159  */
compute_incremental(__isl_take isl_space * space,__isl_keep isl_map * map,int i,__isl_take isl_map * qc,int * left,int * right,isl_bool * exact)1160 static __isl_give isl_map *compute_incremental(
1161 	__isl_take isl_space *space, __isl_keep isl_map *map,
1162 	int i, __isl_take isl_map *qc, int *left, int *right, isl_bool *exact)
1163 {
1164 	isl_map *map_i;
1165 	isl_map *tc;
1166 	isl_map *rtc = NULL;
1167 
1168 	if (!map)
1169 		goto error;
1170 	isl_assert(map->ctx, left || right, goto error);
1171 
1172 	map_i = isl_map_from_basic_map(isl_basic_map_copy(map->p[i]));
1173 	tc = construct_projected_component(isl_space_copy(space), map_i,
1174 						exact, 1);
1175 	isl_map_free(map_i);
1176 
1177 	if (*exact)
1178 		qc = isl_map_transitive_closure(qc, exact);
1179 
1180 	if (!*exact) {
1181 		isl_space_free(space);
1182 		isl_map_free(tc);
1183 		isl_map_free(qc);
1184 		return isl_map_universe(isl_map_get_space(map));
1185 	}
1186 
1187 	if (!left || !right)
1188 		rtc = isl_map_union(isl_map_copy(tc),
1189 				    isl_map_identity(isl_map_get_space(tc)));
1190 	if (!right)
1191 		qc = isl_map_apply_range(rtc, qc);
1192 	if (!left)
1193 		qc = isl_map_apply_range(qc, rtc);
1194 	qc = isl_map_union(tc, qc);
1195 
1196 	isl_space_free(space);
1197 
1198 	return qc;
1199 error:
1200 	isl_space_free(space);
1201 	isl_map_free(qc);
1202 	return NULL;
1203 }
1204 
1205 /* Given a map "map", try to find a basic map such that
1206  * map^+ can be computed as
1207  *
1208  * map^+ = map_i^+ \cup
1209  *    \bigcup_j ((map_i^+ \cup Id_C)^+ \circ map_j \circ (map_i^+ \cup Id_C))^+
1210  *
1211  * with C the simple hull of the domain and range of the input map.
1212  * map_i^ \cup Id_C is computed by allowing the path lengths to be zero
1213  * and by intersecting domain and range with C.
1214  * Of course, we need to check that this is actually equal to map_i^ \cup Id_C.
1215  * Also, we only use the incremental computation if all the transitive
1216  * closures are exact and if the number of basic maps in the union,
1217  * after computing the integer divisions, is smaller than the number
1218  * of basic maps in the input map.
1219  */
incremental_on_entire_domain(__isl_keep isl_space * space,__isl_keep isl_map * map,isl_set ** dom,isl_set ** ran,int * left,int * right,__isl_give isl_map ** res)1220 static isl_bool incremental_on_entire_domain(__isl_keep isl_space *space,
1221 	__isl_keep isl_map *map,
1222 	isl_set **dom, isl_set **ran, int *left, int *right,
1223 	__isl_give isl_map **res)
1224 {
1225 	int i;
1226 	isl_set *C;
1227 	isl_size d;
1228 
1229 	*res = NULL;
1230 
1231 	d = isl_map_dim(map, isl_dim_in);
1232 	if (d < 0)
1233 		return isl_bool_error;
1234 
1235 	C = isl_set_union(isl_map_domain(isl_map_copy(map)),
1236 			  isl_map_range(isl_map_copy(map)));
1237 	C = isl_set_from_basic_set(isl_set_simple_hull(C));
1238 	if (!C)
1239 		return isl_bool_error;
1240 	if (C->n != 1) {
1241 		isl_set_free(C);
1242 		return isl_bool_false;
1243 	}
1244 
1245 	for (i = 0; i < map->n; ++i) {
1246 		isl_map *qc;
1247 		isl_bool exact_i;
1248 		isl_bool spurious;
1249 		int j;
1250 		dom[i] = isl_set_from_basic_set(isl_basic_map_domain(
1251 					isl_basic_map_copy(map->p[i])));
1252 		ran[i] = isl_set_from_basic_set(isl_basic_map_range(
1253 					isl_basic_map_copy(map->p[i])));
1254 		qc = q_closure(isl_space_copy(space), isl_set_copy(C),
1255 				map->p[i], &exact_i);
1256 		if (!qc)
1257 			goto error;
1258 		if (!exact_i) {
1259 			isl_map_free(qc);
1260 			continue;
1261 		}
1262 		spurious = has_spurious_elements(qc, dom[i], ran[i]);
1263 		if (spurious) {
1264 			isl_map_free(qc);
1265 			if (spurious < 0)
1266 				goto error;
1267 			continue;
1268 		}
1269 		qc = isl_map_project_out(qc, isl_dim_in, d, 1);
1270 		qc = isl_map_project_out(qc, isl_dim_out, d, 1);
1271 		qc = isl_map_compute_divs(qc);
1272 		for (j = 0; j < map->n; ++j)
1273 			left[j] = right[j] = 1;
1274 		qc = compose(map, i, qc, left, right);
1275 		if (!qc)
1276 			goto error;
1277 		if (qc->n >= map->n) {
1278 			isl_map_free(qc);
1279 			continue;
1280 		}
1281 		*res = compute_incremental(isl_space_copy(space), map, i, qc,
1282 				left, right, &exact_i);
1283 		if (!*res)
1284 			goto error;
1285 		if (exact_i)
1286 			break;
1287 		isl_map_free(*res);
1288 		*res = NULL;
1289 	}
1290 
1291 	isl_set_free(C);
1292 
1293 	return isl_bool_ok(*res != NULL);
1294 error:
1295 	isl_set_free(C);
1296 	return isl_bool_error;
1297 }
1298 
1299 /* Try and compute the transitive closure of "map" as
1300  *
1301  * map^+ = map_i^+ \cup
1302  *    \bigcup_j ((map_i^+ \cup Id_C)^+ \circ map_j \circ (map_i^+ \cup Id_C))^+
1303  *
1304  * with C either the simple hull of the domain and range of the entire
1305  * map or the simple hull of domain and range of map_i.
1306  */
incremental_closure(__isl_take isl_space * space,__isl_keep isl_map * map,isl_bool * exact,int project)1307 static __isl_give isl_map *incremental_closure(__isl_take isl_space *space,
1308 	__isl_keep isl_map *map, isl_bool *exact, int project)
1309 {
1310 	int i;
1311 	isl_set **dom = NULL;
1312 	isl_set **ran = NULL;
1313 	int *left = NULL;
1314 	int *right = NULL;
1315 	isl_set *C;
1316 	isl_size d;
1317 	isl_map *res = NULL;
1318 
1319 	if (!project)
1320 		return construct_projected_component(space, map, exact,
1321 							project);
1322 
1323 	if (!map)
1324 		goto error;
1325 	if (map->n <= 1)
1326 		return construct_projected_component(space, map, exact,
1327 							project);
1328 
1329 	d = isl_map_dim(map, isl_dim_in);
1330 	if (d < 0)
1331 		goto error;
1332 
1333 	dom = isl_calloc_array(map->ctx, isl_set *, map->n);
1334 	ran = isl_calloc_array(map->ctx, isl_set *, map->n);
1335 	left = isl_calloc_array(map->ctx, int, map->n);
1336 	right = isl_calloc_array(map->ctx, int, map->n);
1337 	if (!ran || !dom || !left || !right)
1338 		goto error;
1339 
1340 	if (incremental_on_entire_domain(space, map, dom, ran, left, right,
1341 					&res) < 0)
1342 		goto error;
1343 
1344 	for (i = 0; !res && i < map->n; ++i) {
1345 		isl_map *qc;
1346 		int comp;
1347 		isl_bool exact_i, spurious;
1348 		if (!dom[i])
1349 			dom[i] = isl_set_from_basic_set(
1350 					isl_basic_map_domain(
1351 						isl_basic_map_copy(map->p[i])));
1352 		if (!dom[i])
1353 			goto error;
1354 		if (!ran[i])
1355 			ran[i] = isl_set_from_basic_set(
1356 					isl_basic_map_range(
1357 						isl_basic_map_copy(map->p[i])));
1358 		if (!ran[i])
1359 			goto error;
1360 		C = isl_set_union(isl_set_copy(dom[i]),
1361 				      isl_set_copy(ran[i]));
1362 		C = isl_set_from_basic_set(isl_set_simple_hull(C));
1363 		if (!C)
1364 			goto error;
1365 		if (C->n != 1) {
1366 			isl_set_free(C);
1367 			continue;
1368 		}
1369 		comp = composability(C, i, dom, ran, left, right, map);
1370 		if (!comp || comp < 0) {
1371 			isl_set_free(C);
1372 			if (comp < 0)
1373 				goto error;
1374 			continue;
1375 		}
1376 		qc = q_closure(isl_space_copy(space), C, map->p[i], &exact_i);
1377 		if (!qc)
1378 			goto error;
1379 		if (!exact_i) {
1380 			isl_map_free(qc);
1381 			continue;
1382 		}
1383 		spurious = has_spurious_elements(qc, dom[i], ran[i]);
1384 		if (spurious) {
1385 			isl_map_free(qc);
1386 			if (spurious < 0)
1387 				goto error;
1388 			continue;
1389 		}
1390 		qc = isl_map_project_out(qc, isl_dim_in, d, 1);
1391 		qc = isl_map_project_out(qc, isl_dim_out, d, 1);
1392 		qc = isl_map_compute_divs(qc);
1393 		qc = compose(map, i, qc, (comp & LEFT) ? left : NULL,
1394 				(comp & RIGHT) ? right : NULL);
1395 		if (!qc)
1396 			goto error;
1397 		if (qc->n >= map->n) {
1398 			isl_map_free(qc);
1399 			continue;
1400 		}
1401 		res = compute_incremental(isl_space_copy(space), map, i, qc,
1402 				(comp & LEFT) ? left : NULL,
1403 				(comp & RIGHT) ? right : NULL, &exact_i);
1404 		if (!res)
1405 			goto error;
1406 		if (exact_i)
1407 			break;
1408 		isl_map_free(res);
1409 		res = NULL;
1410 	}
1411 
1412 	for (i = 0; i < map->n; ++i) {
1413 		isl_set_free(dom[i]);
1414 		isl_set_free(ran[i]);
1415 	}
1416 	free(dom);
1417 	free(ran);
1418 	free(left);
1419 	free(right);
1420 
1421 	if (res) {
1422 		isl_space_free(space);
1423 		return res;
1424 	}
1425 
1426 	return construct_projected_component(space, map, exact, project);
1427 error:
1428 	if (dom)
1429 		for (i = 0; i < map->n; ++i)
1430 			isl_set_free(dom[i]);
1431 	free(dom);
1432 	if (ran)
1433 		for (i = 0; i < map->n; ++i)
1434 			isl_set_free(ran[i]);
1435 	free(ran);
1436 	free(left);
1437 	free(right);
1438 	isl_space_free(space);
1439 	return NULL;
1440 }
1441 
1442 /* Given an array of sets "set", add "dom" at position "pos"
1443  * and search for elements at earlier positions that overlap with "dom".
1444  * If any can be found, then merge all of them, together with "dom", into
1445  * a single set and assign the union to the first in the array,
1446  * which becomes the new group leader for all groups involved in the merge.
1447  * During the search, we only consider group leaders, i.e., those with
1448  * group[i] = i, as the other sets have already been combined
1449  * with one of the group leaders.
1450  */
merge(isl_set ** set,int * group,__isl_take isl_set * dom,int pos)1451 static int merge(isl_set **set, int *group, __isl_take isl_set *dom, int pos)
1452 {
1453 	int i;
1454 
1455 	group[pos] = pos;
1456 	set[pos] = isl_set_copy(dom);
1457 
1458 	for (i = pos - 1; i >= 0; --i) {
1459 		isl_bool o;
1460 
1461 		if (group[i] != i)
1462 			continue;
1463 
1464 		o = isl_set_overlaps(set[i], dom);
1465 		if (o < 0)
1466 			goto error;
1467 		if (!o)
1468 			continue;
1469 
1470 		set[i] = isl_set_union(set[i], set[group[pos]]);
1471 		set[group[pos]] = NULL;
1472 		if (!set[i])
1473 			goto error;
1474 		group[group[pos]] = i;
1475 		group[pos] = i;
1476 	}
1477 
1478 	isl_set_free(dom);
1479 	return 0;
1480 error:
1481 	isl_set_free(dom);
1482 	return -1;
1483 }
1484 
1485 /* Construct a map [x] -> [x+1], with parameters prescribed by "space".
1486  */
increment(__isl_take isl_space * space)1487 static __isl_give isl_map *increment(__isl_take isl_space *space)
1488 {
1489 	int k;
1490 	isl_basic_map *bmap;
1491 	isl_size total;
1492 
1493 	space = isl_space_set_from_params(space);
1494 	space = isl_space_add_dims(space, isl_dim_set, 1);
1495 	space = isl_space_map_from_set(space);
1496 	bmap = isl_basic_map_alloc_space(space, 0, 1, 0);
1497 	total = isl_basic_map_dim(bmap, isl_dim_all);
1498 	k = isl_basic_map_alloc_equality(bmap);
1499 	if (total < 0 || k < 0)
1500 		goto error;
1501 	isl_seq_clr(bmap->eq[k], 1 + total);
1502 	isl_int_set_si(bmap->eq[k][0], 1);
1503 	isl_int_set_si(bmap->eq[k][isl_basic_map_offset(bmap, isl_dim_in)], 1);
1504 	isl_int_set_si(bmap->eq[k][isl_basic_map_offset(bmap, isl_dim_out)], -1);
1505 	return isl_map_from_basic_map(bmap);
1506 error:
1507 	isl_basic_map_free(bmap);
1508 	return NULL;
1509 }
1510 
1511 /* Replace each entry in the n by n grid of maps by the cross product
1512  * with the relation { [i] -> [i + 1] }.
1513  */
add_length(__isl_keep isl_map * map,isl_map *** grid,int n)1514 static isl_stat add_length(__isl_keep isl_map *map, isl_map ***grid, int n)
1515 {
1516 	int i, j;
1517 	isl_space *space;
1518 	isl_map *step;
1519 
1520 	space = isl_space_params(isl_map_get_space(map));
1521 	step = increment(space);
1522 
1523 	if (!step)
1524 		return isl_stat_error;
1525 
1526 	for (i = 0; i < n; ++i)
1527 		for (j = 0; j < n; ++j)
1528 			grid[i][j] = isl_map_product(grid[i][j],
1529 						     isl_map_copy(step));
1530 
1531 	isl_map_free(step);
1532 
1533 	return isl_stat_ok;
1534 }
1535 
1536 /* The core of the Floyd-Warshall algorithm.
1537  * Updates the given n x x matrix of relations in place.
1538  *
1539  * The algorithm iterates over all vertices.  In each step, the whole
1540  * matrix is updated to include all paths that go to the current vertex,
1541  * possibly stay there a while (including passing through earlier vertices)
1542  * and then come back.  At the start of each iteration, the diagonal
1543  * element corresponding to the current vertex is replaced by its
1544  * transitive closure to account for all indirect paths that stay
1545  * in the current vertex.
1546  */
floyd_warshall_iterate(isl_map *** grid,int n,isl_bool * exact)1547 static void floyd_warshall_iterate(isl_map ***grid, int n, isl_bool *exact)
1548 {
1549 	int r, p, q;
1550 
1551 	for (r = 0; r < n; ++r) {
1552 		isl_bool r_exact;
1553 		int check = exact && *exact == isl_bool_true;
1554 		grid[r][r] = isl_map_transitive_closure(grid[r][r],
1555 				check ? &r_exact : NULL);
1556 		if (check && !r_exact)
1557 			*exact = isl_bool_false;
1558 
1559 		for (p = 0; p < n; ++p)
1560 			for (q = 0; q < n; ++q) {
1561 				isl_map *loop;
1562 				if (p == r && q == r)
1563 					continue;
1564 				loop = isl_map_apply_range(
1565 						isl_map_copy(grid[p][r]),
1566 						isl_map_copy(grid[r][q]));
1567 				grid[p][q] = isl_map_union(grid[p][q], loop);
1568 				loop = isl_map_apply_range(
1569 						isl_map_copy(grid[p][r]),
1570 					isl_map_apply_range(
1571 						isl_map_copy(grid[r][r]),
1572 						isl_map_copy(grid[r][q])));
1573 				grid[p][q] = isl_map_union(grid[p][q], loop);
1574 				grid[p][q] = isl_map_coalesce(grid[p][q]);
1575 			}
1576 	}
1577 }
1578 
1579 /* Given a partition of the domains and ranges of the basic maps in "map",
1580  * apply the Floyd-Warshall algorithm with the elements in the partition
1581  * as vertices.
1582  *
1583  * In particular, there are "n" elements in the partition and "group" is
1584  * an array of length 2 * map->n with entries in [0,n-1].
1585  *
1586  * We first construct a matrix of relations based on the partition information,
1587  * apply Floyd-Warshall on this matrix of relations and then take the
1588  * union of all entries in the matrix as the final result.
1589  *
1590  * If we are actually computing the power instead of the transitive closure,
1591  * i.e., when "project" is not set, then the result should have the
1592  * path lengths encoded as the difference between an extra pair of
1593  * coordinates.  We therefore apply the nested transitive closures
1594  * to relations that include these lengths.  In particular, we replace
1595  * the input relation by the cross product with the unit length relation
1596  * { [i] -> [i + 1] }.
1597  */
floyd_warshall_with_groups(__isl_take isl_space * space,__isl_keep isl_map * map,isl_bool * exact,int project,int * group,int n)1598 static __isl_give isl_map *floyd_warshall_with_groups(
1599 	__isl_take isl_space *space, __isl_keep isl_map *map,
1600 	isl_bool *exact, int project, int *group, int n)
1601 {
1602 	int i, j, k;
1603 	isl_map ***grid = NULL;
1604 	isl_map *app;
1605 
1606 	if (!map)
1607 		goto error;
1608 
1609 	if (n == 1) {
1610 		free(group);
1611 		return incremental_closure(space, map, exact, project);
1612 	}
1613 
1614 	grid = isl_calloc_array(map->ctx, isl_map **, n);
1615 	if (!grid)
1616 		goto error;
1617 	for (i = 0; i < n; ++i) {
1618 		grid[i] = isl_calloc_array(map->ctx, isl_map *, n);
1619 		if (!grid[i])
1620 			goto error;
1621 		for (j = 0; j < n; ++j)
1622 			grid[i][j] = isl_map_empty(isl_map_get_space(map));
1623 	}
1624 
1625 	for (k = 0; k < map->n; ++k) {
1626 		i = group[2 * k];
1627 		j = group[2 * k + 1];
1628 		grid[i][j] = isl_map_union(grid[i][j],
1629 				isl_map_from_basic_map(
1630 					isl_basic_map_copy(map->p[k])));
1631 	}
1632 
1633 	if (!project && add_length(map, grid, n) < 0)
1634 		goto error;
1635 
1636 	floyd_warshall_iterate(grid, n, exact);
1637 
1638 	app = isl_map_empty(isl_map_get_space(grid[0][0]));
1639 
1640 	for (i = 0; i < n; ++i) {
1641 		for (j = 0; j < n; ++j)
1642 			app = isl_map_union(app, grid[i][j]);
1643 		free(grid[i]);
1644 	}
1645 	free(grid);
1646 
1647 	free(group);
1648 	isl_space_free(space);
1649 
1650 	return app;
1651 error:
1652 	if (grid)
1653 		for (i = 0; i < n; ++i) {
1654 			if (!grid[i])
1655 				continue;
1656 			for (j = 0; j < n; ++j)
1657 				isl_map_free(grid[i][j]);
1658 			free(grid[i]);
1659 		}
1660 	free(grid);
1661 	free(group);
1662 	isl_space_free(space);
1663 	return NULL;
1664 }
1665 
1666 /* Partition the domains and ranges of the n basic relations in list
1667  * into disjoint cells.
1668  *
1669  * To find the partition, we simply consider all of the domains
1670  * and ranges in turn and combine those that overlap.
1671  * "set" contains the partition elements and "group" indicates
1672  * to which partition element a given domain or range belongs.
1673  * The domain of basic map i corresponds to element 2 * i in these arrays,
1674  * while the domain corresponds to element 2 * i + 1.
1675  * During the construction group[k] is either equal to k,
1676  * in which case set[k] contains the union of all the domains and
1677  * ranges in the corresponding group, or is equal to some l < k,
1678  * with l another domain or range in the same group.
1679  */
setup_groups(isl_ctx * ctx,__isl_keep isl_basic_map ** list,int n,isl_set *** set,int * n_group)1680 static int *setup_groups(isl_ctx *ctx, __isl_keep isl_basic_map **list, int n,
1681 	isl_set ***set, int *n_group)
1682 {
1683 	int i;
1684 	int *group = NULL;
1685 	int g;
1686 
1687 	*set = isl_calloc_array(ctx, isl_set *, 2 * n);
1688 	group = isl_alloc_array(ctx, int, 2 * n);
1689 
1690 	if (!*set || !group)
1691 		goto error;
1692 
1693 	for (i = 0; i < n; ++i) {
1694 		isl_set *dom;
1695 		dom = isl_set_from_basic_set(isl_basic_map_domain(
1696 				isl_basic_map_copy(list[i])));
1697 		if (merge(*set, group, dom, 2 * i) < 0)
1698 			goto error;
1699 		dom = isl_set_from_basic_set(isl_basic_map_range(
1700 				isl_basic_map_copy(list[i])));
1701 		if (merge(*set, group, dom, 2 * i + 1) < 0)
1702 			goto error;
1703 	}
1704 
1705 	g = 0;
1706 	for (i = 0; i < 2 * n; ++i)
1707 		if (group[i] == i) {
1708 			if (g != i) {
1709 				(*set)[g] = (*set)[i];
1710 				(*set)[i] = NULL;
1711 			}
1712 			group[i] = g++;
1713 		} else
1714 			group[i] = group[group[i]];
1715 
1716 	*n_group = g;
1717 
1718 	return group;
1719 error:
1720 	if (*set) {
1721 		for (i = 0; i < 2 * n; ++i)
1722 			isl_set_free((*set)[i]);
1723 		free(*set);
1724 		*set = NULL;
1725 	}
1726 	free(group);
1727 	return NULL;
1728 }
1729 
1730 /* Check if the domains and ranges of the basic maps in "map" can
1731  * be partitioned, and if so, apply Floyd-Warshall on the elements
1732  * of the partition.  Note that we also apply this algorithm
1733  * if we want to compute the power, i.e., when "project" is not set.
1734  * However, the results are unlikely to be exact since the recursive
1735  * calls inside the Floyd-Warshall algorithm typically result in
1736  * non-linear path lengths quite quickly.
1737  */
floyd_warshall(__isl_take isl_space * space,__isl_keep isl_map * map,isl_bool * exact,int project)1738 static __isl_give isl_map *floyd_warshall(__isl_take isl_space *space,
1739 	__isl_keep isl_map *map, isl_bool *exact, int project)
1740 {
1741 	int i;
1742 	isl_set **set = NULL;
1743 	int *group = NULL;
1744 	int n;
1745 
1746 	if (!map)
1747 		goto error;
1748 	if (map->n <= 1)
1749 		return incremental_closure(space, map, exact, project);
1750 
1751 	group = setup_groups(map->ctx, map->p, map->n, &set, &n);
1752 	if (!group)
1753 		goto error;
1754 
1755 	for (i = 0; i < 2 * map->n; ++i)
1756 		isl_set_free(set[i]);
1757 
1758 	free(set);
1759 
1760 	return floyd_warshall_with_groups(space, map, exact, project, group, n);
1761 error:
1762 	isl_space_free(space);
1763 	return NULL;
1764 }
1765 
1766 /* Structure for representing the nodes of the graph of which
1767  * strongly connected components are being computed.
1768  *
1769  * list contains the actual nodes
1770  * check_closed is set if we may have used the fact that
1771  * a pair of basic maps can be interchanged
1772  */
1773 struct isl_tc_follows_data {
1774 	isl_basic_map **list;
1775 	int check_closed;
1776 };
1777 
1778 /* Check whether in the computation of the transitive closure
1779  * "list[i]" (R_1) should follow (or be part of the same component as)
1780  * "list[j]" (R_2).
1781  *
1782  * That is check whether
1783  *
1784  *	R_1 \circ R_2
1785  *
1786  * is a subset of
1787  *
1788  *	R_2 \circ R_1
1789  *
1790  * If so, then there is no reason for R_1 to immediately follow R_2
1791  * in any path.
1792  *
1793  * *check_closed is set if the subset relation holds while
1794  * R_1 \circ R_2 is not empty.
1795  */
basic_map_follows(int i,int j,void * user)1796 static isl_bool basic_map_follows(int i, int j, void *user)
1797 {
1798 	struct isl_tc_follows_data *data = user;
1799 	struct isl_map *map12 = NULL;
1800 	struct isl_map *map21 = NULL;
1801 	isl_bool applies, subset;
1802 
1803 	applies = isl_basic_map_applies_range(data->list[j], data->list[i]);
1804 	if (applies < 0)
1805 		return isl_bool_error;
1806 	if (!applies)
1807 		return isl_bool_false;
1808 
1809 	map21 = isl_map_from_basic_map(
1810 			isl_basic_map_apply_range(
1811 				isl_basic_map_copy(data->list[j]),
1812 				isl_basic_map_copy(data->list[i])));
1813 	subset = isl_map_is_empty(map21);
1814 	if (subset < 0)
1815 		goto error;
1816 	if (subset) {
1817 		isl_map_free(map21);
1818 		return isl_bool_false;
1819 	}
1820 
1821 	if (!isl_basic_map_is_transformation(data->list[i]) ||
1822 	    !isl_basic_map_is_transformation(data->list[j])) {
1823 		isl_map_free(map21);
1824 		return isl_bool_true;
1825 	}
1826 
1827 	map12 = isl_map_from_basic_map(
1828 			isl_basic_map_apply_range(
1829 				isl_basic_map_copy(data->list[i]),
1830 				isl_basic_map_copy(data->list[j])));
1831 
1832 	subset = isl_map_is_subset(map21, map12);
1833 
1834 	isl_map_free(map12);
1835 	isl_map_free(map21);
1836 
1837 	if (subset)
1838 		data->check_closed = 1;
1839 
1840 	return isl_bool_not(subset);
1841 error:
1842 	isl_map_free(map21);
1843 	return isl_bool_error;
1844 }
1845 
1846 /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D
1847  * and a dimension specification (Z^{n+1} -> Z^{n+1}),
1848  * construct a map that is an overapproximation of the map
1849  * that takes an element from the dom R \times Z to an
1850  * element from ran R \times Z, such that the first n coordinates of the
1851  * difference between them is a sum of differences between images
1852  * and pre-images in one of the R_i and such that the last coordinate
1853  * is equal to the number of steps taken.
1854  * If "project" is set, then these final coordinates are not included,
1855  * i.e., a relation of type Z^n -> Z^n is returned.
1856  * That is, let
1857  *
1858  *	\Delta_i = { y - x | (x, y) in R_i }
1859  *
1860  * then the constructed map is an overapproximation of
1861  *
1862  *	{ (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
1863  *				d = (\sum_i k_i \delta_i, \sum_i k_i) and
1864  *				x in dom R and x + d in ran R }
1865  *
1866  * or
1867  *
1868  *	{ (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
1869  *				d = (\sum_i k_i \delta_i) and
1870  *				x in dom R and x + d in ran R }
1871  *
1872  * if "project" is set.
1873  *
1874  * We first split the map into strongly connected components, perform
1875  * the above on each component and then join the results in the correct
1876  * order, at each join also taking in the union of both arguments
1877  * to allow for paths that do not go through one of the two arguments.
1878  */
construct_power_components(__isl_take isl_space * space,__isl_keep isl_map * map,isl_bool * exact,int project)1879 static __isl_give isl_map *construct_power_components(
1880 	__isl_take isl_space *space, __isl_keep isl_map *map, isl_bool *exact,
1881 	int project)
1882 {
1883 	int i, n, c;
1884 	struct isl_map *path = NULL;
1885 	struct isl_tc_follows_data data;
1886 	struct isl_tarjan_graph *g = NULL;
1887 	isl_bool *orig_exact;
1888 	isl_bool local_exact;
1889 
1890 	if (!map)
1891 		goto error;
1892 	if (map->n <= 1)
1893 		return floyd_warshall(space, map, exact, project);
1894 
1895 	data.list = map->p;
1896 	data.check_closed = 0;
1897 	g = isl_tarjan_graph_init(map->ctx, map->n, &basic_map_follows, &data);
1898 	if (!g)
1899 		goto error;
1900 
1901 	orig_exact = exact;
1902 	if (data.check_closed && !exact)
1903 		exact = &local_exact;
1904 
1905 	c = 0;
1906 	i = 0;
1907 	n = map->n;
1908 	if (project)
1909 		path = isl_map_empty(isl_map_get_space(map));
1910 	else
1911 		path = isl_map_empty(isl_space_copy(space));
1912 	path = anonymize(path);
1913 	while (n) {
1914 		struct isl_map *comp;
1915 		isl_map *path_comp, *path_comb;
1916 		comp = isl_map_alloc_space(isl_map_get_space(map), n, 0);
1917 		while (g->order[i] != -1) {
1918 			comp = isl_map_add_basic_map(comp,
1919 				    isl_basic_map_copy(map->p[g->order[i]]));
1920 			--n;
1921 			++i;
1922 		}
1923 		path_comp = floyd_warshall(isl_space_copy(space),
1924 						comp, exact, project);
1925 		path_comp = anonymize(path_comp);
1926 		path_comb = isl_map_apply_range(isl_map_copy(path),
1927 						isl_map_copy(path_comp));
1928 		path = isl_map_union(path, path_comp);
1929 		path = isl_map_union(path, path_comb);
1930 		isl_map_free(comp);
1931 		++i;
1932 		++c;
1933 	}
1934 
1935 	if (c > 1 && data.check_closed && !*exact) {
1936 		isl_bool closed;
1937 
1938 		closed = isl_map_is_transitively_closed(path);
1939 		if (closed < 0)
1940 			goto error;
1941 		if (!closed) {
1942 			isl_tarjan_graph_free(g);
1943 			isl_map_free(path);
1944 			return floyd_warshall(space, map, orig_exact, project);
1945 		}
1946 	}
1947 
1948 	isl_tarjan_graph_free(g);
1949 	isl_space_free(space);
1950 
1951 	return path;
1952 error:
1953 	isl_tarjan_graph_free(g);
1954 	isl_space_free(space);
1955 	isl_map_free(path);
1956 	return NULL;
1957 }
1958 
1959 /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D,
1960  * construct a map that is an overapproximation of the map
1961  * that takes an element from the space D to another
1962  * element from the same space, such that the difference between
1963  * them is a strictly positive sum of differences between images
1964  * and pre-images in one of the R_i.
1965  * The number of differences in the sum is equated to parameter "param".
1966  * That is, let
1967  *
1968  *	\Delta_i = { y - x | (x, y) in R_i }
1969  *
1970  * then the constructed map is an overapproximation of
1971  *
1972  *	{ (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
1973  *				d = \sum_i k_i \delta_i and k = \sum_i k_i > 0 }
1974  * or
1975  *
1976  *	{ (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
1977  *				d = \sum_i k_i \delta_i and \sum_i k_i > 0 }
1978  *
1979  * if "project" is set.
1980  *
1981  * If "project" is not set, then
1982  * we construct an extended mapping with an extra coordinate
1983  * that indicates the number of steps taken.  In particular,
1984  * the difference in the last coordinate is equal to the number
1985  * of steps taken to move from a domain element to the corresponding
1986  * image element(s).
1987  */
construct_power(__isl_keep isl_map * map,isl_bool * exact,int project)1988 static __isl_give isl_map *construct_power(__isl_keep isl_map *map,
1989 	isl_bool *exact, int project)
1990 {
1991 	struct isl_map *app = NULL;
1992 	isl_space *space = NULL;
1993 
1994 	if (!map)
1995 		return NULL;
1996 
1997 	space = isl_map_get_space(map);
1998 
1999 	space = isl_space_add_dims(space, isl_dim_in, 1);
2000 	space = isl_space_add_dims(space, isl_dim_out, 1);
2001 
2002 	app = construct_power_components(isl_space_copy(space), map,
2003 					exact, project);
2004 
2005 	isl_space_free(space);
2006 
2007 	return app;
2008 }
2009 
2010 /* Compute the positive powers of "map", or an overapproximation.
2011  * If the result is exact, then *exact is set to 1.
2012  *
2013  * If project is set, then we are actually interested in the transitive
2014  * closure, so we can use a more relaxed exactness check.
2015  * The lengths of the paths are also projected out instead of being
2016  * encoded as the difference between an extra pair of final coordinates.
2017  */
map_power(__isl_take isl_map * map,isl_bool * exact,int project)2018 static __isl_give isl_map *map_power(__isl_take isl_map *map,
2019 	isl_bool *exact, int project)
2020 {
2021 	struct isl_map *app = NULL;
2022 
2023 	if (exact)
2024 		*exact = isl_bool_true;
2025 
2026 	if (isl_map_check_transformation(map) < 0)
2027 		return isl_map_free(map);
2028 
2029 	app = construct_power(map, exact, project);
2030 
2031 	isl_map_free(map);
2032 	return app;
2033 }
2034 
2035 /* Compute the positive powers of "map", or an overapproximation.
2036  * The result maps the exponent to a nested copy of the corresponding power.
2037  * If the result is exact, then *exact is set to 1.
2038  * map_power constructs an extended relation with the path lengths
2039  * encoded as the difference between the final coordinates.
2040  * In the final step, this difference is equated to an extra parameter
2041  * and made positive.  The extra coordinates are subsequently projected out
2042  * and the parameter is turned into the domain of the result.
2043  */
isl_map_power(__isl_take isl_map * map,isl_bool * exact)2044 __isl_give isl_map *isl_map_power(__isl_take isl_map *map, isl_bool *exact)
2045 {
2046 	isl_space *target_space;
2047 	isl_space *space;
2048 	isl_map *diff;
2049 	isl_size d;
2050 	isl_size param;
2051 
2052 	d = isl_map_dim(map, isl_dim_in);
2053 	param = isl_map_dim(map, isl_dim_param);
2054 	if (d < 0 || param < 0)
2055 		return isl_map_free(map);
2056 
2057 	map = isl_map_compute_divs(map);
2058 	map = isl_map_coalesce(map);
2059 
2060 	if (isl_map_plain_is_empty(map)) {
2061 		map = isl_map_from_range(isl_map_wrap(map));
2062 		map = isl_map_add_dims(map, isl_dim_in, 1);
2063 		map = isl_map_set_dim_name(map, isl_dim_in, 0, "k");
2064 		return map;
2065 	}
2066 
2067 	target_space = isl_map_get_space(map);
2068 	target_space = isl_space_from_range(isl_space_wrap(target_space));
2069 	target_space = isl_space_add_dims(target_space, isl_dim_in, 1);
2070 	target_space = isl_space_set_dim_name(target_space, isl_dim_in, 0, "k");
2071 
2072 	map = map_power(map, exact, 0);
2073 
2074 	map = isl_map_add_dims(map, isl_dim_param, 1);
2075 	space = isl_map_get_space(map);
2076 	diff = equate_parameter_to_length(space, param);
2077 	map = isl_map_intersect(map, diff);
2078 	map = isl_map_project_out(map, isl_dim_in, d, 1);
2079 	map = isl_map_project_out(map, isl_dim_out, d, 1);
2080 	map = isl_map_from_range(isl_map_wrap(map));
2081 	map = isl_map_move_dims(map, isl_dim_in, 0, isl_dim_param, param, 1);
2082 
2083 	map = isl_map_reset_space(map, target_space);
2084 
2085 	return map;
2086 }
2087 
2088 /* Compute a relation that maps each element in the range of the input
2089  * relation to the lengths of all paths composed of edges in the input
2090  * relation that end up in the given range element.
2091  * The result may be an overapproximation, in which case *exact is set to 0.
2092  * The resulting relation is very similar to the power relation.
2093  * The difference are that the domain has been projected out, the
2094  * range has become the domain and the exponent is the range instead
2095  * of a parameter.
2096  */
isl_map_reaching_path_lengths(__isl_take isl_map * map,isl_bool * exact)2097 __isl_give isl_map *isl_map_reaching_path_lengths(__isl_take isl_map *map,
2098 	isl_bool *exact)
2099 {
2100 	isl_space *space;
2101 	isl_map *diff;
2102 	isl_size d;
2103 	isl_size param;
2104 
2105 	d = isl_map_dim(map, isl_dim_in);
2106 	param = isl_map_dim(map, isl_dim_param);
2107 	if (d < 0 || param < 0)
2108 		return isl_map_free(map);
2109 
2110 	map = isl_map_compute_divs(map);
2111 	map = isl_map_coalesce(map);
2112 
2113 	if (isl_map_plain_is_empty(map)) {
2114 		if (exact)
2115 			*exact = isl_bool_true;
2116 		map = isl_map_project_out(map, isl_dim_out, 0, d);
2117 		map = isl_map_add_dims(map, isl_dim_out, 1);
2118 		return map;
2119 	}
2120 
2121 	map = map_power(map, exact, 0);
2122 
2123 	map = isl_map_add_dims(map, isl_dim_param, 1);
2124 	space = isl_map_get_space(map);
2125 	diff = equate_parameter_to_length(space, param);
2126 	map = isl_map_intersect(map, diff);
2127 	map = isl_map_project_out(map, isl_dim_in, 0, d + 1);
2128 	map = isl_map_project_out(map, isl_dim_out, d, 1);
2129 	map = isl_map_reverse(map);
2130 	map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_param, param, 1);
2131 
2132 	return map;
2133 }
2134 
2135 /* Given a map, compute the smallest superset of this map that is of the form
2136  *
2137  *	{ i -> j : L <= j - i <= U and exists a_p: j_p - i_p = M_p a_p }
2138  *
2139  * (where p ranges over the (non-parametric) dimensions),
2140  * compute the transitive closure of this map, i.e.,
2141  *
2142  *	{ i -> j : exists k > 0:
2143  *		k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p }
2144  *
2145  * and intersect domain and range of this transitive closure with
2146  * the given domain and range.
2147  *
2148  * If with_id is set, then try to include as much of the identity mapping
2149  * as possible, by computing
2150  *
2151  *	{ i -> j : exists k >= 0:
2152  *		k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p }
2153  *
2154  * instead (i.e., allow k = 0).
2155  *
2156  * In practice, we compute the difference set
2157  *
2158  *	delta  = { j - i | i -> j in map },
2159  *
2160  * look for stride constraint on the individual dimensions and compute
2161  * (constant) lower and upper bounds for each individual dimension,
2162  * adding a constraint for each bound not equal to infinity.
2163  */
box_closure_on_domain(__isl_take isl_map * map,__isl_take isl_set * dom,__isl_take isl_set * ran,int with_id)2164 static __isl_give isl_map *box_closure_on_domain(__isl_take isl_map *map,
2165 	__isl_take isl_set *dom, __isl_take isl_set *ran, int with_id)
2166 {
2167 	int i;
2168 	int k;
2169 	unsigned d;
2170 	unsigned nparam;
2171 	unsigned total;
2172 	isl_space *space;
2173 	isl_set *delta;
2174 	isl_map *app = NULL;
2175 	isl_basic_set *aff = NULL;
2176 	isl_basic_map *bmap = NULL;
2177 	isl_vec *obj = NULL;
2178 	isl_int opt;
2179 
2180 	isl_int_init(opt);
2181 
2182 	delta = isl_map_deltas(isl_map_copy(map));
2183 
2184 	aff = isl_set_affine_hull(isl_set_copy(delta));
2185 	if (!aff)
2186 		goto error;
2187 	space = isl_map_get_space(map);
2188 	d = isl_space_dim(space, isl_dim_in);
2189 	nparam = isl_space_dim(space, isl_dim_param);
2190 	total = isl_space_dim(space, isl_dim_all);
2191 	bmap = isl_basic_map_alloc_space(space,
2192 					aff->n_div + 1, aff->n_div, 2 * d + 1);
2193 	for (i = 0; i < aff->n_div + 1; ++i) {
2194 		k = isl_basic_map_alloc_div(bmap);
2195 		if (k < 0)
2196 			goto error;
2197 		isl_int_set_si(bmap->div[k][0], 0);
2198 	}
2199 	for (i = 0; i < aff->n_eq; ++i) {
2200 		if (!isl_basic_set_eq_is_stride(aff, i))
2201 			continue;
2202 		k = isl_basic_map_alloc_equality(bmap);
2203 		if (k < 0)
2204 			goto error;
2205 		isl_seq_clr(bmap->eq[k], 1 + nparam);
2206 		isl_seq_cpy(bmap->eq[k] + 1 + nparam + d,
2207 				aff->eq[i] + 1 + nparam, d);
2208 		isl_seq_neg(bmap->eq[k] + 1 + nparam,
2209 				aff->eq[i] + 1 + nparam, d);
2210 		isl_seq_cpy(bmap->eq[k] + 1 + nparam + 2 * d,
2211 				aff->eq[i] + 1 + nparam + d, aff->n_div);
2212 		isl_int_set_si(bmap->eq[k][1 + total + aff->n_div], 0);
2213 	}
2214 	obj = isl_vec_alloc(map->ctx, 1 + nparam + d);
2215 	if (!obj)
2216 		goto error;
2217 	isl_seq_clr(obj->el, 1 + nparam + d);
2218 	for (i = 0; i < d; ++ i) {
2219 		enum isl_lp_result res;
2220 
2221 		isl_int_set_si(obj->el[1 + nparam + i], 1);
2222 
2223 		res = isl_set_solve_lp(delta, 0, obj->el, map->ctx->one, &opt,
2224 					NULL, NULL);
2225 		if (res == isl_lp_error)
2226 			goto error;
2227 		if (res == isl_lp_ok) {
2228 			k = isl_basic_map_alloc_inequality(bmap);
2229 			if (k < 0)
2230 				goto error;
2231 			isl_seq_clr(bmap->ineq[k],
2232 					1 + nparam + 2 * d + bmap->n_div);
2233 			isl_int_set_si(bmap->ineq[k][1 + nparam + i], -1);
2234 			isl_int_set_si(bmap->ineq[k][1 + nparam + d + i], 1);
2235 			isl_int_neg(bmap->ineq[k][1 + nparam + 2 * d + aff->n_div], opt);
2236 		}
2237 
2238 		res = isl_set_solve_lp(delta, 1, obj->el, map->ctx->one, &opt,
2239 					NULL, NULL);
2240 		if (res == isl_lp_error)
2241 			goto error;
2242 		if (res == isl_lp_ok) {
2243 			k = isl_basic_map_alloc_inequality(bmap);
2244 			if (k < 0)
2245 				goto error;
2246 			isl_seq_clr(bmap->ineq[k],
2247 					1 + nparam + 2 * d + bmap->n_div);
2248 			isl_int_set_si(bmap->ineq[k][1 + nparam + i], 1);
2249 			isl_int_set_si(bmap->ineq[k][1 + nparam + d + i], -1);
2250 			isl_int_set(bmap->ineq[k][1 + nparam + 2 * d + aff->n_div], opt);
2251 		}
2252 
2253 		isl_int_set_si(obj->el[1 + nparam + i], 0);
2254 	}
2255 	k = isl_basic_map_alloc_inequality(bmap);
2256 	if (k < 0)
2257 		goto error;
2258 	isl_seq_clr(bmap->ineq[k],
2259 			1 + nparam + 2 * d + bmap->n_div);
2260 	if (!with_id)
2261 		isl_int_set_si(bmap->ineq[k][0], -1);
2262 	isl_int_set_si(bmap->ineq[k][1 + nparam + 2 * d + aff->n_div], 1);
2263 
2264 	app = isl_map_from_domain_and_range(dom, ran);
2265 
2266 	isl_vec_free(obj);
2267 	isl_basic_set_free(aff);
2268 	isl_map_free(map);
2269 	bmap = isl_basic_map_finalize(bmap);
2270 	isl_set_free(delta);
2271 	isl_int_clear(opt);
2272 
2273 	map = isl_map_from_basic_map(bmap);
2274 	map = isl_map_intersect(map, app);
2275 
2276 	return map;
2277 error:
2278 	isl_vec_free(obj);
2279 	isl_basic_map_free(bmap);
2280 	isl_basic_set_free(aff);
2281 	isl_set_free(dom);
2282 	isl_set_free(ran);
2283 	isl_map_free(map);
2284 	isl_set_free(delta);
2285 	isl_int_clear(opt);
2286 	return NULL;
2287 }
2288 
2289 /* Given a map, compute the smallest superset of this map that is of the form
2290  *
2291  *	{ i -> j : L <= j - i <= U and exists a_p: j_p - i_p = M_p a_p }
2292  *
2293  * (where p ranges over the (non-parametric) dimensions),
2294  * compute the transitive closure of this map, i.e.,
2295  *
2296  *	{ i -> j : exists k > 0:
2297  *		k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p }
2298  *
2299  * and intersect domain and range of this transitive closure with
2300  * domain and range of the original map.
2301  */
box_closure(__isl_take isl_map * map)2302 static __isl_give isl_map *box_closure(__isl_take isl_map *map)
2303 {
2304 	isl_set *domain;
2305 	isl_set *range;
2306 
2307 	domain = isl_map_domain(isl_map_copy(map));
2308 	domain = isl_set_coalesce(domain);
2309 	range = isl_map_range(isl_map_copy(map));
2310 	range = isl_set_coalesce(range);
2311 
2312 	return box_closure_on_domain(map, domain, range, 0);
2313 }
2314 
2315 /* Given a map, compute the smallest superset of this map that is of the form
2316  *
2317  *	{ i -> j : L <= j - i <= U and exists a_p: j_p - i_p = M_p a_p }
2318  *
2319  * (where p ranges over the (non-parametric) dimensions),
2320  * compute the transitive and partially reflexive closure of this map, i.e.,
2321  *
2322  *	{ i -> j : exists k >= 0:
2323  *		k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p }
2324  *
2325  * and intersect domain and range of this transitive closure with
2326  * the given domain.
2327  */
box_closure_with_identity(__isl_take isl_map * map,__isl_take isl_set * dom)2328 static __isl_give isl_map *box_closure_with_identity(__isl_take isl_map *map,
2329 	__isl_take isl_set *dom)
2330 {
2331 	return box_closure_on_domain(map, dom, isl_set_copy(dom), 1);
2332 }
2333 
2334 /* Check whether app is the transitive closure of map.
2335  * In particular, check that app is acyclic and, if so,
2336  * check that
2337  *
2338  *	app \subset (map \cup (map \circ app))
2339  */
check_exactness_omega(__isl_keep isl_map * map,__isl_keep isl_map * app)2340 static isl_bool check_exactness_omega(__isl_keep isl_map *map,
2341 	__isl_keep isl_map *app)
2342 {
2343 	isl_set *delta;
2344 	int i;
2345 	isl_bool is_empty, is_exact;
2346 	isl_size d;
2347 	isl_map *test;
2348 
2349 	delta = isl_map_deltas(isl_map_copy(app));
2350 	d = isl_set_dim(delta, isl_dim_set);
2351 	if (d < 0)
2352 		delta = isl_set_free(delta);
2353 	for (i = 0; i < d; ++i)
2354 		delta = isl_set_fix_si(delta, isl_dim_set, i, 0);
2355 	is_empty = isl_set_is_empty(delta);
2356 	isl_set_free(delta);
2357 	if (is_empty < 0 || !is_empty)
2358 		return is_empty;
2359 
2360 	test = isl_map_apply_range(isl_map_copy(app), isl_map_copy(map));
2361 	test = isl_map_union(test, isl_map_copy(map));
2362 	is_exact = isl_map_is_subset(app, test);
2363 	isl_map_free(test);
2364 
2365 	return is_exact;
2366 }
2367 
2368 /* Check if basic map M_i can be combined with all the other
2369  * basic maps such that
2370  *
2371  *	(\cup_j M_j)^+
2372  *
2373  * can be computed as
2374  *
2375  *	M_i \cup (\cup_{j \ne i} M_i^* \circ M_j \circ M_i^*)^+
2376  *
2377  * In particular, check if we can compute a compact representation
2378  * of
2379  *
2380  *		M_i^* \circ M_j \circ M_i^*
2381  *
2382  * for each j != i.
2383  * Let M_i^? be an extension of M_i^+ that allows paths
2384  * of length zero, i.e., the result of box_closure(., 1).
2385  * The criterion, as proposed by Kelly et al., is that
2386  * id = M_i^? - M_i^+ can be represented as a basic map
2387  * and that
2388  *
2389  *	id \circ M_j \circ id = M_j
2390  *
2391  * for each j != i.
2392  *
2393  * If this function returns 1, then tc and qc are set to
2394  * M_i^+ and M_i^?, respectively.
2395  */
can_be_split_off(__isl_keep isl_map * map,int i,__isl_give isl_map ** tc,__isl_give isl_map ** qc)2396 static int can_be_split_off(__isl_keep isl_map *map, int i,
2397 	__isl_give isl_map **tc, __isl_give isl_map **qc)
2398 {
2399 	isl_map *map_i, *id = NULL;
2400 	int j = -1;
2401 	isl_set *C;
2402 
2403 	*tc = NULL;
2404 	*qc = NULL;
2405 
2406 	C = isl_set_union(isl_map_domain(isl_map_copy(map)),
2407 			  isl_map_range(isl_map_copy(map)));
2408 	C = isl_set_from_basic_set(isl_set_simple_hull(C));
2409 	if (!C)
2410 		goto error;
2411 
2412 	map_i = isl_map_from_basic_map(isl_basic_map_copy(map->p[i]));
2413 	*tc = box_closure(isl_map_copy(map_i));
2414 	*qc = box_closure_with_identity(map_i, C);
2415 	id = isl_map_subtract(isl_map_copy(*qc), isl_map_copy(*tc));
2416 
2417 	if (!id || !*qc)
2418 		goto error;
2419 	if (id->n != 1 || (*qc)->n != 1)
2420 		goto done;
2421 
2422 	for (j = 0; j < map->n; ++j) {
2423 		isl_map *map_j, *test;
2424 		int is_ok;
2425 
2426 		if (i == j)
2427 			continue;
2428 		map_j = isl_map_from_basic_map(
2429 					isl_basic_map_copy(map->p[j]));
2430 		test = isl_map_apply_range(isl_map_copy(id),
2431 						isl_map_copy(map_j));
2432 		test = isl_map_apply_range(test, isl_map_copy(id));
2433 		is_ok = isl_map_is_equal(test, map_j);
2434 		isl_map_free(map_j);
2435 		isl_map_free(test);
2436 		if (is_ok < 0)
2437 			goto error;
2438 		if (!is_ok)
2439 			break;
2440 	}
2441 
2442 done:
2443 	isl_map_free(id);
2444 	if (j == map->n)
2445 		return 1;
2446 
2447 	isl_map_free(*qc);
2448 	isl_map_free(*tc);
2449 	*qc = NULL;
2450 	*tc = NULL;
2451 
2452 	return 0;
2453 error:
2454 	isl_map_free(id);
2455 	isl_map_free(*qc);
2456 	isl_map_free(*tc);
2457 	*qc = NULL;
2458 	*tc = NULL;
2459 	return -1;
2460 }
2461 
box_closure_with_check(__isl_take isl_map * map,isl_bool * exact)2462 static __isl_give isl_map *box_closure_with_check(__isl_take isl_map *map,
2463 	isl_bool *exact)
2464 {
2465 	isl_map *app;
2466 
2467 	app = box_closure(isl_map_copy(map));
2468 	if (exact) {
2469 		isl_bool is_exact = check_exactness_omega(map, app);
2470 
2471 		if (is_exact < 0)
2472 			app = isl_map_free(app);
2473 		else
2474 			*exact = is_exact;
2475 	}
2476 
2477 	isl_map_free(map);
2478 	return app;
2479 }
2480 
2481 /* Compute an overapproximation of the transitive closure of "map"
2482  * using a variation of the algorithm from
2483  * "Transitive Closure of Infinite Graphs and its Applications"
2484  * by Kelly et al.
2485  *
2486  * We first check whether we can can split of any basic map M_i and
2487  * compute
2488  *
2489  *	(\cup_j M_j)^+
2490  *
2491  * as
2492  *
2493  *	M_i \cup (\cup_{j \ne i} M_i^* \circ M_j \circ M_i^*)^+
2494  *
2495  * using a recursive call on the remaining map.
2496  *
2497  * If not, we simply call box_closure on the whole map.
2498  */
transitive_closure_omega(__isl_take isl_map * map,isl_bool * exact)2499 static __isl_give isl_map *transitive_closure_omega(__isl_take isl_map *map,
2500 	isl_bool *exact)
2501 {
2502 	int i, j;
2503 	isl_bool exact_i;
2504 	isl_map *app;
2505 
2506 	if (!map)
2507 		return NULL;
2508 	if (map->n == 1)
2509 		return box_closure_with_check(map, exact);
2510 
2511 	for (i = 0; i < map->n; ++i) {
2512 		int ok;
2513 		isl_map *qc, *tc;
2514 		ok = can_be_split_off(map, i, &tc, &qc);
2515 		if (ok < 0)
2516 			goto error;
2517 		if (!ok)
2518 			continue;
2519 
2520 		app = isl_map_alloc_space(isl_map_get_space(map), map->n - 1, 0);
2521 
2522 		for (j = 0; j < map->n; ++j) {
2523 			if (j == i)
2524 				continue;
2525 			app = isl_map_add_basic_map(app,
2526 						isl_basic_map_copy(map->p[j]));
2527 		}
2528 
2529 		app = isl_map_apply_range(isl_map_copy(qc), app);
2530 		app = isl_map_apply_range(app, qc);
2531 
2532 		app = isl_map_union(tc, transitive_closure_omega(app, NULL));
2533 		exact_i = check_exactness_omega(map, app);
2534 		if (exact_i == isl_bool_true) {
2535 			if (exact)
2536 				*exact = exact_i;
2537 			isl_map_free(map);
2538 			return app;
2539 		}
2540 		isl_map_free(app);
2541 		if (exact_i < 0)
2542 			goto error;
2543 	}
2544 
2545 	return box_closure_with_check(map, exact);
2546 error:
2547 	isl_map_free(map);
2548 	return NULL;
2549 }
2550 
2551 /* Compute the transitive closure  of "map", or an overapproximation.
2552  * If the result is exact, then *exact is set to 1.
2553  * Simply use map_power to compute the powers of map, but tell
2554  * it to project out the lengths of the paths instead of equating
2555  * the length to a parameter.
2556  */
isl_map_transitive_closure(__isl_take isl_map * map,isl_bool * exact)2557 __isl_give isl_map *isl_map_transitive_closure(__isl_take isl_map *map,
2558 	isl_bool *exact)
2559 {
2560 	isl_space *target_dim;
2561 	isl_bool closed;
2562 
2563 	if (!map)
2564 		goto error;
2565 
2566 	if (map->ctx->opt->closure == ISL_CLOSURE_BOX)
2567 		return transitive_closure_omega(map, exact);
2568 
2569 	map = isl_map_compute_divs(map);
2570 	map = isl_map_coalesce(map);
2571 	closed = isl_map_is_transitively_closed(map);
2572 	if (closed < 0)
2573 		goto error;
2574 	if (closed) {
2575 		if (exact)
2576 			*exact = isl_bool_true;
2577 		return map;
2578 	}
2579 
2580 	target_dim = isl_map_get_space(map);
2581 	map = map_power(map, exact, 1);
2582 	map = isl_map_reset_space(map, target_dim);
2583 
2584 	return map;
2585 error:
2586 	isl_map_free(map);
2587 	return NULL;
2588 }
2589 
inc_count(__isl_take isl_map * map,void * user)2590 static isl_stat inc_count(__isl_take isl_map *map, void *user)
2591 {
2592 	int *n = user;
2593 
2594 	*n += map->n;
2595 
2596 	isl_map_free(map);
2597 
2598 	return isl_stat_ok;
2599 }
2600 
collect_basic_map(__isl_take isl_map * map,void * user)2601 static isl_stat collect_basic_map(__isl_take isl_map *map, void *user)
2602 {
2603 	int i;
2604 	isl_basic_map ***next = user;
2605 
2606 	for (i = 0; i < map->n; ++i) {
2607 		**next = isl_basic_map_copy(map->p[i]);
2608 		if (!**next)
2609 			goto error;
2610 		(*next)++;
2611 	}
2612 
2613 	isl_map_free(map);
2614 	return isl_stat_ok;
2615 error:
2616 	isl_map_free(map);
2617 	return isl_stat_error;
2618 }
2619 
2620 /* Perform Floyd-Warshall on the given list of basic relations.
2621  * The basic relations may live in different dimensions,
2622  * but basic relations that get assigned to the diagonal of the
2623  * grid have domains and ranges of the same dimension and so
2624  * the standard algorithm can be used because the nested transitive
2625  * closures are only applied to diagonal elements and because all
2626  * compositions are performed on relations with compatible domains and ranges.
2627  */
union_floyd_warshall_on_list(isl_ctx * ctx,__isl_keep isl_basic_map ** list,int n,isl_bool * exact)2628 static __isl_give isl_union_map *union_floyd_warshall_on_list(isl_ctx *ctx,
2629 	__isl_keep isl_basic_map **list, int n, isl_bool *exact)
2630 {
2631 	int i, j, k;
2632 	int n_group;
2633 	int *group = NULL;
2634 	isl_set **set = NULL;
2635 	isl_map ***grid = NULL;
2636 	isl_union_map *app;
2637 
2638 	group = setup_groups(ctx, list, n, &set, &n_group);
2639 	if (!group)
2640 		goto error;
2641 
2642 	grid = isl_calloc_array(ctx, isl_map **, n_group);
2643 	if (!grid)
2644 		goto error;
2645 	for (i = 0; i < n_group; ++i) {
2646 		grid[i] = isl_calloc_array(ctx, isl_map *, n_group);
2647 		if (!grid[i])
2648 			goto error;
2649 		for (j = 0; j < n_group; ++j) {
2650 			isl_space *space1, *space2, *space;
2651 			space1 = isl_space_reverse(isl_set_get_space(set[i]));
2652 			space2 = isl_set_get_space(set[j]);
2653 			space = isl_space_join(space1, space2);
2654 			grid[i][j] = isl_map_empty(space);
2655 		}
2656 	}
2657 
2658 	for (k = 0; k < n; ++k) {
2659 		i = group[2 * k];
2660 		j = group[2 * k + 1];
2661 		grid[i][j] = isl_map_union(grid[i][j],
2662 				isl_map_from_basic_map(
2663 					isl_basic_map_copy(list[k])));
2664 	}
2665 
2666 	floyd_warshall_iterate(grid, n_group, exact);
2667 
2668 	app = isl_union_map_empty(isl_map_get_space(grid[0][0]));
2669 
2670 	for (i = 0; i < n_group; ++i) {
2671 		for (j = 0; j < n_group; ++j)
2672 			app = isl_union_map_add_map(app, grid[i][j]);
2673 		free(grid[i]);
2674 	}
2675 	free(grid);
2676 
2677 	for (i = 0; i < 2 * n; ++i)
2678 		isl_set_free(set[i]);
2679 	free(set);
2680 
2681 	free(group);
2682 	return app;
2683 error:
2684 	if (grid)
2685 		for (i = 0; i < n_group; ++i) {
2686 			if (!grid[i])
2687 				continue;
2688 			for (j = 0; j < n_group; ++j)
2689 				isl_map_free(grid[i][j]);
2690 			free(grid[i]);
2691 		}
2692 	free(grid);
2693 	if (set) {
2694 		for (i = 0; i < 2 * n; ++i)
2695 			isl_set_free(set[i]);
2696 		free(set);
2697 	}
2698 	free(group);
2699 	return NULL;
2700 }
2701 
2702 /* Perform Floyd-Warshall on the given union relation.
2703  * The implementation is very similar to that for non-unions.
2704  * The main difference is that it is applied unconditionally.
2705  * We first extract a list of basic maps from the union map
2706  * and then perform the algorithm on this list.
2707  */
union_floyd_warshall(__isl_take isl_union_map * umap,isl_bool * exact)2708 static __isl_give isl_union_map *union_floyd_warshall(
2709 	__isl_take isl_union_map *umap, isl_bool *exact)
2710 {
2711 	int i, n;
2712 	isl_ctx *ctx;
2713 	isl_basic_map **list = NULL;
2714 	isl_basic_map **next;
2715 	isl_union_map *res;
2716 
2717 	n = 0;
2718 	if (isl_union_map_foreach_map(umap, inc_count, &n) < 0)
2719 		goto error;
2720 
2721 	ctx = isl_union_map_get_ctx(umap);
2722 	list = isl_calloc_array(ctx, isl_basic_map *, n);
2723 	if (!list)
2724 		goto error;
2725 
2726 	next = list;
2727 	if (isl_union_map_foreach_map(umap, collect_basic_map, &next) < 0)
2728 		goto error;
2729 
2730 	res = union_floyd_warshall_on_list(ctx, list, n, exact);
2731 
2732 	if (list) {
2733 		for (i = 0; i < n; ++i)
2734 			isl_basic_map_free(list[i]);
2735 		free(list);
2736 	}
2737 
2738 	isl_union_map_free(umap);
2739 	return res;
2740 error:
2741 	if (list) {
2742 		for (i = 0; i < n; ++i)
2743 			isl_basic_map_free(list[i]);
2744 		free(list);
2745 	}
2746 	isl_union_map_free(umap);
2747 	return NULL;
2748 }
2749 
2750 /* Decompose the give union relation into strongly connected components.
2751  * The implementation is essentially the same as that of
2752  * construct_power_components with the major difference that all
2753  * operations are performed on union maps.
2754  */
union_components(__isl_take isl_union_map * umap,isl_bool * exact)2755 static __isl_give isl_union_map *union_components(
2756 	__isl_take isl_union_map *umap, isl_bool *exact)
2757 {
2758 	int i;
2759 	int n;
2760 	isl_ctx *ctx;
2761 	isl_basic_map **list = NULL;
2762 	isl_basic_map **next;
2763 	isl_union_map *path = NULL;
2764 	struct isl_tc_follows_data data;
2765 	struct isl_tarjan_graph *g = NULL;
2766 	int c, l;
2767 	int recheck = 0;
2768 
2769 	n = 0;
2770 	if (isl_union_map_foreach_map(umap, inc_count, &n) < 0)
2771 		goto error;
2772 
2773 	if (n == 0)
2774 		return umap;
2775 	if (n <= 1)
2776 		return union_floyd_warshall(umap, exact);
2777 
2778 	ctx = isl_union_map_get_ctx(umap);
2779 	list = isl_calloc_array(ctx, isl_basic_map *, n);
2780 	if (!list)
2781 		goto error;
2782 
2783 	next = list;
2784 	if (isl_union_map_foreach_map(umap, collect_basic_map, &next) < 0)
2785 		goto error;
2786 
2787 	data.list = list;
2788 	data.check_closed = 0;
2789 	g = isl_tarjan_graph_init(ctx, n, &basic_map_follows, &data);
2790 	if (!g)
2791 		goto error;
2792 
2793 	c = 0;
2794 	i = 0;
2795 	l = n;
2796 	path = isl_union_map_empty(isl_union_map_get_space(umap));
2797 	while (l) {
2798 		isl_union_map *comp;
2799 		isl_union_map *path_comp, *path_comb;
2800 		comp = isl_union_map_empty(isl_union_map_get_space(umap));
2801 		while (g->order[i] != -1) {
2802 			comp = isl_union_map_add_map(comp,
2803 				    isl_map_from_basic_map(
2804 					isl_basic_map_copy(list[g->order[i]])));
2805 			--l;
2806 			++i;
2807 		}
2808 		path_comp = union_floyd_warshall(comp, exact);
2809 		path_comb = isl_union_map_apply_range(isl_union_map_copy(path),
2810 						isl_union_map_copy(path_comp));
2811 		path = isl_union_map_union(path, path_comp);
2812 		path = isl_union_map_union(path, path_comb);
2813 		++i;
2814 		++c;
2815 	}
2816 
2817 	if (c > 1 && data.check_closed && !*exact) {
2818 		isl_bool closed;
2819 
2820 		closed = isl_union_map_is_transitively_closed(path);
2821 		if (closed < 0)
2822 			goto error;
2823 		recheck = !closed;
2824 	}
2825 
2826 	isl_tarjan_graph_free(g);
2827 
2828 	for (i = 0; i < n; ++i)
2829 		isl_basic_map_free(list[i]);
2830 	free(list);
2831 
2832 	if (recheck) {
2833 		isl_union_map_free(path);
2834 		return union_floyd_warshall(umap, exact);
2835 	}
2836 
2837 	isl_union_map_free(umap);
2838 
2839 	return path;
2840 error:
2841 	isl_tarjan_graph_free(g);
2842 	if (list) {
2843 		for (i = 0; i < n; ++i)
2844 			isl_basic_map_free(list[i]);
2845 		free(list);
2846 	}
2847 	isl_union_map_free(umap);
2848 	isl_union_map_free(path);
2849 	return NULL;
2850 }
2851 
2852 /* Compute the transitive closure  of "umap", or an overapproximation.
2853  * If the result is exact, then *exact is set to 1.
2854  */
isl_union_map_transitive_closure(__isl_take isl_union_map * umap,isl_bool * exact)2855 __isl_give isl_union_map *isl_union_map_transitive_closure(
2856 	__isl_take isl_union_map *umap, isl_bool *exact)
2857 {
2858 	isl_bool closed;
2859 
2860 	if (!umap)
2861 		return NULL;
2862 
2863 	if (exact)
2864 		*exact = isl_bool_true;
2865 
2866 	umap = isl_union_map_compute_divs(umap);
2867 	umap = isl_union_map_coalesce(umap);
2868 	closed = isl_union_map_is_transitively_closed(umap);
2869 	if (closed < 0)
2870 		goto error;
2871 	if (closed)
2872 		return umap;
2873 	umap = union_components(umap, exact);
2874 	return umap;
2875 error:
2876 	isl_union_map_free(umap);
2877 	return NULL;
2878 }
2879 
2880 struct isl_union_power {
2881 	isl_union_map *pow;
2882 	isl_bool *exact;
2883 };
2884 
power(__isl_take isl_map * map,void * user)2885 static isl_stat power(__isl_take isl_map *map, void *user)
2886 {
2887 	struct isl_union_power *up = user;
2888 
2889 	map = isl_map_power(map, up->exact);
2890 	up->pow = isl_union_map_from_map(map);
2891 
2892 	return isl_stat_error;
2893 }
2894 
2895 /* Construct a map [[x]->[y]] -> [y-x], with parameters prescribed by "space".
2896  */
deltas_map(__isl_take isl_space * space)2897 static __isl_give isl_union_map *deltas_map(__isl_take isl_space *space)
2898 {
2899 	isl_basic_map *bmap;
2900 
2901 	space = isl_space_add_dims(space, isl_dim_in, 1);
2902 	space = isl_space_add_dims(space, isl_dim_out, 1);
2903 	bmap = isl_basic_map_universe(space);
2904 	bmap = isl_basic_map_deltas_map(bmap);
2905 
2906 	return isl_union_map_from_map(isl_map_from_basic_map(bmap));
2907 }
2908 
2909 /* Compute the positive powers of "map", or an overapproximation.
2910  * The result maps the exponent to a nested copy of the corresponding power.
2911  * If the result is exact, then *exact is set to 1.
2912  */
isl_union_map_power(__isl_take isl_union_map * umap,isl_bool * exact)2913 __isl_give isl_union_map *isl_union_map_power(__isl_take isl_union_map *umap,
2914 	isl_bool *exact)
2915 {
2916 	isl_size n;
2917 	isl_union_map *inc;
2918 	isl_union_map *dm;
2919 
2920 	n = isl_union_map_n_map(umap);
2921 	if (n < 0)
2922 		return isl_union_map_free(umap);
2923 	if (n == 0)
2924 		return umap;
2925 	if (n == 1) {
2926 		struct isl_union_power up = { NULL, exact };
2927 		isl_union_map_foreach_map(umap, &power, &up);
2928 		isl_union_map_free(umap);
2929 		return up.pow;
2930 	}
2931 	inc = isl_union_map_from_map(increment(isl_union_map_get_space(umap)));
2932 	umap = isl_union_map_product(inc, umap);
2933 	umap = isl_union_map_transitive_closure(umap, exact);
2934 	umap = isl_union_map_zip(umap);
2935 	dm = deltas_map(isl_union_map_get_space(umap));
2936 	umap = isl_union_map_apply_domain(umap, dm);
2937 
2938 	return umap;
2939 }
2940 
2941 #undef TYPE
2942 #define TYPE isl_map
2943 #include "isl_power_templ.c"
2944 
2945 #undef TYPE
2946 #define TYPE isl_union_map
2947 #include "isl_power_templ.c"
2948