[GRASS-SVN] r68006 - grass/trunk/lib/vector/neta
svn_grass at osgeo.org
svn_grass at osgeo.org
Sat Mar 5 14:27:31 PST 2016
Author: mmetz
Date: 2016-03-05 14:27:31 -0800 (Sat, 05 Mar 2016)
New Revision: 68006
Modified:
grass/trunk/lib/vector/neta/components.c
Log:
netalib: fix network components
Modified: grass/trunk/lib/vector/neta/components.c
===================================================================
--- grass/trunk/lib/vector/neta/components.c 2016-03-05 22:25:33 UTC (rev 68005)
+++ grass/trunk/lib/vector/neta/components.c 2016-03-05 22:27:31 UTC (rev 68006)
@@ -11,8 +11,28 @@
(>=v2). Read the file COPYING that comes with GRASS for details.
\author Daniel Bundala (Google Summer of Code 2009)
+ \author Markus Metz
*/
+/* example:
+ *
+ * X -->-- X ---- X --<-- X ---- X
+ * N1 N2 N3 N4 N5
+ *
+ * -->--, --<-- one-way
+ * ---- both ways
+ *
+ * weakly connected:
+ * all 5 nodes, even though there is no direct path from N1 to N4, 5
+ * but N1 connects to N2, 3, and N4, 5 also connect to N2, 3
+ *
+ * strongly connected:
+ * no path from N2 to N1, no path from N3 to N4
+ * component 1: N1
+ * component 2: N2, 3
+ * Component3: N4, 5
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <grass/gis.h>
@@ -21,43 +41,53 @@
#include <grass/dgl/graph.h>
/*!
- \brief Computes weekly connected components
+ \brief Computes weakly connected components
\param graph input graph
- \param[out] component list of components
+ \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;
+ int nnodes, i;
dglInt32_t *stack;
- int *visited;
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));
- visited = (int *)G_calloc(nnodes + 1, sizeof(int));
- if (!stack || !visited) {
+ 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 node_id = dglNodeGet_Id(graph, cur_node);
+ dglInt32_t cur_node_id = dglNodeGet_Id(graph, cur_node);
- if (!visited[node_id]) {
- visited[node_id] = 1;
- stack[0] = node_id;
+ if (!component[cur_node_id]) {
+ stack[0] = cur_node_id;
stack_size = 1;
- component[node_id] = ++components;
+ component[cur_node_id] = ++components;
while (stack_size) {
dglInt32_t *node, *edgeset, *edge;
dglEdgesetTraverser_s et;
@@ -70,84 +100,131 @@
dglInt32_t to;
to = dglNodeGet_Id(graph, dglEdgeGet_Tail(graph, edge));
- if (!visited[to]) {
- visited[to] = 1;
+ if (!component[to]) {
component[to] = components;
- stack[stack_size++] = to;
+ /* 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(visited);
+
+ G_free(stack);
return components;
}
/*!
- \brief Computes strongly connected components
+ \brief Computes strongly connected components with Kosaraju's
+ two-pass algorithm
\param graph input graph
- \param[out] component list of components
+ \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;
+ int nnodes, i;
dglInt32_t *stack, *order;
- int *visited, *processed;
+ int *processed;
int stack_size, order_size, components;
- dglInt32_t *node;
+ 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));
- visited = (int *)G_calloc(nnodes + 1, sizeof(int));
processed = (int *)G_calloc(nnodes + 1, sizeof(int));
- if (!stack || !visited || !order || !processed) {
+ 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 (node = dglNode_T_First(&nt); node; node = dglNode_T_Next(&nt)) {
- dglInt32_t node_id = dglNodeGet_Id(graph, node);
+ 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);
- component[node_id] = 0;
- if (!visited[node_id]) {
- visited[node_id] = 1;
- stack[0] = node_id;
+ 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 cur_node_id = stack[stack_size - 1];
+ dglInt32_t node_id = stack[stack_size - 1];
- if (processed[cur_node_id]) {
+ if (processed[node_id]) {
stack_size--;
- order[order_size++] = cur_node_id;
+ order[order_size++] = node_id;
continue;
}
- processed[cur_node_id] = 1;
- node = dglGetNode(graph, cur_node_id);
+ 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;
- if (dglEdgeGet_Id(graph, edge) < 0)
- continue; /*ignore backward edges */
to = dglNodeGet_Id(graph, dglEdgeGet_Tail(graph, edge));
- if (!visited[to]) {
- visited[to] = 1;
+ 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;
}
}
@@ -158,42 +235,47 @@
dglNode_T_Release(&nt);
+ components = 0;
+ dglNode_T_Initialize(&nt, graph);
+
while (order_size) {
- dglInt32_t node_id = order[--order_size];
+ dglInt32_t cur_node_id = order[--order_size];
+ int cur_comp = component[cur_node_id];
- if (component[node_id])
- continue;
- components++;
- component[node_id] = components;
- stack[0] = node_id;
- stack_size = 1;
- while (stack_size) {
- dglInt32_t *node, *edgeset, *edge;
- dglEdgesetTraverser_s et;
- dglInt32_t cur_node_id = stack[--stack_size];
+ 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, cur_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;
+ 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;
- if (dglEdgeGet_Id(graph, edge) > 0)
- continue; /*ignore forward edges */
- to = dglNodeGet_Id(graph, dglEdgeGet_Tail(graph, edge));
- if (!component[to]) {
- component[to] = components;
- stack[stack_size++] = 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);
}
- dglEdgeset_T_Release(&et);
}
}
+ dglNode_T_Release(&nt);
G_free(stack);
- G_free(visited);
- G_free(order);
- G_free(processed);
return components;
}
More information about the grass-commit
mailing list