[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