[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