/*! \file lib/vector/neta/bridge.c \brief Network Analysis library - bridges Computes number of bridges in the graph. (C) 2009-2010 by Daniel Bundala, and the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. \author Daniel Bundala (Google Summer of Code 2009) */ #include #include #include #include #include #include /*! \brief Get number of bridges in the graph. Bridge is an array containing the indices of the bridges. \param graph input graph \param[out] bridge_list list of bridges \return number of bridges, -1 on error */ int NetA_compute_bridges(dglGraph_s * graph, struct ilist *bridge_list) { int nnodes; int bridges = 0; dglEdgesetTraverser_s *current; /*edge to be processed when the node is visited */ int *tin, *min_tin; /*time in, and smallest tin over all successors. 0 if not yet visited */ dglInt32_t *parent; /*edge from parent to the node */ dglInt32_t **stack; /*stack of nodes */ dglInt32_t **current_edge; /*current edge for each node */ dglNodeTraverser_s nt; dglInt32_t *current_node; int stack_size; int i, time; nnodes = dglGet_NodeCount(graph); current = (dglEdgesetTraverser_s *) G_calloc(nnodes + 1, sizeof(dglEdgesetTraverser_s)); tin = (int *)G_calloc(nnodes + 1, sizeof(int)); min_tin = (int *)G_calloc(nnodes + 1, sizeof(int)); parent = (dglInt32_t *) G_calloc(nnodes + 1, sizeof(dglInt32_t)); stack = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *)); current_edge = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *)); if (!tin || !min_tin || !parent || !stack || !current) { G_fatal_error(_("Out of memory")); return -1; } for (i = 1; i <= nnodes; i++) { dglEdgeset_T_Initialize(¤t[i], graph, dglNodeGet_OutEdgeset(graph, dglGetNode(graph, i))); current_edge[i] = dglEdgeset_T_First(¤t[i]); tin[i] = 0; } dglNode_T_Initialize(&nt, graph); time = 0; for (current_node = dglNode_T_First(&nt); current_node; current_node = dglNode_T_Next(&nt)) { dglInt32_t current_id = dglNodeGet_Id(graph, current_node); if (tin[current_id] == 0) { stack[0] = current_node; stack_size = 1; parent[current_id] = 0; while (stack_size) { dglInt32_t *node = stack[stack_size - 1]; dglInt32_t node_id = dglNodeGet_Id(graph, node); if (tin[node_id] == 0) /*vertex visited for the first time */ min_tin[node_id] = tin[node_id] = ++time; else { /*return from the recursion */ dglInt32_t to = dglNodeGet_Id(graph, dglEdgeGet_Tail(graph, current_edge [node_id])); if (min_tin[to] > tin[node_id]) { /*no path from the subtree above the current node */ Vect_list_append(bridge_list, dglEdgeGet_Id(graph, current_edge[node_id])); /*so it must be a bridge */ bridges++; } if (min_tin[to] < min_tin[node_id]) min_tin[node_id] = min_tin[to]; current_edge[node_id] = dglEdgeset_T_Next(¤t[node_id]); /*proceed to the next edge */ } for (; current_edge[node_id]; current_edge[node_id] = dglEdgeset_T_Next(¤t[node_id])) { /*try next edges */ dglInt32_t *to = dglEdgeGet_Tail(graph, current_edge[node_id]); dglInt32_t edge_id = dglEdgeGet_Id(graph, current_edge[node_id]); if (labs(edge_id) == parent[node_id]) continue; /*skip edge we used to travel to this node */ int to_id = dglNodeGet_Id(graph, to); if (tin[to_id]) { /*back edge, cannot be a bridge/articualtion point */ if (tin[to_id] < min_tin[node_id]) min_tin[node_id] = tin[to_id]; } else { /*forward edge */ parent[to_id] = labs(edge_id); stack[stack_size++] = to; break; } } if (!current_edge[node_id]) stack_size--; /*current node completely processed */ } } } dglNode_T_Release(&nt); for (i = 1; i <= nnodes; i++) dglEdgeset_T_Release(¤t[i]); G_free(current); G_free(tin); G_free(min_tin); G_free(parent); G_free(stack); G_free(current_edge); return bridges; }