847b83b5a983c8847410cb93e3af257037f008f3
[platform/upstream/isl.git] / isl_tarjan.c
1 /*
2  * Copyright 2010-2011 INRIA Saclay
3  * Copyright 2012      Ecole Normale Superieure
4  *
5  * Use of this software is governed by the GNU LGPLv2.1 license
6  *
7  * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
8  * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
9  * 91893 Orsay, France
10  * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
11  */
12
13 #include <stdlib.h>
14 #include <isl/ctx.h>
15 #include <isl_tarjan.h>
16
17 void isl_tarjan_graph_free(struct isl_tarjan_graph *g)
18 {
19         if (!g)
20                 return;
21         free(g->node);
22         free(g->stack);
23         free(g->order);
24         free(g);
25 }
26
27 static struct isl_tarjan_graph *isl_tarjan_graph_alloc(isl_ctx *ctx, int len)
28 {
29         struct isl_tarjan_graph *g;
30         int i;
31
32         g = isl_calloc_type(ctx, struct isl_tarjan_graph);
33         if (!g)
34                 return NULL;
35         g->len = len;
36         g->node = isl_alloc_array(ctx, struct isl_tarjan_node, len);
37         if (!g->node)
38                 goto error;
39         for (i = 0; i < len; ++i)
40                 g->node[i].index = -1;
41         g->stack = isl_alloc_array(ctx, int, len);
42         if (!g->stack)
43                 goto error;
44         g->order = isl_alloc_array(ctx, int, 2 * len);
45         if (!g->order)
46                 goto error;
47
48         g->sp = 0;
49         g->index = 0;
50         g->op = 0;
51
52         return g;
53 error:
54         isl_tarjan_graph_free(g);
55         return NULL;
56 }
57
58 /* Perform Tarjan's algorithm for computing the strongly connected components
59  * in the graph with g->len nodes and with edges defined by "follows".
60  */
61 static int isl_tarjan_components(struct isl_tarjan_graph *g, int i,
62         int (*follows)(int i, int j, void *user), void *user)
63 {
64         int j;
65
66         g->node[i].index = g->index;
67         g->node[i].min_index = g->index;
68         g->node[i].on_stack = 1;
69         g->index++;
70         g->stack[g->sp++] = i;
71
72         for (j = g->len - 1; j >= 0; --j) {
73                 int f;
74
75                 if (j == i)
76                         continue;
77                 if (g->node[j].index >= 0 &&
78                         (!g->node[j].on_stack ||
79                          g->node[j].index > g->node[i].min_index))
80                         continue;
81
82                 f = follows(i, j, user);
83                 if (f < 0)
84                         return -1;
85                 if (!f)
86                         continue;
87
88                 if (g->node[j].index < 0) {
89                         isl_tarjan_components(g, j, follows, user);
90                         if (g->node[j].min_index < g->node[i].min_index)
91                                 g->node[i].min_index = g->node[j].min_index;
92                 } else if (g->node[j].index < g->node[i].min_index)
93                         g->node[i].min_index = g->node[j].index;
94         }
95
96         if (g->node[i].index != g->node[i].min_index)
97                 return 0;
98
99         do {
100                 j = g->stack[--g->sp];
101                 g->node[j].on_stack = 0;
102                 g->order[g->op++] = j;
103         } while (j != i);
104         g->order[g->op++] = -1;
105
106         return 0;
107 }
108
109 /* Decompose the graph with "len" nodes and edges defined by "follows"
110  * into strongly connected components.
111  */
112 struct isl_tarjan_graph *isl_tarjan_graph_init(isl_ctx *ctx, int len,
113         int (*follows)(int i, int j, void *user), void *user)
114 {
115         int i;
116         struct isl_tarjan_graph *g = NULL;
117
118         g = isl_tarjan_graph_alloc(ctx, len);
119         if (!g)
120                 return NULL;
121         for (i = len - 1; i >= 0; --i) {
122                 if (g->node[i].index >= 0)
123                         continue;
124                 if (isl_tarjan_components(g, i, follows, user) < 0)
125                         goto error;
126         }
127
128         return g;
129 error:
130         isl_tarjan_graph_free(g);
131         return NULL;
132 }