isl_map_transitive_closure: construct general paths
[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 /* Given a union of basic maps R = \cup_i R_i \subseteq D \times D,
277  * construct a map that is an overapproximation of the map
278  * that takes an element from the space D to another
279  * element from the same space, such that the difference between
280  * them is a strictly positive sum of differences between images
281  * and pre-images in one of the R_i.
282  * The number of differences in the sum is equated to parameter "param".
283  * That is, let
284  *
285  *      \Delta_i = { y - x | (x, y) in R_i }
286  *
287  * then the constructed map is an overapproximation of
288  *
289  *      { (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
290  *                              d = \sum_i k_i and k = \sum_i k_i > 0 }
291  *
292  * We first construct an extended mapping with an extra coordinate
293  * that indicates the number of steps taken.  In particular,
294  * the difference in the last coordinate is equal to the number
295  * of steps taken to move from a domain element to the corresponding
296  * image element(s).
297  * In the final step, this difference is equated to the parameter "param"
298  * and made positive.  The extra coordinates are subsequently projected out.
299  *
300  * The elements of the singleton \Delta_i's are collected as the
301  * rows of the steps matrix.  For all these \Delta_i's together,
302  * a single path is constructed.
303  * For each of the other \Delta_i's, we compute an overapproximation
304  * of the paths along elements of \Delta_i.
305  * Since each of these paths performs an addition, composition is
306  * symmetric and we can simply compose all resulting paths in any order.
307  */
308 static __isl_give isl_map *construct_path(__isl_keep isl_map *map,
309         unsigned param)
310 {
311         struct isl_mat *steps = NULL;
312         struct isl_map *path = NULL;
313         struct isl_map *diff;
314         struct isl_dim *dim = NULL;
315         unsigned d;
316         int i, j, n;
317
318         if (!map)
319                 return NULL;
320
321         dim = isl_map_get_dim(map);
322
323         d = isl_dim_size(dim, isl_dim_in);
324         dim = isl_dim_add(dim, isl_dim_in, 1);
325         dim = isl_dim_add(dim, isl_dim_out, 1);
326
327         path = isl_map_identity(isl_dim_domain(isl_dim_copy(dim)));
328
329         steps = isl_mat_alloc(map->ctx, map->n, d);
330         if (!steps)
331                 goto error;
332
333         n = 0;
334         for (i = 0; i < map->n; ++i) {
335                 struct isl_basic_set *delta;
336
337                 delta = isl_basic_map_deltas(isl_basic_map_copy(map->p[i]));
338
339                 for (j = 0; j < d; ++j) {
340                         int fixed;
341
342                         fixed = isl_basic_set_fast_dim_is_fixed(delta, j,
343                                                             &steps->row[n][j]);
344                         if (fixed < 0) {
345                                 isl_basic_set_free(delta);
346                                 goto error;
347                         }
348                         if (!fixed)
349                                 break;
350                 }
351
352
353                 if (j < d) {
354                         path = isl_map_apply_range(path,
355                                 path_along_delta(isl_dim_copy(dim), delta));
356                 } else {
357                         isl_basic_set_free(delta);
358                         ++n;
359                 }
360         }
361
362         if (n > 0) {
363                 steps->n_row = n;
364                 path = isl_map_apply_range(path,
365                                 path_along_steps(isl_dim_copy(dim), steps));
366         }
367
368         diff = equate_parameter_to_length(dim, param);
369         path = isl_map_intersect(path, diff);
370         path = isl_map_project_out(path, isl_dim_in, d, 1);
371         path = isl_map_project_out(path, isl_dim_out, d, 1);
372
373         isl_mat_free(steps);
374         return path;
375 error:
376         isl_dim_free(dim);
377         isl_map_free(path);
378         return NULL;
379 }
380
381 /* Check whether "path" is acyclic.
382  * That is, check whether
383  *
384  *      { d | d = y - x and (x,y) in path }
385  *
386  * does not contain the origin.
387  */
388 static int is_acyclic(__isl_take isl_map *path)
389 {
390         int i;
391         int acyclic;
392         unsigned dim;
393         struct isl_set *delta;
394
395         delta = isl_map_deltas(path);
396         dim = isl_set_dim(delta, isl_dim_set);
397         for (i = 0; i < dim; ++i)
398                 delta = isl_set_fix_si(delta, isl_dim_set, i, 0);
399
400         acyclic = isl_set_is_empty(delta);
401         isl_set_free(delta);
402
403         return acyclic;
404 }
405
406 /* Shift variable at position "pos" up by one.
407  * That is, replace the corresponding variable v by v - 1.
408  */
409 static __isl_give isl_basic_map *basic_map_shift_pos(
410         __isl_take isl_basic_map *bmap, unsigned pos)
411 {
412         int i;
413
414         bmap = isl_basic_map_cow(bmap);
415         if (!bmap)
416                 return NULL;
417
418         for (i = 0; i < bmap->n_eq; ++i)
419                 isl_int_sub(bmap->eq[i][0], bmap->eq[i][0], bmap->eq[i][pos]);
420
421         for (i = 0; i < bmap->n_ineq; ++i)
422                 isl_int_sub(bmap->ineq[i][0],
423                                 bmap->ineq[i][0], bmap->ineq[i][pos]);
424
425         for (i = 0; i < bmap->n_div; ++i) {
426                 if (isl_int_is_zero(bmap->div[i][0]))
427                         continue;
428                 isl_int_sub(bmap->div[i][1],
429                                 bmap->div[i][1], bmap->div[i][1 + pos]);
430         }
431
432         return bmap;
433 }
434
435 /* Shift variable at position "pos" up by one.
436  * That is, replace the corresponding variable v by v - 1.
437  */
438 static __isl_give isl_map *map_shift_pos(__isl_take isl_map *map, unsigned pos)
439 {
440         int i;
441
442         map = isl_map_cow(map);
443         if (!map)
444                 return NULL;
445
446         for (i = 0; i < map->n; ++i) {
447                 map->p[i] = basic_map_shift_pos(map->p[i], pos);
448                 if (!map->p[i])
449                         goto error;
450         }
451         ISL_F_CLR(map, ISL_MAP_NORMALIZED);
452         return map;
453 error:
454         isl_map_free(map);
455         return NULL;
456 }
457
458 /* Check whether the overapproximation of the power of "map" is exactly
459  * the power of "map".  Let R be "map" and A_k the overapproximation.
460  * The approximation is exact if
461  *
462  *      A_1 = R
463  *      A_k = A_{k-1} \circ R                   k >= 2
464  *
465  * Since A_k is known to be an overapproximation, we only need to check
466  *
467  *      A_1 \subset R
468  *      A_k \subset A_{k-1} \circ R             k >= 2
469  *
470  */
471 static int check_power_exactness(__isl_take isl_map *map,
472         __isl_take isl_map *app, unsigned param)
473 {
474         int exact;
475         isl_map *app_1;
476         isl_map *app_2;
477
478         app_1 = isl_map_fix_si(isl_map_copy(app), isl_dim_param, param, 1);
479
480         exact = isl_map_is_subset(app_1, map);
481         isl_map_free(app_1);
482
483         if (!exact || exact < 0) {
484                 isl_map_free(app);
485                 isl_map_free(map);
486                 return exact;
487         }
488
489         app_2 = isl_map_lower_bound_si(isl_map_copy(app),
490                                         isl_dim_param, param, 2);
491         app_1 = map_shift_pos(app, 1 + param);
492         app_1 = isl_map_apply_range(map, app_1);
493
494         exact = isl_map_is_subset(app_2, app_1);
495
496         isl_map_free(app_1);
497         isl_map_free(app_2);
498
499         return exact;
500 }
501
502 /* Check whether the overapproximation of the power of "map" is exactly
503  * the power of "map", possibly after projecting out the power (if "project"
504  * is set).
505  *
506  * If "project" is set and if "steps" can only result in acyclic paths,
507  * then we check
508  *
509  *      A = R \cup (A \circ R)
510  *
511  * where A is the overapproximation with the power projected out, i.e.,
512  * an overapproximation of the transitive closure.
513  * More specifically, since A is known to be an overapproximation, we check
514  *
515  *      A \subset R \cup (A \circ R)
516  *
517  * Otherwise, we check if the power is exact.
518  */
519 static int check_exactness(__isl_take isl_map *map, __isl_take isl_map *app,
520         __isl_take isl_map *path, unsigned param, int project)
521 {
522         isl_map *test;
523         int exact;
524
525         if (project) {
526                 project = is_acyclic(path);
527                 if (project < 0)
528                         goto error;
529         } else
530                 isl_map_free(path);
531
532         if (!project)
533                 return check_power_exactness(map, app, param);
534
535         map = isl_map_project_out(map, isl_dim_param, param, 1);
536         app = isl_map_project_out(app, isl_dim_param, param, 1);
537
538         test = isl_map_apply_range(isl_map_copy(map), isl_map_copy(app));
539         test = isl_map_union(test, isl_map_copy(map));
540
541         exact = isl_map_is_subset(app, test);
542
543         isl_map_free(app);
544         isl_map_free(test);
545
546         isl_map_free(map);
547
548         return exact;
549 error:
550         isl_map_free(app);
551         isl_map_free(map);
552         return -1;
553 }
554
555 /* Compute the positive powers of "map", or an overapproximation.
556  * The power is given by parameter "param".  If the result is exact,
557  * then *exact is set to 1.
558  * If project is set, then we are actually interested in the transitive
559  * closure, so we can use a more relaxed exactness check.
560  */
561 static __isl_give isl_map *map_power(__isl_take isl_map *map, unsigned param,
562         int *exact, int project)
563 {
564         struct isl_set *domain = NULL;
565         struct isl_set *range = NULL;
566         struct isl_map *app = NULL;
567         struct isl_map *path = NULL;
568
569         if (exact)
570                 *exact = 1;
571
572         map = isl_map_remove_empty_parts(map);
573         if (!map)
574                 return NULL;
575
576         if (isl_map_fast_is_empty(map))
577                 return map;
578
579         isl_assert(map->ctx, param < isl_map_dim(map, isl_dim_param), goto error);
580         isl_assert(map->ctx,
581                 isl_map_dim(map, isl_dim_in) == isl_map_dim(map, isl_dim_out),
582                 goto error);
583
584         domain = isl_map_domain(isl_map_copy(map));
585         domain = isl_set_coalesce(domain);
586         range = isl_map_range(isl_map_copy(map));
587         range = isl_set_coalesce(range);
588         app = isl_map_from_domain_and_range(isl_set_copy(domain),
589                                             isl_set_copy(range));
590
591         path = construct_path(map, param);
592         app = isl_map_intersect(app, isl_map_copy(path));
593
594         if (exact &&
595             (*exact = check_exactness(isl_map_copy(map), isl_map_copy(app),
596                                   isl_map_copy(path), param, project)) < 0)
597                 goto error;
598
599         isl_set_free(domain);
600         isl_set_free(range);
601         isl_map_free(path);
602         isl_map_free(map);
603         return app;
604 error:
605         isl_set_free(domain);
606         isl_set_free(range);
607         isl_map_free(path);
608         isl_map_free(map);
609         isl_map_free(app);
610         return NULL;
611 }
612
613 /* Compute the positive powers of "map", or an overapproximation.
614  * The power is given by parameter "param".  If the result is exact,
615  * then *exact is set to 1.
616  */
617 __isl_give isl_map *isl_map_power(__isl_take isl_map *map, unsigned param,
618         int *exact)
619 {
620         return map_power(map, param, exact, 0);
621 }
622
623 /* Compute the transitive closure  of "map", or an overapproximation.
624  * If the result is exact, then *exact is set to 1.
625  * Simply compute the powers of map and then project out the parameter
626  * describing the power.
627  */
628 __isl_give isl_map *isl_map_transitive_closure(__isl_take isl_map *map,
629         int *exact)
630 {
631         unsigned param;
632
633         if (!map)
634                 goto error;
635
636         param = isl_map_dim(map, isl_dim_param);
637         map = isl_map_add(map, isl_dim_param, 1);
638         map = map_power(map, param, exact, 1);
639         map = isl_map_project_out(map, isl_dim_param, param, 1);
640
641         return map;
642 error:
643         isl_map_free(map);
644         return NULL;
645 }