25
25
* SHORTEST PATH CACHE
29
* - visited network: a node is marked as visited when its departing
30
* edges have been added to the cache
31
* - predist network: node distances from start node
32
* - NodeHeap: holds unvisited nodes, the next node extracted is the
33
* unvisited node closest to SP start
35
* not all nodes in the predist network have been visited, SP from start
36
* is known only for visited nodes
37
* unvisited nodes can be reached, but not necessarily on the shortest
39
* important for DGL_SP_CACHE_DISTANCE_FUNC and DGL_SP_CACHE_REPORT_FUNC
27
42
#if !defined(DGL_DEFINE_TREE_PROCS) && !defined(DGL_DEFINE_FLAT_PROCS)
29
44
int DGL_SP_CACHE_INITIALIZE_FUNC(dglGraph_s * pgraph, dglSPCache_s * pCache,
108
123
VisitedItem.nKey = nDestination;
110
124
if (avl_find(pCache->pvVisited, &VisitedItem) == NULL) {
111
125
pgraph->iErrno = DGL_ERR_TailNodeNotFound;
129
PredistItem.nKey = nDestination;
130
if (avl_find(pCache->pvPredist, &PredistItem) == NULL) {
131
pgraph->iErrno = DGL_ERR_UnexpectedNullPointer;
115
135
for (PredistItem.nKey = nDestination,
116
136
pPredistItem = avl_find(pCache->pvPredist, &PredistItem);
364
386
if (pgraph->iErrno == DGL_ERR_HeadNodeNotFound) {
365
387
DGL_SP_CACHE_RELEASE_FUNC(pgraph, pCache);
366
388
DGL_SP_CACHE_INITIALIZE_FUNC(pgraph, pCache, nStart);
368
391
else if (pgraph->iErrno != DGL_ERR_TailNodeNotFound) {
372
* reset visited status for existing cache: fix for BUG1
374
if (pCache->pvVisited) {
375
avl_destroy(pCache->pvVisited, dglTreeTouchI32Cancel);
377
if ((pCache->pvVisited =
378
avl_create(dglTreeTouchI32Compare, NULL,
379
dglTreeGetAllocator())) == NULL)
413
* now we inspect all edges departing from the start node
414
* - at each loop 'pedge' points to the edge in the edge buffer
415
* - we invoke the caller's clip() and eventually skip the edge (clip() != 0)
416
* - we insert a item in the predist network to set actual predecessor and distance
417
* (there is no precedecessor at this stage) and actual distance from the starting node
418
* (at this stage it equals the edge's cost)
419
* - we insert a item in the node min-heap (sorted on node distance), storing the offset of the
420
* edge in the edge buffer.
421
* In the case of undirected graph (version 3) we inspect input edges as well.
423
pEdgeset = _DGL_OUTEDGESET(pgraph, pStart);
424
if (DGL_EDGESET_T_INITIALIZE_FUNC(pgraph, &laT, pEdgeset) < 0) {
427
for (pEdge = DGL_EDGESET_T_FIRST_FUNC(&laT);
428
pEdge; pEdge = DGL_EDGESET_T_NEXT_FUNC(&laT)
430
__EDGELOOP_BODY_1(0);
432
DGL_EDGESET_T_RELEASE_FUNC(&laT);
434
if (pgraph->Version == 3) {
435
pEdgeset = _DGL_INEDGESET(pgraph, pStart);
424
/* if we do not need a new cache, we just continue with the unvisited
425
* nodes in the cache */
428
* now we inspect all edges departing from the start node
429
* - at each loop 'pedge' points to the edge in the edge buffer
430
* - we invoke the caller's clip() and eventually skip the edge (clip() != 0)
431
* - we insert a item in the predist network to set actual predecessor and distance
432
* (there is no precedecessor at this stage) and actual distance from the starting node
433
* (at this stage it equals the edge's cost)
434
* - we insert a item in the node min-heap (sorted on node distance), storing the offset of the
435
* edge in the edge buffer.
436
* In the case of undirected graph (version 3) we inspect input edges as well.
438
pEdgeset = _DGL_OUTEDGESET(pgraph, pStart);
436
439
if (DGL_EDGESET_T_INITIALIZE_FUNC(pgraph, &laT, pEdgeset) < 0) {
439
442
for (pEdge = DGL_EDGESET_T_FIRST_FUNC(&laT);
440
443
pEdge; pEdge = DGL_EDGESET_T_NEXT_FUNC(&laT)
442
if (DGL_EDGE_STATUS(pEdge) & DGL_ES_DIRECTED)
444
__EDGELOOP_BODY_1(1);
445
__EDGELOOP_BODY_1(0);
446
447
DGL_EDGESET_T_RELEASE_FUNC(&laT);
449
if (pgraph->Version == 3) {
450
pEdgeset = _DGL_INEDGESET(pgraph, pStart);
451
if (DGL_EDGESET_T_INITIALIZE_FUNC(pgraph, &laT, pEdgeset) < 0) {
454
for (pEdge = DGL_EDGESET_T_FIRST_FUNC(&laT);
455
pEdge; pEdge = DGL_EDGESET_T_NEXT_FUNC(&laT)
457
if (DGL_EDGE_STATUS(pEdge) & DGL_ES_DIRECTED)
459
__EDGELOOP_BODY_1(1);
461
DGL_EDGESET_T_RELEASE_FUNC(&laT);
451
466
* Now we begin extracting nodes from the min-heap. Each node extracted is
452
467
* the one that is actually closest to the SP start.
491
* Dijkstra algorithm ends when the destination node is extracted from
492
* the min distance heap, that means: no other path exist in the network giving
494
* If this happens we jump to the epilogue in order to build a path report and return.
496
if (DGL_NODE_ID(pStart) == nDestination) {
497
goto destination_found;
501
505
* Give up with visited nodes now
503
507
if (pVisitedItem) {
508
if (DGL_NODE_ID(pStart) == nDestination) {
509
/* should not happen but does not harm
510
* this case should have been handled above */
511
goto destination_found;
534
549
* Scan the edgeset and loads pedge at each iteration with next-edge.
535
550
* iWay == DGL_EDGESET_T_WAY_OUT then pedge is a out arc (departing from node) else ot is a in arc.
536
551
* V1 has no in-degree support so iWay is always OUT, V2/3 have in-degree support.
553
* This loop needs to be done also when destination is found, otherwise
554
* the node is marked as visited but its departing edges are not added to the cache
555
* --> loose end, we might need these edges later on
538
557
pEdgeset = _DGL_OUTEDGESET(pgraph, pStart);
539
558
if (DGL_EDGESET_T_INITIALIZE_FUNC(pgraph, &laT, pEdgeset) < 0) {
561
580
DGL_EDGESET_T_RELEASE_FUNC(&laT);
584
* Dijkstra algorithm ends when the destination node is extracted from
585
* the min distance heap, that means: no other path exist in the network giving
587
* If this happens we jump to the epilogue in order to build a path report and return.
589
if (DGL_NODE_ID(pStart) == nDestination) {
590
goto destination_found;
566
595
if (pCache == &spCache) {
567
596
DGL_SP_CACHE_RELEASE_FUNC(pgraph, pCache);
569
return -pgraph->iErrno; /* ==0 path not found */
598
return -pgraph->iErrno; /* == 0 path not found */
571
600
destination_found: /* path found - build a shortest path report or report the distance only */