find paths from src to dest by traversing from dest to src using DFS inspecting nodes which where discovered by the previous call to `AllShortestPaths_FindMinimumLength`
| 103 | // inspecting nodes which where discovered by |
| 104 | // the previous call to `AllShortestPaths_FindMinimumLength` |
| 105 | Path *AllShortestPaths_NextPath |
| 106 | ( |
| 107 | AllPathsCtx *ctx |
| 108 | ) { |
| 109 | ASSERT(ctx != NULL); |
| 110 | |
| 111 | uint32_t depth = Path_NodeCount(ctx->path); |
| 112 | if(depth > 0) { |
| 113 | // a full path already returned |
| 114 | // advance to next path by backtracking |
| 115 | depth--; |
| 116 | } else { |
| 117 | if(array_len(ctx->levels[0]) == 0) return NULL; |
| 118 | |
| 119 | Path_EnsureLen(ctx->path, ctx->minLen); |
| 120 | LevelConnection frontierConnection = array_pop(ctx->levels[0]); |
| 121 | Node frontierNode = frontierConnection.node; |
| 122 | Path_SetNode(ctx->path, ctx->minLen - depth - 1, frontierNode); |
| 123 | depth++; |
| 124 | addNeighbors(ctx, &frontierConnection, depth, ctx->dir); |
| 125 | } |
| 126 | |
| 127 | // as long as we didn't found a full path from src to dest |
| 128 | while (depth < ctx->maxLen) { |
| 129 | if (array_len(ctx->levels[depth]) > 0) { |
| 130 | // get a new node from the frontier |
| 131 | bool is_visited; |
| 132 | LevelConnection frontierConnection = array_pop(ctx->levels[depth]); |
| 133 | Node frontierNode = frontierConnection.node; |
| 134 | NodeID frontierID = ENTITY_GET_ID(&frontierNode); |
| 135 | GrB_Info info = GrB_Vector_extractElement_BOOL(&is_visited, |
| 136 | ctx->visited, frontierID); |
| 137 | |
| 138 | // consider only previously discovered nodes |
| 139 | if(info == GrB_NO_VALUE) continue; |
| 140 | |
| 141 | // if we reached to the end of the path and this node is not the |
| 142 | // dst node continue |
| 143 | if(depth == ctx->maxLen - 1 && |
| 144 | frontierID != ENTITY_GET_ID(ctx->dst)) { |
| 145 | continue; |
| 146 | } |
| 147 | |
| 148 | Path_SetNode(ctx->path, ctx->minLen - depth - 1, frontierNode); |
| 149 | Path_SetEdge(ctx->path, ctx->minLen - depth - 1, frontierConnection.edge); |
| 150 | |
| 151 | if(depth == ctx->maxLen - 1) break; |
| 152 | |
| 153 | depth++; |
| 154 | addNeighbors(ctx, &frontierConnection, depth, ctx->dir); |
| 155 | } else { |
| 156 | depth--; |
| 157 | if(depth == 0) { |
| 158 | Path_Clear(ctx->path); |
| 159 | // first level fully consumed |
| 160 | // there are no more paths leading from src to dest, we're done |
| 161 | return NULL; |
| 162 | } |
no test coverage detected