2 * Copyright 2010 INRIA Saclay
4 * Use of this software is governed by the GNU LGPLv2.1 license
6 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
7 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
12 #include "isl_map_private.h"
15 * The transitive closure implementation is based on the paper
16 * "Computing the Transitive Closure of a Union of Affine Integer
17 * Tuple Relations" by Anna Beletska, Denis Barthou, Wlodzimierz Bielecki and
21 /* Given a union of translations (uniform dependences), return a matrix
22 * with as many rows as there are disjuncts in the union and as many
23 * columns as there are input dimensions (which should be equal to
24 * the number of output dimensions).
25 * Each row contains the translation performed by the corresponding disjunct.
26 * If "map" turns out not to be a union of translations, then the contents
27 * of the returned matrix are undefined and *ok is set to 0.
29 static __isl_give isl_mat
*extract_steps(__isl_keep isl_map
*map
, int *ok
)
32 struct isl_mat
*steps
;
33 unsigned dim
= isl_map_dim(map
, isl_dim_in
);
37 steps
= isl_mat_alloc(map
->ctx
, map
->n
, dim
);
41 for (i
= 0; i
< map
->n
; ++i
) {
42 struct isl_basic_set
*delta
;
44 delta
= isl_basic_map_deltas(isl_basic_map_copy(map
->p
[i
]));
46 for (j
= 0; j
< dim
; ++j
) {
49 fixed
= isl_basic_set_fast_dim_is_fixed(delta
, j
,
52 isl_basic_set_free(delta
);
59 isl_basic_set_free(delta
);
74 /* Given a set of n offsets v_i (the rows of "steps"), construct a relation
75 * of the given dimension specification (Z^{n+1} -> Z^{n+1})
76 * that maps an element x to any element that can be reached
77 * by taking a non-negative number of steps along any of
78 * the extended offsets v'_i = [v_i 1].
81 * { [x] -> [y] : exists k_i >= 0, y = x + \sum_i k_i v'_i }
83 * For any element in this relation, the number of steps taken
84 * is equal to the difference in the final coordinates.
86 static __isl_give isl_map
*path_along_steps(__isl_take isl_dim
*dim
,
87 __isl_keep isl_mat
*steps
)
90 struct isl_basic_map
*path
= NULL
;
98 d
= isl_dim_size(dim
, isl_dim_in
);
100 nparam
= isl_dim_size(dim
, isl_dim_param
);
102 path
= isl_basic_map_alloc_dim(isl_dim_copy(dim
), n
, d
, n
);
104 for (i
= 0; i
< n
; ++i
) {
105 k
= isl_basic_map_alloc_div(path
);
108 isl_assert(steps
->ctx
, i
== k
, goto error
);
109 isl_int_set_si(path
->div
[k
][0], 0);
112 for (i
= 0; i
< d
; ++i
) {
113 k
= isl_basic_map_alloc_equality(path
);
116 isl_seq_clr(path
->eq
[k
], 1 + isl_basic_map_total_dim(path
));
117 isl_int_set_si(path
->eq
[k
][1 + nparam
+ i
], 1);
118 isl_int_set_si(path
->eq
[k
][1 + nparam
+ d
+ i
], -1);
120 for (j
= 0; j
< n
; ++j
)
121 isl_int_set_si(path
->eq
[k
][1 + nparam
+ 2 * d
+ j
], 1);
123 for (j
= 0; j
< n
; ++j
)
124 isl_int_set(path
->eq
[k
][1 + nparam
+ 2 * d
+ j
],
128 for (i
= 0; i
< n
; ++i
) {
129 k
= isl_basic_map_alloc_inequality(path
);
132 isl_seq_clr(path
->ineq
[k
], 1 + isl_basic_map_total_dim(path
));
133 isl_int_set_si(path
->ineq
[k
][1 + nparam
+ 2 * d
+ i
], 1);
138 path
= isl_basic_map_simplify(path
);
139 path
= isl_basic_map_finalize(path
);
140 return isl_map_from_basic_map(path
);
143 isl_basic_map_free(path
);
147 /* Given a dimenion specification Z^{n+1} -> Z^{n+1} and a parameter "param",
148 * construct a map that equates the parameter to the difference
149 * in the final coordinates and imposes that this difference is positive.
152 * { [x,x_s] -> [y,y_s] : k = y_s - x_s > 0 }
154 static __isl_give isl_map
*equate_parameter_to_length(__isl_take isl_dim
*dim
,
157 struct isl_basic_map
*bmap
;
162 d
= isl_dim_size(dim
, isl_dim_in
);
163 nparam
= isl_dim_size(dim
, isl_dim_param
);
164 bmap
= isl_basic_map_alloc_dim(dim
, 0, 1, 1);
165 k
= isl_basic_map_alloc_equality(bmap
);
168 isl_seq_clr(bmap
->eq
[k
], 1 + isl_basic_map_total_dim(bmap
));
169 isl_int_set_si(bmap
->eq
[k
][1 + param
], -1);
170 isl_int_set_si(bmap
->eq
[k
][1 + nparam
+ d
- 1], -1);
171 isl_int_set_si(bmap
->eq
[k
][1 + nparam
+ d
+ d
- 1], 1);
173 k
= isl_basic_map_alloc_inequality(bmap
);
176 isl_seq_clr(bmap
->ineq
[k
], 1 + isl_basic_map_total_dim(bmap
));
177 isl_int_set_si(bmap
->ineq
[k
][1 + param
], 1);
178 isl_int_set_si(bmap
->ineq
[k
][0], -1);
180 bmap
= isl_basic_map_finalize(bmap
);
181 return isl_map_from_basic_map(bmap
);
183 isl_basic_map_free(bmap
);
187 /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D,
188 * construct a map that is an overapproximation of the map
189 * that takes an element from the space D to another
190 * element from the same space, such that the difference between
191 * them is a strictly positive sum of differences between images
192 * and pre-images in one of the R_i.
193 * The number of differences in the sum is equated to parameter "param".
196 * \Delta_i = { y - x | (x, y) in R_i }
198 * then the constructed map is an overapproximation of
200 * { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
201 * d = \sum_i k_i and k = \sum_i k_i > 0 }
203 * We first construct an extended mapping with an extra coordinate
204 * that indicates the number of steps taken. In particular,
205 * the difference in the last coordinate is equal to the number
206 * of steps taken to move from a domain element to the corresponding
208 * In the final step, this difference is equated to the parameter "param"
209 * and made positive. The extra coordinates are subsequently projected out.
211 * If any of the \Delta_i contains more than one element, then
212 * we currently simply return a universal map { (x) -> (y) }.
214 static __isl_give isl_map
*construct_path(__isl_keep isl_map
*map
,
217 struct isl_mat
*steps
= NULL
;
218 struct isl_map
*path
= NULL
;
219 struct isl_map
*diff
;
227 steps
= extract_steps(map
, &ok
);
232 return isl_map_universe(isl_map_get_dim(map
));
235 dim
= isl_map_get_dim(map
);
237 d
= isl_dim_size(dim
, isl_dim_in
);
238 dim
= isl_dim_add(dim
, isl_dim_in
, 1);
239 dim
= isl_dim_add(dim
, isl_dim_out
, 1);
240 path
= path_along_steps(isl_dim_copy(dim
), steps
);
241 diff
= equate_parameter_to_length(dim
, param
);
243 path
= isl_map_intersect(path
, diff
);
244 path
= isl_map_project_out(path
, isl_dim_in
, d
, 1);
245 path
= isl_map_project_out(path
, isl_dim_out
, d
, 1);
251 /* Check whether "path" is acyclic.
252 * That is, check whether
254 * { d | d = y - x and (x,y) in path }
256 * does not contain the origin.
258 static int is_acyclic(__isl_take isl_map
*path
)
263 struct isl_set
*delta
;
265 delta
= isl_map_deltas(path
);
266 dim
= isl_set_dim(delta
, isl_dim_set
);
267 for (i
= 0; i
< dim
; ++i
)
268 delta
= isl_set_fix_si(delta
, isl_dim_set
, i
, 0);
270 acyclic
= isl_set_is_empty(delta
);
276 /* Shift variable at position "pos" up by one.
277 * That is, replace the corresponding variable v by v - 1.
279 static __isl_give isl_basic_map
*basic_map_shift_pos(
280 __isl_take isl_basic_map
*bmap
, unsigned pos
)
284 bmap
= isl_basic_map_cow(bmap
);
288 for (i
= 0; i
< bmap
->n_eq
; ++i
)
289 isl_int_sub(bmap
->eq
[i
][0], bmap
->eq
[i
][0], bmap
->eq
[i
][pos
]);
291 for (i
= 0; i
< bmap
->n_ineq
; ++i
)
292 isl_int_sub(bmap
->ineq
[i
][0],
293 bmap
->ineq
[i
][0], bmap
->ineq
[i
][pos
]);
295 for (i
= 0; i
< bmap
->n_div
; ++i
) {
296 if (isl_int_is_zero(bmap
->div
[i
][0]))
298 isl_int_sub(bmap
->div
[i
][1],
299 bmap
->div
[i
][1], bmap
->div
[i
][1 + pos
]);
305 /* Shift variable at position "pos" up by one.
306 * That is, replace the corresponding variable v by v - 1.
308 static __isl_give isl_map
*map_shift_pos(__isl_take isl_map
*map
, unsigned pos
)
312 map
= isl_map_cow(map
);
316 for (i
= 0; i
< map
->n
; ++i
) {
317 map
->p
[i
] = basic_map_shift_pos(map
->p
[i
], pos
);
321 ISL_F_CLR(map
, ISL_MAP_NORMALIZED
);
328 /* Check whether the overapproximation of the power of "map" is exactly
329 * the power of "map". Let R be "map" and A_k the overapproximation.
330 * The approximation is exact if
333 * A_k = A_{k-1} \circ R k >= 2
335 * Since A_k is known to be an overapproximation, we only need to check
338 * A_k \subset A_{k-1} \circ R k >= 2
341 static int check_power_exactness(__isl_take isl_map
*map
,
342 __isl_take isl_map
*app
, unsigned param
)
348 app_1
= isl_map_fix_si(isl_map_copy(app
), isl_dim_param
, param
, 1);
350 exact
= isl_map_is_subset(app_1
, map
);
353 if (!exact
|| exact
< 0) {
359 app_2
= isl_map_lower_bound_si(isl_map_copy(app
),
360 isl_dim_param
, param
, 2);
361 app_1
= map_shift_pos(app
, 1 + param
);
362 app_1
= isl_map_apply_range(map
, app_1
);
364 exact
= isl_map_is_subset(app_2
, app_1
);
372 /* Check whether the overapproximation of the power of "map" is exactly
373 * the power of "map", possibly after projecting out the power (if "project"
376 * If "project" is set and if "steps" can only result in acyclic paths,
379 * A = R \cup (A \circ R)
381 * where A is the overapproximation with the power projected out, i.e.,
382 * an overapproximation of the transitive closure.
383 * More specifically, since A is known to be an overapproximation, we check
385 * A \subset R \cup (A \circ R)
387 * Otherwise, we check if the power is exact.
389 static int check_exactness(__isl_take isl_map
*map
, __isl_take isl_map
*app
,
390 __isl_take isl_map
*path
, unsigned param
, int project
)
396 project
= is_acyclic(path
);
403 return check_power_exactness(map
, app
, param
);
405 map
= isl_map_project_out(map
, isl_dim_param
, param
, 1);
406 app
= isl_map_project_out(app
, isl_dim_param
, param
, 1);
408 test
= isl_map_apply_range(isl_map_copy(map
), isl_map_copy(app
));
409 test
= isl_map_union(test
, isl_map_copy(map
));
411 exact
= isl_map_is_subset(app
, test
);
425 /* Compute the positive powers of "map", or an overapproximation.
426 * The power is given by parameter "param". If the result is exact,
427 * then *exact is set to 1.
428 * If project is set, then we are actually interested in the transitive
429 * closure, so we can use a more relaxed exactness check.
431 static __isl_give isl_map
*map_power(__isl_take isl_map
*map
, unsigned param
,
432 int *exact
, int project
)
434 struct isl_set
*domain
= NULL
;
435 struct isl_set
*range
= NULL
;
436 struct isl_map
*app
= NULL
;
437 struct isl_map
*path
= NULL
;
442 map
= isl_map_remove_empty_parts(map
);
446 if (isl_map_fast_is_empty(map
))
449 isl_assert(map
->ctx
, param
< isl_map_dim(map
, isl_dim_param
), goto error
);
451 isl_map_dim(map
, isl_dim_in
) == isl_map_dim(map
, isl_dim_out
),
454 domain
= isl_map_domain(isl_map_copy(map
));
455 domain
= isl_set_coalesce(domain
);
456 range
= isl_map_range(isl_map_copy(map
));
457 range
= isl_set_coalesce(range
);
458 app
= isl_map_from_domain_and_range(isl_set_copy(domain
),
459 isl_set_copy(range
));
461 path
= construct_path(map
, param
);
462 app
= isl_map_intersect(app
, isl_map_copy(path
));
465 (*exact
= check_exactness(isl_map_copy(map
), isl_map_copy(app
),
466 isl_map_copy(path
), param
, project
)) < 0)
469 isl_set_free(domain
);
475 isl_set_free(domain
);
483 /* Compute the positive powers of "map", or an overapproximation.
484 * The power is given by parameter "param". If the result is exact,
485 * then *exact is set to 1.
487 __isl_give isl_map
*isl_map_power(__isl_take isl_map
*map
, unsigned param
,
490 return map_power(map
, param
, exact
, 0);
493 /* Compute the transitive closure of "map", or an overapproximation.
494 * If the result is exact, then *exact is set to 1.
495 * Simply compute the powers of map and then project out the parameter
496 * describing the power.
498 __isl_give isl_map
*isl_map_transitive_closure(__isl_take isl_map
*map
,
506 param
= isl_map_dim(map
, isl_dim_param
);
507 map
= isl_map_add(map
, isl_dim_param
, 1);
508 map
= map_power(map
, param
, exact
, 1);
509 map
= isl_map_project_out(map
, isl_dim_param
, param
, 1);