use DFS to find all paths from src to dst tracking cost and weight
| 428 | |
| 429 | // use DFS to find all paths from src to dst tracking cost and weight |
| 430 | static void SPpaths_next |
| 431 | ( |
| 432 | SinglePairCtx *ctx, |
| 433 | WeightedPath *p, |
| 434 | double max_weight |
| 435 | ) { |
| 436 | // as long as path is not empty OR there are neighbors to traverse. |
| 437 | while(Path_NodeCount(ctx->path) || _SinglePairCtx_LevelNotEmpty(ctx, 0)) { |
| 438 | uint32_t depth = Path_NodeCount(ctx->path); |
| 439 | |
| 440 | // can we advance? |
| 441 | if(_SinglePairCtx_LevelNotEmpty(ctx, depth)) { |
| 442 | // get a new frontier. |
| 443 | LevelConnection frontierConnection = array_pop(ctx->levels[depth]); |
| 444 | Node frontierNode = frontierConnection.node; |
| 445 | |
| 446 | bool frontierAlreadyOnPath = Path_ContainsNode(ctx->path, &frontierNode); |
| 447 | |
| 448 | // don't allow cycles |
| 449 | if(frontierAlreadyOnPath) continue; |
| 450 | |
| 451 | // add frontier to path. |
| 452 | Path_AppendNode(ctx->path, frontierNode); |
| 453 | |
| 454 | // if depth is 0 this is the source node, there is no leading edge to it. |
| 455 | // For depth > 0 for each frontier node, there is a leading edge. |
| 456 | if(depth > 0) { |
| 457 | SIValue c = _get_value_or_defualt((GraphEntity *)&frontierConnection.edge, ctx->cost_prop, SI_LongVal(1)); |
| 458 | SIValue w = _get_value_or_defualt((GraphEntity *)&frontierConnection.edge, ctx->weight_prop, SI_LongVal(1)); |
| 459 | if(p->cost + SI_GET_NUMERIC(c) <= ctx->max_cost && p->weight + SI_GET_NUMERIC(w) <= max_weight) { |
| 460 | p->cost += SI_GET_NUMERIC(c); |
| 461 | p->weight += SI_GET_NUMERIC(w); |
| 462 | Path_AppendEdge(ctx->path, frontierConnection.edge); |
| 463 | } else { |
| 464 | Path_PopNode(ctx->path); |
| 465 | continue; |
| 466 | } |
| 467 | } |
| 468 | |
| 469 | // update path depth. |
| 470 | depth++; |
| 471 | |
| 472 | // introduce neighbors only if path depth < maximum path length. |
| 473 | // and frontier wasn't already expanded. |
| 474 | if(depth < ctx->maxLen) { |
| 475 | addNeighbors(ctx, &frontierConnection, depth, ctx->dir); |
| 476 | } |
| 477 | |
| 478 | // see if we can return path. |
| 479 | if(depth >= ctx->minLen && depth <= ctx->maxLen) { |
| 480 | Node dst = Path_Head(ctx->path); |
| 481 | if(ENTITY_GET_ID(ctx->dst) != ENTITY_GET_ID(&dst)) { |
| 482 | continue; |
| 483 | } |
| 484 | p->path = ctx->path; |
| 485 | return; |
| 486 | } |
| 487 | } else { |
no test coverage detected