[GRASS-SVN] r43857 - grass/trunk/lib/vector/dglib

svn_grass at osgeo.org svn_grass at osgeo.org
Mon Oct 11 09:19:03 EDT 2010


Author: mmetz
Date: 2010-10-11 06:19:02 -0700 (Mon, 11 Oct 2010)
New Revision: 43857

Modified:
   grass/trunk/lib/vector/dglib/sp-template.c
Log:
new fix for dglib cache BUG1

Modified: grass/trunk/lib/vector/dglib/sp-template.c
===================================================================
--- grass/trunk/lib/vector/dglib/sp-template.c	2010-10-11 13:10:59 UTC (rev 43856)
+++ grass/trunk/lib/vector/dglib/sp-template.c	2010-10-11 13:19:02 UTC (rev 43857)
@@ -23,6 +23,16 @@
 
 /*
  * SHORTEST PATH CACHE
+ * 
+ * components:
+ *   - visited network: a node is marked as visited when its departing
+ *     edges have been added to the cache
+ *   - predist network: node distances from start node
+ *   - NodeHeap: holds unvisited nodes, the next node extracted is the
+ *     one closest to SP start
+ *
+ * not all nodes in the cache have been visited, but distances from
+ * SP start are known for all nodes in the cache
  */
 #if !defined(DGL_DEFINE_TREE_PROCS) && !defined(DGL_DEFINE_FLAT_PROCS)
 
@@ -60,7 +70,6 @@
 				      dglInt32_t nStart,
 				      dglInt32_t nDestination)
 {
-    dglTreeTouchI32_s *pVisitedItem, VisitedItem;
     dglTreePredist_s *pPredistItem, PredistItem;
 
     if (pCache->nStartNode != nStart) {
@@ -68,15 +77,9 @@
 	return -pgraph->iErrno;
     }
 
-    VisitedItem.nKey = nDestination;
-    if ((pVisitedItem = avl_find(pCache->pvPredist, &VisitedItem)) == NULL) {
-	pgraph->iErrno = DGL_ERR_TailNodeNotFound;
-	return -pgraph->iErrno;
-    }
-
     PredistItem.nKey = nDestination;
     if ((pPredistItem = avl_find(pCache->pvPredist, &PredistItem)) == NULL) {
-	pgraph->iErrno = DGL_ERR_UnexpectedNullPointer;
+	pgraph->iErrno = DGL_ERR_TailNodeNotFound;
 	return -pgraph->iErrno;
     }
 
@@ -90,7 +93,6 @@
 					       dglInt32_t nStart,
 					       dglInt32_t nDestination)
 {
-    dglTreeTouchI32_s VisitedItem;
     dglTreePredist_s *pPredistItem, PredistItem;
     dglInt32_t *pEdge;
     dglInt32_t *pDestination;
@@ -105,9 +107,9 @@
 	return NULL;
     }
 
-    VisitedItem.nKey = nDestination;
+    PredistItem.nKey = nDestination;
 
-    if (avl_find(pCache->pvVisited, &VisitedItem) == NULL) {
+    if (avl_find(pCache->pvPredist, &PredistItem) == NULL) {
 	pgraph->iErrno = DGL_ERR_TailNodeNotFound;
 	return NULL;
     }
@@ -312,6 +314,7 @@
     dglEdgesetTraverser_s laT;
 
     dglSPCache_s spCache;
+    int new_cache = 0;
 
     /*
      * shortest path distance temporary min heap
@@ -346,6 +349,7 @@
     if (pCache == NULL) {
 	pCache = &spCache;
 	DGL_SP_CACHE_INITIALIZE_FUNC(pgraph, pCache, nStart);
+	new_cache = 1;
     }
     else {
 	if (ppReport) {
@@ -364,21 +368,11 @@
 	if (pgraph->iErrno == DGL_ERR_HeadNodeNotFound) {
 	    DGL_SP_CACHE_RELEASE_FUNC(pgraph, pCache);
 	    DGL_SP_CACHE_INITIALIZE_FUNC(pgraph, pCache, nStart);
+	    new_cache = 1;
 	}
 	else if (pgraph->iErrno != DGL_ERR_TailNodeNotFound) {
 	    goto sp_error;
 	}
-	/*
-	 * reset visited status for existing cache: fix for BUG1
-	 */
-	if (pCache->pvVisited) {
-	    avl_destroy(pCache->pvVisited, dglTreeTouchI32Cancel);
-
-	    if ((pCache->pvVisited =
-		avl_create(dglTreeTouchI32Compare, NULL,
-			dglTreeGetAllocator())) == NULL)
-		return -1;
-	}
     }
 
     /*
@@ -409,44 +403,47 @@
 	goto sp_error;
     }
 
-    /*
-     * now we inspect all edges departing from the start node
-     * - at each loop 'pedge' points to the edge in the edge buffer
-     * - we invoke the caller's clip() and eventually skip the edge (clip() != 0)
-     * - we insert a item in the predist network to set actual predecessor and distance
-     *   (there is no precedecessor at this stage) and actual distance from the starting node
-     *   (at this stage it equals the edge's cost)
-     * - we insert a item in the node min-heap (sorted on node distance), storing the offset of the
-     *   edge in the edge buffer.
-     * In the case of undirected graph (version 3) we inspect input edges as well.
-     */
-    pEdgeset = _DGL_OUTEDGESET(pgraph, pStart);
-    if (DGL_EDGESET_T_INITIALIZE_FUNC(pgraph, &laT, pEdgeset) < 0) {
-	goto sp_error;
-    }
-    for (pEdge = DGL_EDGESET_T_FIRST_FUNC(&laT);
-	 pEdge; pEdge = DGL_EDGESET_T_NEXT_FUNC(&laT)
-	) {
-	__EDGELOOP_BODY_1(0);
-    }
-    DGL_EDGESET_T_RELEASE_FUNC(&laT);
-
-    if (pgraph->Version == 3) {
-	pEdgeset = _DGL_INEDGESET(pgraph, pStart);
+    /* if we do not need a new cache, we just continue with the unvisited
+     * nodes in the cache */
+    if (new_cache) {
+	/*
+	 * now we inspect all edges departing from the start node
+	 * - at each loop 'pedge' points to the edge in the edge buffer
+	 * - we invoke the caller's clip() and eventually skip the edge (clip() != 0)
+	 * - we insert a item in the predist network to set actual predecessor and distance
+	 *   (there is no precedecessor at this stage) and actual distance from the starting node
+	 *   (at this stage it equals the edge's cost)
+	 * - we insert a item in the node min-heap (sorted on node distance), storing the offset of the
+	 *   edge in the edge buffer.
+	 * In the case of undirected graph (version 3) we inspect input edges as well.
+	 */
+	pEdgeset = _DGL_OUTEDGESET(pgraph, pStart);
 	if (DGL_EDGESET_T_INITIALIZE_FUNC(pgraph, &laT, pEdgeset) < 0) {
 	    goto sp_error;
 	}
 	for (pEdge = DGL_EDGESET_T_FIRST_FUNC(&laT);
 	     pEdge; pEdge = DGL_EDGESET_T_NEXT_FUNC(&laT)
 	    ) {
-	    if (DGL_EDGE_STATUS(pEdge) & DGL_ES_DIRECTED)
-		continue;
-	    __EDGELOOP_BODY_1(1);
+	    __EDGELOOP_BODY_1(0);
 	}
 	DGL_EDGESET_T_RELEASE_FUNC(&laT);
+
+	if (pgraph->Version == 3) {
+	    pEdgeset = _DGL_INEDGESET(pgraph, pStart);
+	    if (DGL_EDGESET_T_INITIALIZE_FUNC(pgraph, &laT, pEdgeset) < 0) {
+		goto sp_error;
+	    }
+	    for (pEdge = DGL_EDGESET_T_FIRST_FUNC(&laT);
+		 pEdge; pEdge = DGL_EDGESET_T_NEXT_FUNC(&laT)
+		) {
+		if (DGL_EDGE_STATUS(pEdge) & DGL_ES_DIRECTED)
+		    continue;
+		__EDGELOOP_BODY_1(1);
+	    }
+	    DGL_EDGESET_T_RELEASE_FUNC(&laT);
+	}
     }
 
-
     /*
      * Now we begin extracting nodes from the min-heap. Each node extracted is
      * the one that is actually closest to the SP start.
@@ -470,7 +467,6 @@
 	    pStart = _DGL_EDGE_HEADNODE(pgraph, pEdge);	/* reversed head/tail */
 	}
 
-
 	/*
 	 * We do not want to explore twice the same node as a relative starting point,
 	 * that's the meaning of 'visited'. We mark actual start node as 'visited' by
@@ -488,20 +484,16 @@
 	}
 
 	/*
-	 * Dijkstra algorithm ends when the destination node is extracted from
-	 * the min distance heap, that means: no other path exist in the network giving
-	 * a shortest output.
-	 * If this happens we jump to the epilogue in order to build a path report and return.
-	 */
-	if (DGL_NODE_ID(pStart) == nDestination) {
-	    goto destination_found;
-	}
-
-	/*
 	 * Give up with visited nodes now
 	 */
 	if (pVisitedItem) {
-	    continue;
+	    if (DGL_NODE_ID(pStart) == nDestination) {
+		/* should not happen but does not harm
+		 * this case should have been handled above */
+		goto destination_found;
+	    }
+	    else
+		continue;
 	}
 
 	/*
@@ -509,8 +501,13 @@
 	 * blind alley. Just give up this direction and continue looping.
 	 * This only applies to v1 and v2 (digraphs)
 	 */
-	if (!(DGL_NODE_STATUS(pStart) & DGL_NS_HEAD) && pgraph->Version < 3)
-	    continue;
+	if (!(DGL_NODE_STATUS(pStart) & DGL_NS_HEAD) && pgraph->Version < 3) {
+	    if (DGL_NODE_ID(pStart) == nDestination) {
+		goto destination_found;
+	    }
+	    else
+		continue;
+	}
 
 	/*
 	 * save actual edge for later clip()
@@ -534,6 +531,10 @@
 	 * Scan the edgeset and loads pedge at each iteration with next-edge.
 	 * iWay == DGL_EDGESET_T_WAY_OUT then pedge is a out arc (departing from node) else ot is a in arc.
 	 * V1 has no in-degree support so iWay is always OUT, V2/3 have in-degree support.
+	 *
+	 * This loop needs to be done also when destination is found, otherwise
+	 * the node is marked as visited but its departing edges are not added to the cache
+	 * --> loose end, we might need these edges later on
 	 */
 	pEdgeset = _DGL_OUTEDGESET(pgraph, pStart);
 	if (DGL_EDGESET_T_INITIALIZE_FUNC(pgraph, &laT, pEdgeset) < 0) {
@@ -560,13 +561,23 @@
 	    }
 	    DGL_EDGESET_T_RELEASE_FUNC(&laT);
 	}
+
+	/*
+	 * Dijkstra algorithm ends when the destination node is extracted from
+	 * the min distance heap, that means: no other path exist in the network giving
+	 * a shortest output.
+	 * If this happens we jump to the epilogue in order to build a path report and return.
+	 */
+	if (DGL_NODE_ID(pStart) == nDestination) {
+	    goto destination_found;
+	}
     }
 
   sp_error:
     if (pCache == &spCache) {
 	DGL_SP_CACHE_RELEASE_FUNC(pgraph, pCache);
     }
-    return -pgraph->iErrno;	/* ==0 path not found */
+    return -pgraph->iErrno;	/* == 0 path not found */
 
   destination_found:		/* path found - build a shortest path report or report the distance only */
 



More information about the grass-commit mailing list