Skip to content

Commit 861c9f7

Browse files
Optimize predecessor cycle checks for hot path
Co-authored-by: Andrey G <networmix@gmail.com>
1 parent d2cca2c commit 861c9f7

1 file changed

Lines changed: 12 additions & 10 deletions

File tree

src/shortest_paths.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -230,28 +230,29 @@ shortest_paths_core(const StrictMultiDiGraph& g, NodeId src,
230230

231231
std::vector<std::uint32_t> seen(static_cast<std::size_t>(N), 0u);
232232
std::uint32_t seen_token = 0u;
233+
std::vector<NodeId> dfs_stack;
234+
dfs_stack.reserve(16);
233235
auto parent_reaches_child_via_pred_links = [&](NodeId parent, NodeId child) {
234236
if (parent == child) return true;
235237
++seen_token;
236238
if (seen_token == 0) {
237239
std::fill(seen.begin(), seen.end(), 0);
238240
seen_token = 1;
239241
}
240-
std::vector<NodeId> st;
241-
st.reserve(16);
242-
st.push_back(parent);
242+
dfs_stack.clear();
243+
dfs_stack.push_back(parent);
243244
seen[static_cast<std::size_t>(parent)] = seen_token;
244-
while (!st.empty()) {
245-
NodeId cur = st.back();
246-
st.pop_back();
245+
while (!dfs_stack.empty()) {
246+
NodeId cur = dfs_stack.back();
247+
dfs_stack.pop_back();
247248
if (cur == child) return true;
248249
for (const auto& pr : pred_lists[static_cast<std::size_t>(cur)]) {
249250
NodeId p = pr.first;
250251
if (p < 0 || p >= N) continue;
251252
auto p_idx = static_cast<std::size_t>(p);
252253
if (seen[p_idx] == seen_token) continue;
253254
seen[p_idx] = seen_token;
254-
st.push_back(p);
255+
dfs_stack.push_back(p);
255256
}
256257
}
257258
return false;
@@ -383,9 +384,10 @@ shortest_paths_core(const StrictMultiDiGraph& g, NodeId src,
383384
}
384385
// Multipath: found equal-cost alternative path to v.
385386
else if (multipath && new_cost == dist[v_idx]) {
386-
// Guard against zero-cost predecessor cycles by rejecting additions
387-
// that would introduce a cycle in predecessor relations.
388-
if (!parent_reaches_child_via_pred_links(u, v)) {
387+
// With non-negative edge costs, predecessor cycles can only arise on
388+
// zero-cost equal-distance tiers. Keep the cycle guard only for that
389+
// case to minimize overhead in typical positive-cost topologies.
390+
if (min_edge_cost != 0 || !parent_reaches_child_via_pred_links(u, v)) {
389391
pred_lists[v_idx].push_back({u, std::move(selected_edges)});
390392
}
391393
// Note: In multipath mode, we don't update min_residual_to_node because

0 commit comments

Comments
 (0)