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