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