75c21fd5ec423103d0d3408bce3dd71f0852ddaa
[platform/upstream/isl.git] / isl_transitive_closure.c
1 /*
2  * Copyright 2010      INRIA Saclay
3  *
4  * Use of this software is governed by the GNU LGPLv2.1 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_map.h"
12 #include "isl_map_private.h"
13 #include "isl_seq.h"
14  
15 /*
16  * The transitive closure implementation is based on the paper
17  * "Computing the Transitive Closure of a Union of Affine Integer
18  * Tuple Relations" by Anna Beletska, Denis Barthou, Wlodzimierz Bielecki and
19  * Albert Cohen.
20  */
21
22 /* Given a set of n offsets v_i (the rows of "steps"), construct a relation
23  * of the given dimension specification (Z^{n+1} -> Z^{n+1})
24  * that maps an element x to any element that can be reached
25  * by taking a non-negative number of steps along any of
26  * the extended offsets v'_i = [v_i 1].
27  * That is, construct
28  *
29  * { [x] -> [y] : exists k_i >= 0, y = x + \sum_i k_i v'_i }
30  *
31  * For any element in this relation, the number of steps taken
32  * is equal to the difference in the final coordinates.
33  */
34 static __isl_give isl_map *path_along_steps(__isl_take isl_dim *dim,
35         __isl_keep isl_mat *steps)
36 {
37         int i, j, k;
38         struct isl_basic_map *path = NULL;
39         unsigned d;
40         unsigned n;
41         unsigned nparam;
42
43         if (!dim || !steps)
44                 goto error;
45
46         d = isl_dim_size(dim, isl_dim_in);
47         n = steps->n_row;
48         nparam = isl_dim_size(dim, isl_dim_param);
49
50         path = isl_basic_map_alloc_dim(isl_dim_copy(dim), n, d, n);
51
52         for (i = 0; i < n; ++i) {
53                 k = isl_basic_map_alloc_div(path);
54                 if (k < 0)
55                         goto error;
56                 isl_assert(steps->ctx, i == k, goto error);
57                 isl_int_set_si(path->div[k][0], 0);
58         }
59
60         for (i = 0; i < d; ++i) {
61                 k = isl_basic_map_alloc_equality(path);
62                 if (k < 0)
63                         goto error;
64                 isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path));
65                 isl_int_set_si(path->eq[k][1 + nparam + i], 1);
66                 isl_int_set_si(path->eq[k][1 + nparam + d + i], -1);
67                 if (i == d - 1)
68                         for (j = 0; j < n; ++j)
69                                 isl_int_set_si(path->eq[k][1 + nparam + 2 * d + j], 1);
70                 else
71                         for (j = 0; j < n; ++j)
72                                 isl_int_set(path->eq[k][1 + nparam + 2 * d + j],
73                                             steps->row[j][i]);
74         }
75
76         for (i = 0; i < n; ++i) {
77                 k = isl_basic_map_alloc_inequality(path);
78                 if (k < 0)
79                         goto error;
80                 isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path));
81                 isl_int_set_si(path->ineq[k][1 + nparam + 2 * d + i], 1);
82         }
83
84         isl_dim_free(dim);
85
86         path = isl_basic_map_simplify(path);
87         path = isl_basic_map_finalize(path);
88         return isl_map_from_basic_map(path);
89 error:
90         isl_dim_free(dim);
91         isl_basic_map_free(path);
92         return NULL;
93 }
94
95 #define IMPURE          0
96 #define PURE_PARAM      1
97 #define PURE_VAR        2
98
99 /* Return PURE_PARAM if only the coefficients of the parameters are non-zero.
100  * Return PURE_VAR if only the coefficients of the set variables are non-zero.
101  * Return IMPURE otherwise.
102  */
103 static int purity(__isl_keep isl_basic_set *bset, isl_int *c)
104 {
105         unsigned d;
106         unsigned n_div;
107         unsigned nparam;
108
109         n_div = isl_basic_set_dim(bset, isl_dim_div);
110         d = isl_basic_set_dim(bset, isl_dim_set);
111         nparam = isl_basic_set_dim(bset, isl_dim_param);
112
113         if (isl_seq_first_non_zero(c + 1 + nparam + d, n_div) != -1)
114                 return IMPURE;
115         if (isl_seq_first_non_zero(c + 1, nparam) == -1)
116                 return PURE_VAR;
117         if (isl_seq_first_non_zero(c + 1 + nparam, d) == -1)
118                 return PURE_PARAM;
119         return IMPURE;
120 }
121
122 /* Given a set of offsets "delta", construct a relation of the
123  * given dimension specification (Z^{n+1} -> Z^{n+1}) that
124  * is an overapproximation of the relations that
125  * maps an element x to any element that can be reached
126  * by taking a non-negative number of steps along any of
127  * the elements in "delta".
128  * That is, construct an approximation of
129  *
130  *      { [x] -> [y] : exists f \in \delta, k \in Z :
131  *                                      y = x + k [f, 1] and k >= 0 }
132  *
133  * For any element in this relation, the number of steps taken
134  * is equal to the difference in the final coordinates.
135  *
136  * In particular, let delta be defined as
137  *
138  *      \delta = [p] -> { [x] : A x + a >= and B p + b >= 0 and
139  *                              C x + C'p + c >= 0 }
140  *
141  * then the relation is constructed as
142  *
143  *      { [x] -> [y] : exists [f, k] \in Z^{n+1} : y = x + f and
144  *                      A f + k a >= 0 and B p + b >= 0 and k >= 1 }
145  *      union { [x] -> [x] }
146  *
147  * Existentially quantified variables in \delta are currently ignored.
148  * This is safe, but leads to an additional overapproximation.
149  */
150 static __isl_give isl_map *path_along_delta(__isl_take isl_dim *dim,
151         __isl_take isl_basic_set *delta)
152 {
153         isl_basic_map *path = NULL;
154         unsigned d;
155         unsigned n_div;
156         unsigned nparam;
157         unsigned off;
158         int i, k;
159
160         if (!delta)
161                 goto error;
162         n_div = isl_basic_set_dim(delta, isl_dim_div);
163         d = isl_basic_set_dim(delta, isl_dim_set);
164         nparam = isl_basic_set_dim(delta, isl_dim_param);
165         path = isl_basic_map_alloc_dim(isl_dim_copy(dim), n_div + d + 1,
166                         d + 1 + delta->n_eq, delta->n_ineq + 1);
167         off = 1 + nparam + 2 * (d + 1) + n_div;
168
169         for (i = 0; i < n_div + d + 1; ++i) {
170                 k = isl_basic_map_alloc_div(path);
171                 if (k < 0)
172                         goto error;
173                 isl_int_set_si(path->div[k][0], 0);
174         }
175
176         for (i = 0; i < d + 1; ++i) {
177                 k = isl_basic_map_alloc_equality(path);
178                 if (k < 0)
179                         goto error;
180                 isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path));
181                 isl_int_set_si(path->eq[k][1 + nparam + i], 1);
182                 isl_int_set_si(path->eq[k][1 + nparam + d + 1 + i], -1);
183                 isl_int_set_si(path->eq[k][off + i], 1);
184         }
185
186         for (i = 0; i < delta->n_eq; ++i) {
187                 int p = purity(delta, delta->eq[i]);
188                 if (p == IMPURE)
189                         continue;
190                 k = isl_basic_map_alloc_equality(path);
191                 if (k < 0)
192                         goto error;
193                 isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path));
194                 if (p == PURE_VAR) {
195                         isl_seq_cpy(path->eq[k] + off,
196                                     delta->eq[i] + 1 + nparam, d);
197                         isl_int_set(path->eq[k][off + d], delta->eq[i][0]);
198                 } else
199                         isl_seq_cpy(path->eq[k], delta->eq[i], 1 + nparam);
200         }
201
202         for (i = 0; i < delta->n_ineq; ++i) {
203                 int p = purity(delta, delta->ineq[i]);
204                 if (p == IMPURE)
205                         continue;
206                 k = isl_basic_map_alloc_inequality(path);
207                 if (k < 0)
208                         goto error;
209                 isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path));
210                 if (p == PURE_VAR) {
211                         isl_seq_cpy(path->ineq[k] + off,
212                                     delta->ineq[i] + 1 + nparam, d);
213                         isl_int_set(path->ineq[k][off + d], delta->ineq[i][0]);
214                 } else
215                         isl_seq_cpy(path->ineq[k], delta->ineq[i], 1 + nparam);
216         }
217
218         k = isl_basic_map_alloc_inequality(path);
219         if (k < 0)
220                 goto error;
221         isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path));
222         isl_int_set_si(path->ineq[k][0], -1);
223         isl_int_set_si(path->ineq[k][off + d], 1);
224                         
225         isl_basic_set_free(delta);
226         path = isl_basic_map_finalize(path);
227         return isl_basic_map_union(path,
228                                 isl_basic_map_identity(isl_dim_domain(dim)));
229 error:
230         isl_dim_free(dim);
231         isl_basic_set_free(delta);
232         isl_basic_map_free(path);
233         return NULL;
234 }
235
236 /* Given a dimenion specification Z^{n+1} -> Z^{n+1} and a parameter "param",
237  * construct a map that equates the parameter to the difference
238  * in the final coordinates and imposes that this difference is positive.
239  * That is, construct
240  *
241  *      { [x,x_s] -> [y,y_s] : k = y_s - x_s > 0 }
242  */
243 static __isl_give isl_map *equate_parameter_to_length(__isl_take isl_dim *dim,
244         unsigned param)
245 {
246         struct isl_basic_map *bmap;
247         unsigned d;
248         unsigned nparam;
249         int k;
250
251         d = isl_dim_size(dim, isl_dim_in);
252         nparam = isl_dim_size(dim, isl_dim_param);
253         bmap = isl_basic_map_alloc_dim(dim, 0, 1, 1);
254         k = isl_basic_map_alloc_equality(bmap);
255         if (k < 0)
256                 goto error;
257         isl_seq_clr(bmap->eq[k], 1 + isl_basic_map_total_dim(bmap));
258         isl_int_set_si(bmap->eq[k][1 + param], -1);
259         isl_int_set_si(bmap->eq[k][1 + nparam + d - 1], -1);
260         isl_int_set_si(bmap->eq[k][1 + nparam + d + d - 1], 1);
261
262         k = isl_basic_map_alloc_inequality(bmap);
263         if (k < 0)
264                 goto error;
265         isl_seq_clr(bmap->ineq[k], 1 + isl_basic_map_total_dim(bmap));
266         isl_int_set_si(bmap->ineq[k][1 + param], 1);
267         isl_int_set_si(bmap->ineq[k][0], -1);
268
269         bmap = isl_basic_map_finalize(bmap);
270         return isl_map_from_basic_map(bmap);
271 error:
272         isl_basic_map_free(bmap);
273         return NULL;
274 }
275
276 /* Check whether "path" is acyclic, where the last coordinates of domain
277  * and range of path encode the number of steps taken.
278  * That is, check whether
279  *
280  *      { d | d = y - x and (x,y) in path }
281  *
282  * does not contain any element with positive last coordinate (positive length)
283  * and zero remaining coordinates (cycle).
284  */
285 static int is_acyclic(__isl_take isl_map *path)
286 {
287         int i;
288         int acyclic;
289         unsigned dim;
290         struct isl_set *delta;
291
292         delta = isl_map_deltas(path);
293         dim = isl_set_dim(delta, isl_dim_set);
294         for (i = 0; i < dim; ++i) {
295                 if (i == dim -1)
296                         delta = isl_set_lower_bound_si(delta, isl_dim_set, i, 1);
297                 else
298                         delta = isl_set_fix_si(delta, isl_dim_set, i, 0);
299         }
300
301         acyclic = isl_set_is_empty(delta);
302         isl_set_free(delta);
303
304         return acyclic;
305 }
306
307 /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D,
308  * construct a map that is an overapproximation of the map
309  * that takes an element from the space D to another
310  * element from the same space, such that the difference between
311  * them is a strictly positive sum of differences between images
312  * and pre-images in one of the R_i.
313  * The number of differences in the sum is equated to parameter "param".
314  * That is, let
315  *
316  *      \Delta_i = { y - x | (x, y) in R_i }
317  *
318  * then the constructed map is an overapproximation of
319  *
320  *      { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
321  *                              d = \sum_i k_i and k = \sum_i k_i > 0 }
322  *
323  * We first construct an extended mapping with an extra coordinate
324  * that indicates the number of steps taken.  In particular,
325  * the difference in the last coordinate is equal to the number
326  * of steps taken to move from a domain element to the corresponding
327  * image element(s).
328  * In the final step, this difference is equated to the parameter "param"
329  * and made positive.  The extra coordinates are subsequently projected out.
330  *
331  * The elements of the singleton \Delta_i's are collected as the
332  * rows of the steps matrix.  For all these \Delta_i's together,
333  * a single path is constructed.
334  * For each of the other \Delta_i's, we compute an overapproximation
335  * of the paths along elements of \Delta_i.
336  * Since each of these paths performs an addition, composition is
337  * symmetric and we can simply compose all resulting paths in any order.
338  */
339 static __isl_give isl_map *construct_path(__isl_keep isl_map *map,
340         unsigned param, int *project)
341 {
342         struct isl_mat *steps = NULL;
343         struct isl_map *path = NULL;
344         struct isl_map *diff;
345         struct isl_dim *dim = NULL;
346         unsigned d;
347         int i, j, n;
348
349         if (!map)
350                 return NULL;
351
352         dim = isl_map_get_dim(map);
353
354         d = isl_dim_size(dim, isl_dim_in);
355         dim = isl_dim_add(dim, isl_dim_in, 1);
356         dim = isl_dim_add(dim, isl_dim_out, 1);
357
358         path = isl_map_identity(isl_dim_domain(isl_dim_copy(dim)));
359
360         steps = isl_mat_alloc(map->ctx, map->n, d);
361         if (!steps)
362                 goto error;
363
364         n = 0;
365         for (i = 0; i < map->n; ++i) {
366                 struct isl_basic_set *delta;
367
368                 delta = isl_basic_map_deltas(isl_basic_map_copy(map->p[i]));
369
370                 for (j = 0; j < d; ++j) {
371                         int fixed;
372
373                         fixed = isl_basic_set_fast_dim_is_fixed(delta, j,
374                                                             &steps->row[n][j]);
375                         if (fixed < 0) {
376                                 isl_basic_set_free(delta);
377                                 goto error;
378                         }
379                         if (!fixed)
380                                 break;
381                 }
382
383
384                 if (j < d) {
385                         path = isl_map_apply_range(path,
386                                 path_along_delta(isl_dim_copy(dim), delta));
387                 } else {
388                         isl_basic_set_free(delta);
389                         ++n;
390                 }
391         }
392
393         if (n > 0) {
394                 steps->n_row = n;
395                 path = isl_map_apply_range(path,
396                                 path_along_steps(isl_dim_copy(dim), steps));
397         }
398
399         if (project && *project) {
400                 *project = is_acyclic(isl_map_copy(path));
401                 if (*project < 0)
402                         goto error;
403         }
404
405         diff = equate_parameter_to_length(dim, param);
406         path = isl_map_intersect(path, diff);
407         path = isl_map_project_out(path, isl_dim_in, d, 1);
408         path = isl_map_project_out(path, isl_dim_out, d, 1);
409
410         isl_mat_free(steps);
411         return path;
412 error:
413         isl_dim_free(dim);
414         isl_map_free(path);
415         return NULL;
416 }
417
418 /* Shift variable at position "pos" up by one.
419  * That is, replace the corresponding variable v by v - 1.
420  */
421 static __isl_give isl_basic_map *basic_map_shift_pos(
422         __isl_take isl_basic_map *bmap, unsigned pos)
423 {
424         int i;
425
426         bmap = isl_basic_map_cow(bmap);
427         if (!bmap)
428                 return NULL;
429
430         for (i = 0; i < bmap->n_eq; ++i)
431                 isl_int_sub(bmap->eq[i][0], bmap->eq[i][0], bmap->eq[i][pos]);
432
433         for (i = 0; i < bmap->n_ineq; ++i)
434                 isl_int_sub(bmap->ineq[i][0],
435                                 bmap->ineq[i][0], bmap->ineq[i][pos]);
436
437         for (i = 0; i < bmap->n_div; ++i) {
438                 if (isl_int_is_zero(bmap->div[i][0]))
439                         continue;
440                 isl_int_sub(bmap->div[i][1],
441                                 bmap->div[i][1], bmap->div[i][1 + pos]);
442         }
443
444         return bmap;
445 }
446
447 /* Shift variable at position "pos" up by one.
448  * That is, replace the corresponding variable v by v - 1.
449  */
450 static __isl_give isl_map *map_shift_pos(__isl_take isl_map *map, unsigned pos)
451 {
452         int i;
453
454         map = isl_map_cow(map);
455         if (!map)
456                 return NULL;
457
458         for (i = 0; i < map->n; ++i) {
459                 map->p[i] = basic_map_shift_pos(map->p[i], pos);
460                 if (!map->p[i])
461                         goto error;
462         }
463         ISL_F_CLR(map, ISL_MAP_NORMALIZED);
464         return map;
465 error:
466         isl_map_free(map);
467         return NULL;
468 }
469
470 /* Check whether the overapproximation of the power of "map" is exactly
471  * the power of "map".  Let R be "map" and A_k the overapproximation.
472  * The approximation is exact if
473  *
474  *      A_1 = R
475  *      A_k = A_{k-1} \circ R                   k >= 2
476  *
477  * Since A_k is known to be an overapproximation, we only need to check
478  *
479  *      A_1 \subset R
480  *      A_k \subset A_{k-1} \circ R             k >= 2
481  *
482  */
483 static int check_power_exactness(__isl_take isl_map *map,
484         __isl_take isl_map *app, unsigned param)
485 {
486         int exact;
487         isl_map *app_1;
488         isl_map *app_2;
489
490         app_1 = isl_map_fix_si(isl_map_copy(app), isl_dim_param, param, 1);
491
492         exact = isl_map_is_subset(app_1, map);
493         isl_map_free(app_1);
494
495         if (!exact || exact < 0) {
496                 isl_map_free(app);
497                 isl_map_free(map);
498                 return exact;
499         }
500
501         app_2 = isl_map_lower_bound_si(isl_map_copy(app),
502                                         isl_dim_param, param, 2);
503         app_1 = map_shift_pos(app, 1 + param);
504         app_1 = isl_map_apply_range(map, app_1);
505
506         exact = isl_map_is_subset(app_2, app_1);
507
508         isl_map_free(app_1);
509         isl_map_free(app_2);
510
511         return exact;
512 }
513
514 /* Check whether the overapproximation of the power of "map" is exactly
515  * the power of "map", possibly after projecting out the power (if "project"
516  * is set).
517  *
518  * If "project" is set and if "steps" can only result in acyclic paths,
519  * then we check
520  *
521  *      A = R \cup (A \circ R)
522  *
523  * where A is the overapproximation with the power projected out, i.e.,
524  * an overapproximation of the transitive closure.
525  * More specifically, since A is known to be an overapproximation, we check
526  *
527  *      A \subset R \cup (A \circ R)
528  *
529  * Otherwise, we check if the power is exact.
530  */
531 static int check_exactness(__isl_take isl_map *map, __isl_take isl_map *app,
532         unsigned param, int project)
533 {
534         isl_map *test;
535         int exact;
536
537         if (!project)
538                 return check_power_exactness(map, app, param);
539
540         map = isl_map_project_out(map, isl_dim_param, param, 1);
541         app = isl_map_project_out(app, isl_dim_param, param, 1);
542
543         test = isl_map_apply_range(isl_map_copy(map), isl_map_copy(app));
544         test = isl_map_union(test, isl_map_copy(map));
545
546         exact = isl_map_is_subset(app, test);
547
548         isl_map_free(app);
549         isl_map_free(test);
550
551         isl_map_free(map);
552
553         return exact;
554 error:
555         isl_map_free(app);
556         isl_map_free(map);
557         return -1;
558 }
559
560 /* Compute the positive powers of "map", or an overapproximation.
561  * The power is given by parameter "param".  If the result is exact,
562  * then *exact is set to 1.
563  * If project is set, then we are actually interested in the transitive
564  * closure, so we can use a more relaxed exactness check.
565  */
566 static __isl_give isl_map *map_power(__isl_take isl_map *map, unsigned param,
567         int *exact, int project)
568 {
569         struct isl_set *domain = NULL;
570         struct isl_set *range = NULL;
571         struct isl_map *app = NULL;
572         struct isl_map *path = NULL;
573
574         if (exact)
575                 *exact = 1;
576
577         map = isl_map_remove_empty_parts(map);
578         if (!map)
579                 return NULL;
580
581         if (isl_map_fast_is_empty(map))
582                 return map;
583
584         isl_assert(map->ctx, param < isl_map_dim(map, isl_dim_param), goto error);
585         isl_assert(map->ctx,
586                 isl_map_dim(map, isl_dim_in) == isl_map_dim(map, isl_dim_out),
587                 goto error);
588
589         domain = isl_map_domain(isl_map_copy(map));
590         domain = isl_set_coalesce(domain);
591         range = isl_map_range(isl_map_copy(map));
592         range = isl_set_coalesce(range);
593         app = isl_map_from_domain_and_range(isl_set_copy(domain),
594                                             isl_set_copy(range));
595
596         path = construct_path(map, param, exact ? &project : NULL);
597         app = isl_map_intersect(app, isl_map_copy(path));
598
599         if (exact &&
600             (*exact = check_exactness(isl_map_copy(map), isl_map_copy(app),
601                                       param, project)) < 0)
602                 goto error;
603
604         isl_set_free(domain);
605         isl_set_free(range);
606         isl_map_free(path);
607         isl_map_free(map);
608         return app;
609 error:
610         isl_set_free(domain);
611         isl_set_free(range);
612         isl_map_free(path);
613         isl_map_free(map);
614         isl_map_free(app);
615         return NULL;
616 }
617
618 /* Compute the positive powers of "map", or an overapproximation.
619  * The power is given by parameter "param".  If the result is exact,
620  * then *exact is set to 1.
621  */
622 __isl_give isl_map *isl_map_power(__isl_take isl_map *map, unsigned param,
623         int *exact)
624 {
625         return map_power(map, param, exact, 0);
626 }
627
628 /* Compute the transitive closure  of "map", or an overapproximation.
629  * If the result is exact, then *exact is set to 1.
630  * Simply compute the powers of map and then project out the parameter
631  * describing the power.
632  */
633 __isl_give isl_map *isl_map_transitive_closure(__isl_take isl_map *map,
634         int *exact)
635 {
636         unsigned param;
637
638         if (!map)
639                 goto error;
640
641         param = isl_map_dim(map, isl_dim_param);
642         map = isl_map_add(map, isl_dim_param, 1);
643         map = map_power(map, param, exact, 1);
644         map = isl_map_project_out(map, isl_dim_param, param, 1);
645
646         return map;
647 error:
648         isl_map_free(map);
649         return NULL;
650 }