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