Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
57f3204
Implement incoming edges Phases 1-3 and rename concepts/aliases for c…
pratzl Feb 22, 2026
054d6cc
Swap primary/alias: out_edges, out_degree, find_out_edge are now primary
pratzl Feb 22, 2026
d53310d
Rename contains_edge -> contains_out_edge (primary), contains_edge is…
pratzl Feb 22, 2026
64cc2d1
Rename has_edge(g) CPO to has_edges(g)
pratzl Feb 22, 2026
80a4e1a
Phase 4: undirected_adjacency_list incoming-edge support
pratzl Feb 22, 2026
0951379
Update Phase 5-6 plan: out_* primary naming for views and adaptors
pratzl Feb 22, 2026
428c1f4
Update Phase 5 plan: single-header approach for views
pratzl Feb 22, 2026
94abc34
Restructure Phases 5-7: edge accessor parameterization
pratzl Feb 22, 2026
90f6157
Phase 5: Edge accessor + parameterized incidence/neighbors views
pratzl Feb 22, 2026
ecef002
Phase 6: Pipe-syntax adaptors for incoming views + alias renames
pratzl Feb 22, 2026
3f994fc
Phase 8: dynamic_graph bidirectional support with direction tags
pratzl Feb 22, 2026
7911ba1
Phase 9: transpose_view + kosaraju bidirectional overload
pratzl Feb 22, 2026
50b8e15
Phases 7 & 10: Accessor-parameterized search views + documentation
pratzl Feb 23, 2026
e96800e
docs: update migration guide and coverage report for bidirectional/un…
pratzl Feb 23, 2026
4c6862d
Minor update to migration guide for v2.1.0 release.
pratzl Feb 23, 2026
4b933c8
docs: update metrics and implementation matrix (2026-02-23)
pratzl Feb 23, 2026
026df37
refine dynamic_edge_refactor_strategy: comprehensive review fixes\n\n…
pratzl Feb 23, 2026
ded9bd9
add phased implementation plan for dynamic_edge refactor\n\n6-phase p…
pratzl Feb 23, 2026
9a39591
docs: apply final review patches to dynamic_edge_refactor_plan
pratzl Feb 23, 2026
715020f
feat: add dynamic_in_edge class and detection-idiom aliases (Phase 1)
pratzl Feb 23, 2026
46ba10d
feat: wire in_edge_type into bidir vertex base and load_edges (Phase 2)
pratzl Feb 23, 2026
f560d86
refactor: rename dynamic_edge → dynamic_out_edge with deprecated alia…
pratzl Feb 23, 2026
0b57cec
docs: mark Phase 3 COMPLETE in refactor plan
pratzl Feb 23, 2026
89e1018
refactor: remove Sourced from edge classes, collapse dynamic_out_edge…
pratzl Feb 23, 2026
08e6ef6
Phase 4b: Remove bool Sourced from vertex and graph classes
pratzl Feb 23, 2026
67a0e1f
Phase 4c: Remove bool Sourced from all 27 traits files
pratzl Feb 23, 2026
7b06988
Phase 4d: Simplify load_edges — remove Sourced branches and make_in_edge
pratzl Feb 23, 2026
01a980a
Phase 4f/4g: Compile gate — fix examples, verify library headers compile
pratzl Feb 23, 2026
cd8b5a5
docs: update status tracker — Phase 4a-4g all COMPLETE
pratzl Feb 23, 2026
9fd9c1f
Phase 5.1: Update graph_test_types.hpp — remove Sourced, add bidir al…
pratzl Feb 23, 2026
880ae00
test: update all tests for Sourced removal and add bidir uniform/non-…
pratzl Feb 23, 2026
74c731d
chore: update status tracker for Phase 5 completion (5.8 count fix, 5…
pratzl Feb 23, 2026
686d897
chore: fix stale dynamic_edge comment in edge_descriptor.hpp (Phase 6.1)
pratzl Feb 23, 2026
ee50199
docs: update Doxygen comments in dynamic_graph.hpp — remove Sourced/d…
pratzl Feb 23, 2026
e8a426b
docs: fix stale Sourced references in migration-from-v2.md (Phase 6.3)
pratzl Feb 23, 2026
42e6414
docs: cleanup Doxygen, update user docs, archive strategy (Phase 6)
pratzl Feb 23, 2026
25fc136
chore: record Phase 6.6 commit hash in status tracker
pratzl Feb 23, 2026
3ccfd6a
test: add coverage for uncovered dijkstra_shortest_paths.hpp lines (e…
pratzl Feb 23, 2026
57f3efb
docs: update coverage.md — dijkstra 100% line coverage, overall 96.3%
pratzl Feb 23, 2026
b8223e9
docs: fix Quick Example in README — add init_shortest_paths, weight f…
pratzl Feb 23, 2026
de6fb62
Phase 0: Add raw_vertex_id_t, vertex_id_store_t; protect vertex_id_t …
pratzl Feb 25, 2026
6a2531d
Phase 1: descriptor return types to decltype(auto)
pratzl Feb 26, 2026
14ee056
Phase 2: Concept and trait requires-expressions use const vertex_id_t…
pratzl Feb 26, 2026
c8c43db
Phase 3: View factory functions and constructors use const vertex_id_…
pratzl Feb 26, 2026
8274ab8
Phase 4a: Algorithm parameter signatures use const vertex_id_t<G>&
pratzl Feb 26, 2026
d0678bd
Phase 4b: Algorithm internals use vertex_id_store_t<G> with static_as…
pratzl Feb 26, 2026
61bed7c
Phase 5: Adaptor/pipe syntax verified — no changes needed
pratzl Feb 26, 2026
5ae80cf
Phase 6: Update docs, examples, and fix missed prim seed param
pratzl Feb 26, 2026
d1ef3f5
vertex_id_const_ref_plan.md completed
pratzl Feb 26, 2026
085b989
Merge origin/main (Incoming #4) into feature/vertex-id-const-ref
pratzl Feb 26, 2026
f4e459b
Fix static_assert platform portability: check size+signedness not exa…
pratzl Feb 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
675 changes: 675 additions & 0 deletions agents/vertex_id_const_ref_plan.md

Large diffs are not rendered by default.

707 changes: 707 additions & 0 deletions agents/vertex_id_const_ref_strategy.md

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions docs/contributing/algorithm-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,11 @@ template <adjacency_list G,
class WF = function<range_value_t<Distance>(edge_t<G>)>>
requires /* ... constraints ... */
void algorithm_name(
G&& g, // graph
vertex_id_t<G> source, // starting vertex
Distance& distance, // out: distances
Predecessor& predecessor, // out: predecessors
WF&& weight) // edge weight function
G&& g, // graph
const vertex_id_t<G>& source, // starting vertex
Distance& distance, // out: distances
Predecessor& predecessor, // out: predecessors
WF&& weight) // edge weight function
```

---
Expand Down
4 changes: 2 additions & 2 deletions docs/user-guide/algorithms/bellman_ford.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ bellman_ford_shortest_paths(G&& g, const Sources& sources,

// Single-source, distances + predecessors
[[nodiscard]] constexpr optional<vertex_id_t<G>>
bellman_ford_shortest_paths(G&& g, vertex_id_t<G> source,
bellman_ford_shortest_paths(G&& g, const vertex_id_t<G>& source,
Distances& distances, Predecessors& predecessors,
WF&& weight,
Visitor&& visitor = empty_visitor(),
Expand All @@ -93,7 +93,7 @@ bellman_ford_shortest_distances(G&& g, const Sources& sources,

// Single-source, distances only
[[nodiscard]] constexpr optional<vertex_id_t<G>>
bellman_ford_shortest_distances(G&& g, vertex_id_t<G> source,
bellman_ford_shortest_distances(G&& g, const vertex_id_t<G>& source,
Distances& distances,
WF&& weight,
Visitor&& visitor = empty_visitor(),
Expand Down
2 changes: 1 addition & 1 deletion docs/user-guide/algorithms/bfs.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void breadth_first_search(G&& g, const Sources& sources,
Visitor&& visitor = empty_visitor());

// Single-source BFS
void breadth_first_search(G&& g, vertex_id_t<G> source,
void breadth_first_search(G&& g, const vertex_id_t<G>& source,
Visitor&& visitor = empty_visitor());
```

Expand Down
4 changes: 2 additions & 2 deletions docs/user-guide/algorithms/dijkstra.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ constexpr void dijkstra_shortest_paths(G&& g, const Sources& sources,
Combine&& combine = plus<>{});

// Single-source, distances + predecessors
constexpr void dijkstra_shortest_paths(G&& g, vertex_id_t<G> source,
constexpr void dijkstra_shortest_paths(G&& g, const vertex_id_t<G>& source,
Distances& distances, Predecessors& predecessors,
WF&& weight = /* default returns 1 */,
Visitor&& visitor = empty_visitor(),
Expand All @@ -93,7 +93,7 @@ constexpr void dijkstra_shortest_distances(G&& g, const Sources& sources,
Combine&& combine = plus<>{});

// Single-source, distances only
constexpr void dijkstra_shortest_distances(G&& g, vertex_id_t<G> source,
constexpr void dijkstra_shortest_distances(G&& g, const vertex_id_t<G>& source,
Distances& distances,
WF&& weight = /* default returns 1 */,
Visitor&& visitor = empty_visitor(),
Expand Down
2 changes: 1 addition & 1 deletion docs/user-guide/algorithms/mis.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ remaining unmarked vertices in order.

```cpp
size_t maximal_independent_set(G&& g, OutputIterator mis,
vertex_id_t<G> seed = 0);
const vertex_id_t<G>& seed = 0);
```

**Returns** the number of vertices in the MIS. Selected vertex IDs are written
Expand Down
4 changes: 2 additions & 2 deletions docs/user-guide/algorithms/mst.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@ lightest edge crossing the cut between tree and non-tree vertices.
```cpp
// Simple: uses default weight function from edge values
auto prim(G&& g, Predecessors& predecessors, Weights& weights,
vertex_id_t<G> seed = 0);
const vertex_id_t<G>& seed = 0);

// Full: custom comparator, initial distance, and weight function
auto prim(G&& g, Predecessors& predecessors, Weights& weights,
Compare compare, range_value_t<Weights> init_dist,
WF weight_fn, vertex_id_t<G> seed = 0);
WF weight_fn, const vertex_id_t<G>& seed = 0);
```

**Returns** the total MST weight.
Expand Down
2 changes: 1 addition & 1 deletion docs/user-guide/algorithms/topological_sort.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Three overloads cover different use cases:
bool topological_sort(const G& g, OutputIterator result);

// Single-source topological sort
bool topological_sort(const G& g, vertex_id_t<G> source, OutputIterator result);
bool topological_sort(const G& g, const vertex_id_t<G>& source, OutputIterator result);

// Multi-source topological sort
bool topological_sort(const G& g, const Sources& sources, OutputIterator result);
Expand Down
4 changes: 2 additions & 2 deletions examples/dijkstra_clrs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ requires forward_range<vertex_range_t<G>> && //
convertible_to<vertex_id_t<G>, range_value_t<Predecessor>> && //
edge_weight_function<G, WF>
void dijkstra_clrs(
G&& g, // graph
vertex_id_t<G> seed, // starting vertex_id
G&& g, // graph
const vertex_id_t<G>& seed, // starting vertex_id
Distance& distance, // out: distance[uid] of uid from seed
Predecessor& predecessor, // out: predecessor[uid] of uid in path
WF&& weight = [](const auto&,
Expand Down
2 changes: 1 addition & 1 deletion include/graph/adj_list/adjacency_list_concepts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ concept out_edge_range = std::ranges::forward_range<R> && edge<G, std::ranges::r
* @tparam V Vertex type (must be vertex_descriptor)
*/
template <class G, class V>
concept vertex = is_vertex_descriptor_v<std::remove_cvref_t<V>> && requires(G& g, const V& u, vertex_id_t<G> uid) {
concept vertex = is_vertex_descriptor_v<std::remove_cvref_t<V>> && requires(G& g, const V& u, const vertex_id_t<G>& uid) {
vertex_id(g, u);
find_vertex(g, uid);
};
Expand Down
12 changes: 6 additions & 6 deletions include/graph/adj_list/adjacency_list_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace detail {

// Helper to detect if degree(g, uid) is valid
template <typename G>
concept has_degree_uid_impl = requires(G& g, vertex_id_t<G> uid) {
concept has_degree_uid_impl = requires(G& g, const vertex_id_t<G>& uid) {
{ degree(g, uid) } -> std::integral;
};
} // namespace detail
Expand Down Expand Up @@ -59,7 +59,7 @@ inline constexpr bool has_degree_v = has_degree<G>;
namespace detail {
// Helper to detect if find_vertex(g, uid) is valid and returns correct type
template <typename G>
concept has_find_vertex_impl = requires(G& g, vertex_id_t<G> uid) {
concept has_find_vertex_impl = requires(G& g, const vertex_id_t<G>& uid) {
{ find_vertex(g, uid) } -> std::same_as<vertex_t<G>>;
};
} // namespace detail
Expand Down Expand Up @@ -94,13 +94,13 @@ namespace detail {

// Helper to detect if find_vertex_edge(g, u, vid) is valid
template <typename G>
concept has_find_vertex_edge_uvid_impl = requires(G& g, vertex_t<G> u, vertex_id_t<G> vid) {
concept has_find_vertex_edge_uvid_impl = requires(G& g, vertex_t<G> u, const vertex_id_t<G>& vid) {
{ find_vertex_edge(g, u, vid) } -> std::same_as<edge_t<G>>;
};

// Helper to detect if find_vertex_edge(g, uid, vid) is valid
template <typename G>
concept has_find_vertex_edge_uidvid_impl = requires(G& g, vertex_id_t<G> uid, vertex_id_t<G> vid) {
concept has_find_vertex_edge_uidvid_impl = requires(G& g, const vertex_id_t<G>& uid, const vertex_id_t<G>& vid) {
{ find_vertex_edge(g, uid, vid) } -> std::same_as<edge_t<G>>;
};
} // namespace detail
Expand Down Expand Up @@ -206,13 +206,13 @@ namespace detail {

// Helper to detect if find_in_edge(g, u, vid) is valid with descriptor + id
template <typename G>
concept has_find_in_edge_uid_impl = requires(G& g, vertex_t<G> u, vertex_id_t<G> vid) {
concept has_find_in_edge_uid_impl = requires(G& g, vertex_t<G> u, const vertex_id_t<G>& vid) {
{ find_in_edge(g, u, vid) };
};

// Helper to detect if find_in_edge(g, uid, vid) is valid with vertex IDs
template <typename G>
concept has_find_in_edge_uidvid_impl = requires(G& g, vertex_id_t<G> uid, vertex_id_t<G> vid) {
concept has_find_in_edge_uidvid_impl = requires(G& g, const vertex_id_t<G>& uid, const vertex_id_t<G>& vid) {
{ find_in_edge(g, uid, vid) };
};
} // namespace detail
Expand Down
17 changes: 14 additions & 3 deletions include/graph/adj_list/detail/graph_cpo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,13 +388,24 @@ inline namespace _cpo_instances {
/**
* @brief Vertex ID type for graph G
*
* The type of the unique identifier returned by vertex_id(g, u).
* The type of the unique identifier returned by vertex_id(g, u), with references stripped.
* - For random-access containers (vector, deque): size_t (index)
* - For associative containers (map): key type
* - For associative containers (map): key type (e.g. std::string)
* - For bidirectional containers: iterator-based ID
*/
template <typename G>
using vertex_id_t = decltype(vertex_id(std::declval<G&>(), std::declval<vertex_t<G>>()));
using vertex_id_t = std::remove_cvref_t<
decltype(vertex_id(std::declval<G&>(), std::declval<vertex_t<G>>()))>;

/**
* @brief Raw return type of vertex_id(g, u), preserving reference-ness.
*
* For vector-based graphs this is a prvalue (e.g. size_t).
* For map-based graphs this is an lvalue reference to the stable key (e.g. const std::string&).
* Used primarily by vertex_id_store_t to select the optimal internal storage strategy.
*/
template <typename G>
using raw_vertex_id_t = decltype(vertex_id(std::declval<G&>(), std::declval<vertex_t<G>>()));

namespace _cpo_impls {

Expand Down
49 changes: 19 additions & 30 deletions include/graph/adj_list/edge_descriptor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,44 +66,33 @@ class edge_descriptor {

/**
* @brief Get the source vertex ID
* @return The vertex ID of the source vertex
* @return The vertex ID of the source vertex (by value for integral, const& for map keys)
*
* Extracts the ID from the stored source vertex descriptor.
*
* @note Current implementation returns by value (auto) which is suitable for
* integral vertex IDs. When non-trivial vertex ID types (e.g., std::string)
* are supported, this method should:
* 1. Change return type to decltype(auto) for reference semantics
* 2. This delegates to vertex_descriptor::vertex_id() which will also need updating
* See descriptor.md "Lambda Reference Binding Issues" section for details.
* Returns decltype(auto) to propagate reference semantics from vertex_descriptor::vertex_id().
*/
[[nodiscard]] constexpr auto source_id() const noexcept { return source_.vertex_id(); }
[[nodiscard]] constexpr decltype(auto) source_id() const noexcept { return source_.vertex_id(); }

/**
* @brief Get the target vertex ID from the edge data
* @param vertex_data The vertex/edge data structure passed from the CPO
* @return The target vertex identifier extracted from the edge
*
* For random access iterators, uses the stored index to access the container.
* For forward/bidirectional iterators, dereferences the stored iterator.
*
* The vertex_data parameter varies by graph structure:
* - vov-style: vertex object with .edges() method
* - map-based: std::pair<VId, vertex_type> where .second is the vertex
* - raw adjacency: the edge container directly
* Returns decltype(auto) for reference semantics on non-trivial ID types.
* Pair-like .first branches are parenthesized to return const& to the stable
* key rather than copying. std::get<0> and native .target_id() calls already
* return appropriate types.
*/
/**
* @brief Get the source vertex ID by navigating the edge container (in-edge only)
* @param vertex_data The vertex/edge data structure passed from the CPO
* @return The source vertex identifier extracted from the native in-edge
*
* Edge data extraction:
* - Simple integral types: returns the value directly as target ID
* - Pair-like types: returns .first as target ID
* - Tuple-like types: returns std::get<0> as target ID
* For in-edge descriptors, source_id() (no args) returns the owning vertex ID
* which is actually the target. This overload navigates the in_edges container
* to retrieve the native edge's source_id — the actual source vertex.
*
* @note Current implementation returns by value (auto) which is suitable for
* integral vertex IDs. When non-trivial vertex ID types (e.g., std::string)
* are supported, this method should:
* 1. Change return type to decltype(auto) for reference semantics
* 2. Replace lambda-based extraction with direct if constexpr branches
* 3. Wrap return expressions in parentheses: return (edge_val.first);
* See descriptor.md "Lambda Reference Binding Issues" section for details.
* Only available when EdgeDirection is in_edge_tag.
*/
/**
* @brief Get the source vertex ID by navigating the edge container (in-edge only)
Expand Down Expand Up @@ -206,7 +195,7 @@ class edge_descriptor {
if constexpr (requires { vertex_data.second.edges(); }) {
return vertex_data.second.edges();
} else {
return vertex_data.second;
return (vertex_data.second); // parenthesized: return const& to the container
}
} else {
return vertex_data;
Expand Down Expand Up @@ -234,8 +223,8 @@ class edge_descriptor {
// Edge object with target_id() member (e.g., dynamic_out_edge)
return edge_val.target_id();
} else if constexpr (requires { edge_val.first; }) {
// Pair-like: .first is the target ID
return edge_val.first;
// Pair-like: .first is the target ID — parenthesized for reference semantics
return (edge_val.first);
} else if constexpr (requires { std::get<0>(edge_val); }) {
// Tuple-like: first element is the target ID
return std::get<0>(edge_val);
Expand Down
18 changes: 10 additions & 8 deletions include/graph/adj_list/vertex_descriptor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,18 @@ class vertex_descriptor {

/**
* @brief Get the vertex ID
* @return For random access: the index. For bidirectional: the key from the pair
* @return For random access: the index (by value). For bidirectional: const& to the key.
*
* @note Current implementation returns by value (auto) which is suitable for
* integral vertex IDs. When non-trivial vertex ID types (e.g., std::string)
* are supported, this method should:
* 1. Change return type to decltype(auto) for reference semantics
* 2. Wrap return expressions in parentheses: return (storage_);
* See descriptor.md "Lambda Reference Binding Issues" section for details.
* Returns decltype(auto) so that map-based graphs return a const reference
* to the stable key stored in the map node, avoiding copies of non-trivial
* ID types like std::string.
*
* For random-access iterators, `return storage_;` (non-parenthesized) ensures
* decltype deduces the value type (size_t) — safe even on temporaries.
* For bidirectional iterators, std::get<0> returns a reference to the map key,
* which is stable as long as the container is alive.
*/
[[nodiscard]] constexpr auto vertex_id() const noexcept {
[[nodiscard]] constexpr decltype(auto) vertex_id() const noexcept {
if constexpr (std::random_access_iterator<VertexIter>) {
return storage_;
} else {
Expand Down
20 changes: 11 additions & 9 deletions include/graph/algorithm/bellman_ford_shortest_paths.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,16 @@ requires convertible_to<range_value_t<Sources>, vertex_id_t<G>> && //
Visitor&& visitor = empty_visitor(),
Compare&& compare = less<range_value_t<Distances>>(),
Combine&& combine = plus<range_value_t<Distances>>()) {
using id_type = vertex_id_t<G>;
using id_type = vertex_id_store_t<G>;
static_assert(std::is_same_v<id_type, vertex_id_t<G>>,
"vertex_id_store_t<G> should equal vertex_id_t<G> for index_adjacency_list");
using DistanceValue = range_value_t<Distances>;
using weight_type = invoke_result_t<WF, const std::remove_reference_t<G>&, edge_t<G>>;
using return_type = optional<vertex_id_t<G>>;

// relaxing the target is the function of reducing the distance from the source to the target
auto relax_target = [&g, &predecessor, &distances, &compare, &combine] //
(const edge_t<G>& e, vertex_id_t<G> uid, const weight_type& w_e) -> bool {
(const edge_t<G>& e, const vertex_id_t<G>& uid, const weight_type& w_e) -> bool {
id_type vid = target_id(g, e);
const DistanceValue d_u = distances[static_cast<size_t>(uid)];
const DistanceValue d_v = distances[static_cast<size_t>(vid)];
Expand Down Expand Up @@ -301,10 +303,10 @@ requires is_arithmetic_v<range_value_t<Distances>> && //
sized_range<Predecessors> && //
basic_edge_weight_function<G, WF, range_value_t<Distances>, Compare, Combine>
[[nodiscard]] constexpr optional<vertex_id_t<G>> bellman_ford_shortest_paths(
G&& g,
vertex_id_t<G> source,
Distances& distances,
Predecessors& predecessor,
G&& g,
const vertex_id_t<G>& source,
Distances& distances,
Predecessors& predecessor,
WF&& weight = [](const auto&,
const edge_t<G>& uv) { return range_value_t<Distances>(1); }, // default weight(g, uv) -> 1
Visitor&& visitor = empty_visitor(),
Expand Down Expand Up @@ -392,9 +394,9 @@ requires is_arithmetic_v<range_value_t<Distances>> && //
sized_range<Distances> && //
basic_edge_weight_function<G, WF, range_value_t<Distances>, Compare, Combine>
[[nodiscard]] constexpr optional<vertex_id_t<G>> bellman_ford_shortest_distances(
G&& g,
vertex_id_t<G> source,
Distances& distances,
G&& g,
const vertex_id_t<G>& source,
Distances& distances,
WF&& weight = [](const auto&,
const edge_t<G>& uv) { return range_value_t<Distances>(1); }, // default weight(g, uv) -> 1
Visitor&& visitor = empty_visitor(),
Expand Down
10 changes: 6 additions & 4 deletions include/graph/algorithm/breadth_first_search.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,9 @@ requires std::convertible_to<std::ranges::range_value_t<Sources>, vertex_id_t<G>
void breadth_first_search(G&& g, // graph
const Sources& sources,
Visitor&& visitor = empty_visitor()) {
using id_type = vertex_id_t<G>;
using id_type = vertex_id_store_t<G>;
static_assert(std::is_same_v<id_type, vertex_id_t<G>>,
"vertex_id_store_t<G> should equal vertex_id_t<G> for index_adjacency_list");

// Initialize BFS data structures
std::queue<id_type> Q; // FIFO queue for level-order traversal
Expand Down Expand Up @@ -333,9 +335,9 @@ void breadth_first_search(G&& g, // graph
* @see views::vertices_bfs BFS view for range-based traversal
*/
template <index_adjacency_list G, class Visitor = empty_visitor>
void breadth_first_search(G&& g, // graph
vertex_id_t<G> source, // starting vertex_id
Visitor&& visitor = empty_visitor()) {
void breadth_first_search(G&& g, // graph
const vertex_id_t<G>& source, // starting vertex_id
Visitor&& visitor = empty_visitor()) {
// Wrap single source in array and delegate to multi-source version
std::array<vertex_id_t<G>, 1> sources{source};
breadth_first_search(std::forward<G>(g), sources, std::forward<Visitor>(visitor));
Expand Down
4 changes: 2 additions & 2 deletions include/graph/algorithm/connected_components.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ void kosaraju(G&& g, // graph

// Helper: iterative DFS to compute finish times (post-order)
// This creates reverse topological ordering for SCC discovery
auto dfs_finish_order = [&](vertex_id_t<G> start) {
auto dfs_finish_order = [&](const vertex_id_t<G>& start) {
std::stack<std::pair<vertex_id_t<G>, bool>> stack; // (vertex, children_visited)
stack.push({start, false});
visited[start] = true;
Expand Down Expand Up @@ -280,7 +280,7 @@ void kosaraju(G&& g, // bidirectional graph
auto& g_ref = g;

// First pass: iterative DFS to compute finish times (same as two-graph version)
auto dfs_finish_order = [&](vertex_id_t<G> start) {
auto dfs_finish_order = [&](const vertex_id_t<G>& start) {
std::stack<std::pair<vertex_id_t<G>, bool>> stack;
stack.push({start, false});
visited[start] = true;
Expand Down
Loading
Loading