/*! \brief Get number of articulation points in the graph \param graph input graph \param[out] articulation_list list of articulation points \return number of points \return -1 on error */ int NetA_articulation_points(dglGraph_s * graph, struct ilist *articulation_list) { int nnodes; int points = 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; /*parents of the nodes */ dglInt32_t **stack; /*stack of nodes */ dglInt32_t **current_edge; /*current edge for each node */ int *mark; /*marked articulation points */ 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 *)); mark = (int *)G_calloc(nnodes + 1, sizeof(int)); if (!tin || !min_tin || !parent || !stack || !current || !mark) { 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] = mark[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) { int children = 0; /*number of subtrees rooted at the root/current_node */ stack[0] = current_node; stack_size = 1; parent[current_id] = NULL; 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 */ mark[node_id] = 1; /*so the current node must be an articulation point */ 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 */ } /*try next edges */ for (; current_edge[node_id]; current_edge[node_id] = dglEdgeset_T_Next(¤t[node_id])) { dglInt32_t *to = dglEdgeGet_Tail(graph, current_edge[node_id]); if (to == parent[node_id]) continue; /*skip parent */ 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 */ if (node_id == current_id) children++; /*if root, increase number of children */ parent[to_id] = node; stack[stack_size++] = to; break; } } if (!current_edge[node_id]) stack_size--; /*current node completely processed */ } if (children > 1) mark[current_id] = 1; /*if the root has more than 1 subtrees rooted at it, then it is an * articulation point */ } } for (i = 1; i <= nnodes; i++) if (mark[i]) { points++; Vect_list_append(articulation_list, i); } 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 points; }
static int _print_node(dglGraph_s * pgraph, dglInt32_t * pnode, void *pvarg) { FILE *f = (FILE *) pvarg; dglInt32_t *pedgeset; dglInt32_t *pedge; dglInt32_t *ptonode; dglInt32_t *pnattr; int iAttr, cAttr; int role; int i; dglEdgesetTraverser_s edgeaT; role = 0; if (dglNodeGet_Status(pgraph, pnode) & DGL_NS_HEAD) { role |= 1; } if (dglNodeGet_Status(pgraph, pnode) & DGL_NS_TAIL) { role |= 2; } fprintf(f, "HEAD %-8ld - %-s", dglNodeGet_Id(pgraph, pnode), (role > 2) ? "'H/T'" : (role == 2) ? "'T '" : (role == 1) ? "'H '" : "'A '"); if ((cAttr = dglGet_NodeAttrSize(pgraph)) > 0) { pnattr = dglNodeGet_Attr(pgraph, pnode); fprintf(f, " - HEAD ATTR ["); for (iAttr = 0; iAttr < cAttr; iAttr++) { if (iAttr && !(iAttr % 4)) fprintf(f, " "); fprintf(f, "%02x", ((unsigned char *)pnattr)[iAttr]); } fprintf(f, "]\n"); } else { fprintf(f, "\n"); } if (role & 1) { pedgeset = dglNodeGet_OutEdgeset(pgraph, pnode); dglEdgeset_T_Initialize(&edgeaT, pgraph, pedgeset); for (i = 0, pedge = dglEdgeset_T_First(&edgeaT); pedge; i++, pedge = dglEdgeset_T_Next(&edgeaT) ) { ptonode = dglEdgeGet_Tail(pgraph, pedge); if (ptonode) { role = 0; if (dglNodeGet_Status(pgraph, ptonode) & DGL_NS_HEAD) { role |= 1; } if (dglNodeGet_Status(pgraph, ptonode) & DGL_NS_TAIL) { role |= 2; } fprintf(f, "EDGE #%-8d: TAIL %-8ld - %-s - COST %-8ld - ID %-8ld", i, dglNodeGet_Id(pgraph, ptonode), (role > 2) ? "'H/T'" : (role == 2) ? "'T '" : (role == 1) ? "'H '" : "'A '", dglEdgeGet_Cost(pgraph, pedge), dglEdgeGet_Id(pgraph, pedge) ); if ((cAttr = dglGet_NodeAttrSize(pgraph)) > 0) { pnattr = dglNodeGet_Attr(pgraph, ptonode); fprintf(f, " - TAIL ATTR ["); for (iAttr = 0; iAttr < cAttr; iAttr++) { if (iAttr && !(iAttr % 4)) fprintf(f, " "); fprintf(f, "%02x", ((unsigned char *)pnattr)[iAttr]); } fprintf(f, "]"); } if ((cAttr = dglGet_EdgeAttrSize(pgraph)) > 0) { pnattr = dglEdgeGet_Attr(pgraph, pedge); fprintf(f, " - EDGE ATTR ["); for (iAttr = 0; iAttr < cAttr; iAttr++) { if (iAttr && !(iAttr % 4)) fprintf(f, " "); fprintf(f, "%02x", ((unsigned char *)pnattr)[iAttr]); } fprintf(f, "]\n"); } else { fprintf(f, "\n"); } } } dglEdgeset_T_Release(&edgeaT); } return 0; }
/*! \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 (abs(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] = abs(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; }
/*! \brief Computes shortests paths to every node from nodes in "from". Array "dst" contains the length of the path or -1 if the node is not reachable. Prev contains edges from predecessor along the shortest path. \param graph input graph \param from list of 'from' positions \param dst list of 'to' positions \param[out] prev list of edges from predecessor along the shortest path \return 0 on success \return -1 on failure */ int NetA_distance_from_points(dglGraph_s *graph, struct ilist *from, int *dst, dglInt32_t **prev) { int i, nnodes; dglHeap_s heap; nnodes = dglGet_NodeCount(graph); dglEdgesetTraverser_s et; /* initialize costs and edge list */ for (i = 1; i <= nnodes; i++) { dst[i] = -1; prev[i] = NULL; } dglHeapInit(&heap); for (i = 0; i < from->n_values; i++) { int v = from->value[i]; if (dst[v] == 0) continue; /*ingore duplicates */ dst[v] = 0; /* make sure all from nodes are processed first */ dglHeapData_u heap_data; heap_data.ul = v; dglHeapInsertMin(&heap, 0, ' ', heap_data); } while (1) { dglInt32_t v, dist; dglHeapNode_s heap_node; dglHeapData_u heap_data; if (!dglHeapExtractMin(&heap, &heap_node)) break; v = heap_node.value.ul; dist = heap_node.key; if (dst[v] < dist) continue; dglInt32_t *edge; dglEdgeset_T_Initialize(&et, graph, dglNodeGet_OutEdgeset(graph, dglGetNode(graph, v))); for (edge = dglEdgeset_T_First(&et); edge; edge = dglEdgeset_T_Next(&et)) { dglInt32_t *to = dglEdgeGet_Tail(graph, edge); dglInt32_t to_id = dglNodeGet_Id(graph, to); dglInt32_t d = dglEdgeGet_Cost(graph, edge); if (dst[to_id] < 0 || dst[to_id] > dist + d) { dst[to_id] = dist + d; prev[to_id] = edge; heap_data.ul = to_id; dglHeapInsertMin(&heap, dist + d, ' ', heap_data); } } dglEdgeset_T_Release(&et); } dglHeapFree(&heap, NULL); return 0; }
/*! \brief Find a path (minimum number of edges) from 'from' to 'to' using only edges in 'edges'. Precisely, edge with id I is used if edges[abs(i)] == 1. List stores the indices of lines on the path. Method return number of edges or -1 if no path exist. \param graph input graph \param from 'from' position \param to 'to' position \param edges list of available edges \param[out] list list of edges \return number of edges \return -1 on failure */ int NetA_find_path(dglGraph_s * graph, int from, int to, int *edges, struct ilist *list) { dglInt32_t **prev, *queue; dglEdgesetTraverser_s et; char *vis; int begin, end, cur, nnodes; nnodes = dglGet_NodeCount(graph); prev = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *)); queue = (dglInt32_t *) G_calloc(nnodes + 1, sizeof(dglInt32_t)); vis = (char *)G_calloc(nnodes + 1, sizeof(char)); if (!prev || !queue || !vis) { G_fatal_error(_("Out of memory")); return -1; } Vect_reset_list(list); begin = 0; end = 1; vis[from] = 'y'; queue[0] = from; prev[from] = NULL; while (begin != end) { dglInt32_t vertex = queue[begin++]; if (vertex == to) break; dglInt32_t *edge, *node = dglGetNode(graph, vertex); dglEdgeset_T_Initialize(&et, graph, dglNodeGet_OutEdgeset(graph, node)); for (edge = dglEdgeset_T_First(&et); edge; edge = dglEdgeset_T_Next(&et)) { dglInt32_t id = abs(dglEdgeGet_Id(graph, edge)); dglInt32_t to = dglNodeGet_Id(graph, dglEdgeGet_Tail(graph, edge)); if (edges[id] && !vis[to]) { vis[to] = 'y'; prev[to] = edge; queue[end++] = to; } } dglEdgeset_T_Release(&et); } G_free(queue); if (!vis[to]) { G_free(prev); G_free(vis); return -1; } cur = to; while (prev[cur] != NULL) { Vect_list_append(list, abs(dglEdgeGet_Id(graph, prev[cur]))); cur = dglNodeGet_Id(graph, dglEdgeGet_Head(graph, prev[cur])); } G_free(prev); G_free(vis); return list->n_values; }
/*! \brief Computes weakly connected components \param graph input graph \param[out] component array of component ids \return number of components \return -1 on failure */ int NetA_weakly_connected_components(dglGraph_s * graph, int *component) { int nnodes, i; dglInt32_t *stack; int stack_size, components; dglInt32_t *cur_node; dglNodeTraverser_s nt; int have_node_costs; dglInt32_t ncost; if (graph->Version < 2) { G_warning("Directed graph must be version 2 or 3 for NetA_weakly_connected_components()"); return -1; } components = 0; nnodes = dglGet_NodeCount(graph); stack = (dglInt32_t *) G_calloc(nnodes + 1, sizeof(dglInt32_t)); if (!stack) { G_fatal_error(_("Out of memory")); return -1; } for (i = 1; i <= nnodes; i++) component[i] = 0; ncost = 0; have_node_costs = dglGet_NodeAttrSize(graph); dglNode_T_Initialize(&nt, graph); for (cur_node = dglNode_T_First(&nt); cur_node; cur_node = dglNode_T_Next(&nt)) { dglInt32_t cur_node_id = dglNodeGet_Id(graph, cur_node); if (!component[cur_node_id]) { stack[0] = cur_node_id; stack_size = 1; component[cur_node_id] = ++components; while (stack_size) { dglInt32_t *node, *edgeset, *edge; dglEdgesetTraverser_s et; node = dglGetNode(graph, stack[--stack_size]); edgeset = dglNodeGet_OutEdgeset(graph, node); dglEdgeset_T_Initialize(&et, graph, edgeset); for (edge = dglEdgeset_T_First(&et); edge; edge = dglEdgeset_T_Next(&et)) { dglInt32_t to; to = dglNodeGet_Id(graph, dglEdgeGet_Tail(graph, edge)); if (!component[to]) { component[to] = components; /* do not go through closed nodes */ if (have_node_costs) { memcpy(&ncost, dglNodeGet_Attr(graph, dglEdgeGet_Tail(graph, edge)), sizeof(ncost)); } if (ncost >= 0) stack[stack_size++] = to; } } dglEdgeset_T_Release(&et); edgeset = dglNodeGet_InEdgeset(graph, node); dglEdgeset_T_Initialize(&et, graph, edgeset); for (edge = dglEdgeset_T_First(&et); edge; edge = dglEdgeset_T_Next(&et)) { dglInt32_t to; to = dglNodeGet_Id(graph, dglEdgeGet_Head(graph, edge)); if (!component[to]) { component[to] = components; /* do not go through closed nodes */ if (have_node_costs) { memcpy(&ncost, dglNodeGet_Attr(graph, dglEdgeGet_Tail(graph, edge)), sizeof(ncost)); } if (ncost >= 0) stack[stack_size++] = to; } } dglEdgeset_T_Release(&et); } } } dglNode_T_Release(&nt); G_free(stack); return components; }
/*! \brief Computes strongly connected components with Kosaraju's two-pass algorithm \param graph input graph \param[out] component array of component ids \return number of components \return -1 on failure */ int NetA_strongly_connected_components(dglGraph_s * graph, int *component) { int nnodes, i; dglInt32_t *stack, *order; int *processed; int stack_size, order_size, components; dglInt32_t *cur_node; dglNodeTraverser_s nt; int have_node_costs; dglInt32_t ncost; if (graph->Version < 2) { G_warning("Directed graph must be version 2 or 3 for NetA_strongly_connected_components()"); return -1; } components = 0; nnodes = dglGet_NodeCount(graph); stack = (dglInt32_t *) G_calloc(nnodes + 1, sizeof(dglInt32_t)); order = (dglInt32_t *) G_calloc(nnodes + 1, sizeof(dglInt32_t)); processed = (int *)G_calloc(nnodes + 1, sizeof(int)); if (!stack || !order || !processed) { G_fatal_error(_("Out of memory")); return -1; } for (i = 1; i <= nnodes; i++) { component[i] = 0; } ncost = 0; have_node_costs = dglGet_NodeAttrSize(graph); order_size = 0; dglNode_T_Initialize(&nt, graph); for (cur_node = dglNode_T_First(&nt); cur_node; cur_node = dglNode_T_Next(&nt)) { dglInt32_t cur_node_id = dglNodeGet_Id(graph, cur_node); if (!component[cur_node_id]) { component[cur_node_id] = --components; stack[0] = cur_node_id; stack_size = 1; while (stack_size) { dglInt32_t *node, *edgeset, *edge; dglEdgesetTraverser_s et; dglInt32_t node_id = stack[stack_size - 1]; if (processed[node_id]) { stack_size--; order[order_size++] = node_id; continue; } processed[node_id] = 1; node = dglGetNode(graph, node_id); edgeset = dglNodeGet_OutEdgeset(graph, node); dglEdgeset_T_Initialize(&et, graph, edgeset); for (edge = dglEdgeset_T_First(&et); edge; edge = dglEdgeset_T_Next(&et)) { dglInt32_t to; to = dglNodeGet_Id(graph, dglEdgeGet_Tail(graph, edge)); if (!component[to]) { component[to] = components; /* do not go through closed nodes */ if (have_node_costs) { memcpy(&ncost, dglNodeGet_Attr(graph, dglEdgeGet_Tail(graph, edge)), sizeof(ncost)); } if (ncost < 0) processed[to] = 1; stack[stack_size++] = to; } } dglEdgeset_T_Release(&et); } } } dglNode_T_Release(&nt); components = 0; dglNode_T_Initialize(&nt, graph); while (order_size) { dglInt32_t cur_node_id = order[--order_size]; int cur_comp = component[cur_node_id]; if (cur_comp < 1) { component[cur_node_id] = ++components; stack[0] = cur_node_id; stack_size = 1; while (stack_size) { dglInt32_t *node, *edgeset, *edge; dglEdgesetTraverser_s et; dglInt32_t node_id = stack[--stack_size]; node = dglGetNode(graph, node_id); edgeset = dglNodeGet_InEdgeset(graph, node); dglEdgeset_T_Initialize(&et, graph, edgeset); for (edge = dglEdgeset_T_First(&et); edge; edge = dglEdgeset_T_Next(&et)) { dglInt32_t to; to = dglNodeGet_Id(graph, dglEdgeGet_Head(graph, edge)); if (component[to] == cur_comp) { component[to] = components; /* do not go through closed nodes */ if (have_node_costs) { memcpy(&ncost, dglNodeGet_Attr(graph, dglEdgeGet_Head(graph, edge)), sizeof(ncost)); } if (ncost >= 0) stack[stack_size++] = to; } } dglEdgeset_T_Release(&et); } } } dglNode_T_Release(&nt); G_free(stack); G_free(order); G_free(processed); return components; }