152a25237STobias Grosser /*
252a25237STobias Grosser * Copyright 2010-2011 INRIA Saclay
352a25237STobias Grosser * Copyright 2012 Ecole Normale Superieure
452a25237STobias Grosser *
552a25237STobias Grosser * Use of this software is governed by the MIT license
652a25237STobias Grosser *
752a25237STobias Grosser * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
852a25237STobias Grosser * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
952a25237STobias Grosser * 91893 Orsay, France
1052a25237STobias Grosser * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
1152a25237STobias Grosser */
1252a25237STobias Grosser
1352a25237STobias Grosser #include <stdlib.h>
1452a25237STobias Grosser #include <isl/ctx.h>
1552a25237STobias Grosser #include <isl_tarjan.h>
1652a25237STobias Grosser
isl_tarjan_graph_free(struct isl_tarjan_graph * g)17*a7f1e040STobias Grosser struct isl_tarjan_graph *isl_tarjan_graph_free(struct isl_tarjan_graph *g)
1852a25237STobias Grosser {
1952a25237STobias Grosser if (!g)
20*a7f1e040STobias Grosser return NULL;
2152a25237STobias Grosser free(g->node);
2252a25237STobias Grosser free(g->stack);
2352a25237STobias Grosser free(g->order);
2452a25237STobias Grosser free(g);
25*a7f1e040STobias Grosser return NULL;
2652a25237STobias Grosser }
2752a25237STobias Grosser
isl_tarjan_graph_alloc(isl_ctx * ctx,int len)2852a25237STobias Grosser static struct isl_tarjan_graph *isl_tarjan_graph_alloc(isl_ctx *ctx, int len)
2952a25237STobias Grosser {
3052a25237STobias Grosser struct isl_tarjan_graph *g;
3152a25237STobias Grosser int i;
3252a25237STobias Grosser
3352a25237STobias Grosser g = isl_calloc_type(ctx, struct isl_tarjan_graph);
3452a25237STobias Grosser if (!g)
3552a25237STobias Grosser return NULL;
3652a25237STobias Grosser g->len = len;
3752a25237STobias Grosser g->node = isl_alloc_array(ctx, struct isl_tarjan_node, len);
3852a25237STobias Grosser if (len && !g->node)
3952a25237STobias Grosser goto error;
4052a25237STobias Grosser for (i = 0; i < len; ++i)
4152a25237STobias Grosser g->node[i].index = -1;
4252a25237STobias Grosser g->stack = isl_alloc_array(ctx, int, len);
4352a25237STobias Grosser if (len && !g->stack)
4452a25237STobias Grosser goto error;
4552a25237STobias Grosser g->order = isl_alloc_array(ctx, int, 2 * len);
4652a25237STobias Grosser if (len && !g->order)
4752a25237STobias Grosser goto error;
4852a25237STobias Grosser
4952a25237STobias Grosser g->sp = 0;
5052a25237STobias Grosser g->index = 0;
5152a25237STobias Grosser g->op = 0;
5252a25237STobias Grosser
5352a25237STobias Grosser return g;
5452a25237STobias Grosser error:
5552a25237STobias Grosser isl_tarjan_graph_free(g);
5652a25237STobias Grosser return NULL;
5752a25237STobias Grosser }
5852a25237STobias Grosser
5952a25237STobias Grosser /* Perform Tarjan's algorithm for computing the strongly connected components
6052a25237STobias Grosser * in the graph with g->len nodes and with edges defined by "follows".
6152a25237STobias Grosser */
isl_tarjan_components(struct isl_tarjan_graph * g,int i,isl_bool (* follows)(int i,int j,void * user),void * user)62b2f39926STobias Grosser static isl_stat isl_tarjan_components(struct isl_tarjan_graph *g, int i,
63b2f39926STobias Grosser isl_bool (*follows)(int i, int j, void *user), void *user)
6452a25237STobias Grosser {
6552a25237STobias Grosser int j;
6652a25237STobias Grosser
6752a25237STobias Grosser g->node[i].index = g->index;
6852a25237STobias Grosser g->node[i].min_index = g->index;
6952a25237STobias Grosser g->node[i].on_stack = 1;
7052a25237STobias Grosser g->index++;
7152a25237STobias Grosser g->stack[g->sp++] = i;
7252a25237STobias Grosser
7352a25237STobias Grosser for (j = g->len - 1; j >= 0; --j) {
74b2f39926STobias Grosser isl_bool f;
7552a25237STobias Grosser
7652a25237STobias Grosser if (j == i)
7752a25237STobias Grosser continue;
7852a25237STobias Grosser if (g->node[j].index >= 0 &&
7952a25237STobias Grosser (!g->node[j].on_stack ||
8052a25237STobias Grosser g->node[j].index > g->node[i].min_index))
8152a25237STobias Grosser continue;
8252a25237STobias Grosser
8352a25237STobias Grosser f = follows(i, j, user);
8452a25237STobias Grosser if (f < 0)
85b2f39926STobias Grosser return isl_stat_error;
8652a25237STobias Grosser if (!f)
8752a25237STobias Grosser continue;
8852a25237STobias Grosser
8952a25237STobias Grosser if (g->node[j].index < 0) {
9052a25237STobias Grosser isl_tarjan_components(g, j, follows, user);
9152a25237STobias Grosser if (g->node[j].min_index < g->node[i].min_index)
9252a25237STobias Grosser g->node[i].min_index = g->node[j].min_index;
9352a25237STobias Grosser } else if (g->node[j].index < g->node[i].min_index)
9452a25237STobias Grosser g->node[i].min_index = g->node[j].index;
9552a25237STobias Grosser }
9652a25237STobias Grosser
9752a25237STobias Grosser if (g->node[i].index != g->node[i].min_index)
98b2f39926STobias Grosser return isl_stat_ok;
9952a25237STobias Grosser
10052a25237STobias Grosser do {
10152a25237STobias Grosser j = g->stack[--g->sp];
10252a25237STobias Grosser g->node[j].on_stack = 0;
10352a25237STobias Grosser g->order[g->op++] = j;
10452a25237STobias Grosser } while (j != i);
10552a25237STobias Grosser g->order[g->op++] = -1;
10652a25237STobias Grosser
107b2f39926STobias Grosser return isl_stat_ok;
10852a25237STobias Grosser }
10952a25237STobias Grosser
11052a25237STobias Grosser /* Decompose the graph with "len" nodes and edges defined by "follows"
11152a25237STobias Grosser * into strongly connected components (SCCs).
11252a25237STobias Grosser * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise.
11352a25237STobias Grosser * It should return -1 on error.
11452a25237STobias Grosser *
11552a25237STobias Grosser * If SCC a contains a node i that follows a node j in another SCC b
11652a25237STobias Grosser * (i.e., follows(i, j, user) returns 1), then SCC a will appear after SCC b
11752a25237STobias Grosser * in the result.
11852a25237STobias Grosser */
isl_tarjan_graph_init(isl_ctx * ctx,int len,isl_bool (* follows)(int i,int j,void * user),void * user)11952a25237STobias Grosser struct isl_tarjan_graph *isl_tarjan_graph_init(isl_ctx *ctx, int len,
120b2f39926STobias Grosser isl_bool (*follows)(int i, int j, void *user), void *user)
12152a25237STobias Grosser {
12252a25237STobias Grosser int i;
12352a25237STobias Grosser struct isl_tarjan_graph *g = NULL;
12452a25237STobias Grosser
12552a25237STobias Grosser g = isl_tarjan_graph_alloc(ctx, len);
12652a25237STobias Grosser if (!g)
12752a25237STobias Grosser return NULL;
12852a25237STobias Grosser for (i = len - 1; i >= 0; --i) {
12952a25237STobias Grosser if (g->node[i].index >= 0)
13052a25237STobias Grosser continue;
13152a25237STobias Grosser if (isl_tarjan_components(g, i, follows, user) < 0)
132*a7f1e040STobias Grosser return isl_tarjan_graph_free(g);
13352a25237STobias Grosser }
13452a25237STobias Grosser
13552a25237STobias Grosser return g;
136*a7f1e040STobias Grosser }
137*a7f1e040STobias Grosser
138*a7f1e040STobias Grosser /* Decompose the graph with "len" nodes and edges defined by "follows"
139*a7f1e040STobias Grosser * into the strongly connected component (SCC) that contains "node"
140*a7f1e040STobias Grosser * as well as all SCCs that are followed by this SCC.
141*a7f1e040STobias Grosser * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise.
142*a7f1e040STobias Grosser * It should return -1 on error.
143*a7f1e040STobias Grosser *
144*a7f1e040STobias Grosser * The SCC containing "node" will appear as the last component
145*a7f1e040STobias Grosser * in g->order.
146*a7f1e040STobias Grosser */
isl_tarjan_graph_component(isl_ctx * ctx,int len,int node,isl_bool (* follows)(int i,int j,void * user),void * user)147*a7f1e040STobias Grosser struct isl_tarjan_graph *isl_tarjan_graph_component(isl_ctx *ctx, int len,
148*a7f1e040STobias Grosser int node, isl_bool (*follows)(int i, int j, void *user), void *user)
149*a7f1e040STobias Grosser {
150*a7f1e040STobias Grosser struct isl_tarjan_graph *g;
151*a7f1e040STobias Grosser
152*a7f1e040STobias Grosser g = isl_tarjan_graph_alloc(ctx, len);
153*a7f1e040STobias Grosser if (!g)
15452a25237STobias Grosser return NULL;
155*a7f1e040STobias Grosser if (isl_tarjan_components(g, node, follows, user) < 0)
156*a7f1e040STobias Grosser return isl_tarjan_graph_free(g);
157*a7f1e040STobias Grosser
158*a7f1e040STobias Grosser return g;
15952a25237STobias Grosser }
160