1 | /* |
2 | * Copyright 2010-2011 INRIA Saclay |
3 | * Copyright 2012 Ecole Normale Superieure |
4 | * |
5 | * Use of this software is governed by the MIT 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 | struct isl_tarjan_graph *isl_tarjan_graph_free(struct isl_tarjan_graph *g) |
18 | { |
19 | if (!g) |
20 | return NULL; |
21 | free(ptr: g->node); |
22 | free(ptr: g->stack); |
23 | free(ptr: g->order); |
24 | free(ptr: g); |
25 | return NULL; |
26 | } |
27 | |
28 | static struct isl_tarjan_graph *isl_tarjan_graph_alloc(isl_ctx *ctx, int len) |
29 | { |
30 | struct isl_tarjan_graph *g; |
31 | int i; |
32 | |
33 | g = isl_calloc_type(ctx, struct isl_tarjan_graph); |
34 | if (!g) |
35 | return NULL; |
36 | g->len = len; |
37 | g->node = isl_alloc_array(ctx, struct isl_tarjan_node, len); |
38 | if (len && !g->node) |
39 | goto error; |
40 | for (i = 0; i < len; ++i) |
41 | g->node[i].index = -1; |
42 | g->stack = isl_alloc_array(ctx, int, len); |
43 | if (len && !g->stack) |
44 | goto error; |
45 | g->order = isl_alloc_array(ctx, int, 2 * len); |
46 | if (len && !g->order) |
47 | goto error; |
48 | |
49 | g->sp = 0; |
50 | g->index = 0; |
51 | g->op = 0; |
52 | |
53 | return g; |
54 | error: |
55 | isl_tarjan_graph_free(g); |
56 | return NULL; |
57 | } |
58 | |
59 | /* Perform Tarjan's algorithm for computing the strongly connected components |
60 | * in the graph with g->len nodes and with edges defined by "follows". |
61 | */ |
62 | static isl_stat isl_tarjan_components(struct isl_tarjan_graph *g, int i, |
63 | isl_bool (*follows)(int i, int j, void *user), void *user) |
64 | { |
65 | int j; |
66 | |
67 | g->node[i].index = g->index; |
68 | g->node[i].min_index = g->index; |
69 | g->node[i].on_stack = 1; |
70 | g->index++; |
71 | g->stack[g->sp++] = i; |
72 | |
73 | for (j = g->len - 1; j >= 0; --j) { |
74 | isl_bool f; |
75 | |
76 | if (j == i) |
77 | continue; |
78 | if (g->node[j].index >= 0 && |
79 | (!g->node[j].on_stack || |
80 | g->node[j].index > g->node[i].min_index)) |
81 | continue; |
82 | |
83 | f = follows(i, j, user); |
84 | if (f < 0) |
85 | return isl_stat_error; |
86 | if (!f) |
87 | continue; |
88 | |
89 | if (g->node[j].index < 0) { |
90 | isl_tarjan_components(g, i: j, follows, user); |
91 | if (g->node[j].min_index < g->node[i].min_index) |
92 | g->node[i].min_index = g->node[j].min_index; |
93 | } else if (g->node[j].index < g->node[i].min_index) |
94 | g->node[i].min_index = g->node[j].index; |
95 | } |
96 | |
97 | if (g->node[i].index != g->node[i].min_index) |
98 | return isl_stat_ok; |
99 | |
100 | do { |
101 | j = g->stack[--g->sp]; |
102 | g->node[j].on_stack = 0; |
103 | g->order[g->op++] = j; |
104 | } while (j != i); |
105 | g->order[g->op++] = -1; |
106 | |
107 | return isl_stat_ok; |
108 | } |
109 | |
110 | /* Decompose the graph with "len" nodes and edges defined by "follows" |
111 | * into strongly connected components (SCCs). |
112 | * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise. |
113 | * It should return -1 on error. |
114 | * |
115 | * If SCC a contains a node i that follows a node j in another SCC b |
116 | * (i.e., follows(i, j, user) returns 1), then SCC a will appear after SCC b |
117 | * in the result. |
118 | */ |
119 | struct isl_tarjan_graph *isl_tarjan_graph_init(isl_ctx *ctx, int len, |
120 | isl_bool (*follows)(int i, int j, void *user), void *user) |
121 | { |
122 | int i; |
123 | struct isl_tarjan_graph *g = NULL; |
124 | |
125 | g = isl_tarjan_graph_alloc(ctx, len); |
126 | if (!g) |
127 | return NULL; |
128 | for (i = len - 1; i >= 0; --i) { |
129 | if (g->node[i].index >= 0) |
130 | continue; |
131 | if (isl_tarjan_components(g, i, follows, user) < 0) |
132 | return isl_tarjan_graph_free(g); |
133 | } |
134 | |
135 | return g; |
136 | } |
137 | |
138 | /* Decompose the graph with "len" nodes and edges defined by "follows" |
139 | * into the strongly connected component (SCC) that contains "node" |
140 | * as well as all SCCs that are followed by this SCC. |
141 | * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise. |
142 | * It should return -1 on error. |
143 | * |
144 | * The SCC containing "node" will appear as the last component |
145 | * in g->order. |
146 | */ |
147 | struct isl_tarjan_graph *isl_tarjan_graph_component(isl_ctx *ctx, int len, |
148 | int node, isl_bool (*follows)(int i, int j, void *user), void *user) |
149 | { |
150 | struct isl_tarjan_graph *g; |
151 | |
152 | g = isl_tarjan_graph_alloc(ctx, len); |
153 | if (!g) |
154 | return NULL; |
155 | if (isl_tarjan_components(g, i: node, follows, user) < 0) |
156 | return isl_tarjan_graph_free(g); |
157 | |
158 | return g; |
159 | } |
160 | |