diff --git a/docs/user-guide/adjacency-lists.md b/docs/user-guide/adjacency-lists.md index 3ae9062..466a648 100644 --- a/docs/user-guide/adjacency-lists.md +++ b/docs/user-guide/adjacency-lists.md @@ -256,7 +256,7 @@ Extracts the per-vertex value type from a property map container: // Works with any adjacency_list graph — index or mapped auto distances = make_vertex_property_map(g, - shortest_path_infinite_distance()); + infinite_distance()); auto predecessors = make_vertex_property_map>(g, vertex_id_t{}); diff --git a/docs/user-guide/algorithms.md b/docs/user-guide/algorithms.md index ac81eaf..35e19e4 100644 --- a/docs/user-guide/algorithms.md +++ b/docs/user-guide/algorithms.md @@ -73,7 +73,7 @@ dijkstra_shortest_paths(g, 0, distance, predecessor, // Map-based graph: use vertex property maps using G = /* some mapped_adjacency_list graph */; -auto distances = make_vertex_property_map(g, shortest_path_infinite_distance()); +auto distances = make_vertex_property_map(g, infinite_distance()); auto predecessors = make_vertex_property_map>(g, vertex_id_t{}); for (auto&& [uid, u] : views::vertexlist(g)) predecessors[uid] = uid; @@ -299,8 +299,8 @@ All shortest-path algorithms share utilities from `traversal_common.hpp`: |---------|---------| | `init_shortest_paths(distances)` | Set all distances to infinity | | `init_shortest_paths(distances, predecessors)` | Set distances to infinity, predecessors to self | -| `shortest_path_infinite_distance()` | Returns the "infinity" sentinel for type `T` | -| `shortest_path_zero()` | Returns the additive identity for type `T` | +| `infinite_distance()` | Returns the "infinity" sentinel for type `T` | +| `zero_distance()` | Returns the additive identity for type `T` | ### Visitors diff --git a/docs/user-guide/algorithms/bellman_ford.md b/docs/user-guide/algorithms/bellman_ford.md index 5bc8238..7ee0d65 100644 --- a/docs/user-guide/algorithms/bellman_ford.md +++ b/docs/user-guide/algorithms/bellman_ford.md @@ -80,7 +80,7 @@ from the predecessor array. // Multi-source, distances + predecessors [[nodiscard]] constexpr optional> bellman_ford_shortest_paths(G&& g, const Sources& sources, - Distances& distances, Predecessors& predecessors, + DistanceFn&& distance, PredecessorFn&& predecessor, WF&& weight = /* default returns 1 */, Visitor&& visitor = empty_visitor(), Compare&& compare = less<>{}, @@ -89,7 +89,7 @@ bellman_ford_shortest_paths(G&& g, const Sources& sources, // Single-source, distances + predecessors [[nodiscard]] constexpr optional> bellman_ford_shortest_paths(G&& g, const vertex_id_t& source, - Distances& distances, Predecessors& predecessors, + DistanceFn&& distance, PredecessorFn&& predecessor, WF&& weight, Visitor&& visitor = empty_visitor(), Compare&& compare = less<>{}, @@ -98,7 +98,7 @@ bellman_ford_shortest_paths(G&& g, const vertex_id_t& source, // Multi-source, distances only [[nodiscard]] constexpr optional> bellman_ford_shortest_distances(G&& g, const Sources& sources, - Distances& distances, + DistanceFn&& distance, WF&& weight, Visitor&& visitor = empty_visitor(), Compare&& compare = less<>{}, @@ -107,7 +107,7 @@ bellman_ford_shortest_distances(G&& g, const Sources& sources, // Single-source, distances only [[nodiscard]] constexpr optional> bellman_ford_shortest_distances(G&& g, const vertex_id_t& source, - Distances& distances, + DistanceFn&& distance, WF&& weight, Visitor&& visitor = empty_visitor(), Compare&& compare = less<>{}, @@ -125,8 +125,8 @@ void find_negative_cycle(G& g, const Predecessors& predecessor, |-----------|-------------| | `g` | Graph satisfying `adjacency_list` | | `source` / `sources` | Source vertex ID or range of source vertex IDs | -| `distances` | Subscriptable by `vertex_id_t`. For index graphs, a pre-sized `std::vector`; for mapped graphs, use `make_vertex_property_map(g, init)`. Must satisfy `vertex_property_map_for`. | -| `predecessors` | Subscriptable by `vertex_id_t`. For index graphs, a pre-sized `std::vector`; for mapped graphs, use `make_vertex_property_map(g, init)`. Must satisfy `vertex_property_map_for`. | +| `distance` | Callable `(const G&, vertex_id_t) -> Distance&` returning a mutable reference to the per-vertex distance. For containers: wrap with `container_value_fn(dist)`. Must satisfy `distance_fn_for`. | +| `predecessor` | Callable `(const G&, vertex_id_t) -> Predecessor&` returning a mutable reference to the per-vertex predecessor. For containers: wrap with `container_value_fn(pred)`. Must satisfy `predecessor_fn_for`. Use `_null_predecessor` when path reconstruction is not needed. | | `weight` | Callable `WF(g, uv)` returning edge weight (may be negative). Must satisfy `basic_edge_weight_function`. | | `visitor` | Optional visitor struct with callback methods (see below). Default: `empty_visitor{}`. | | `compare` | Comparison function for distance values. Default: `std::less<>{}`. | @@ -176,11 +176,12 @@ each edge satisfies the triangle inequality. - ✅ DAGs (works correctly, though topological-order relaxation is faster) - ⚠️ Negative-weight cycles — detected and reported; distances undefined for affected vertices -**Container Requirements:** +**Property Function Requirements:** - Required: `adjacency_list` -- `distances` must satisfy `vertex_property_map_for` -- `predecessors` must satisfy `vertex_property_map_for` +- `distance` must satisfy `distance_fn_for` +- `predecessor` must satisfy `predecessor_fn_for` - `weight` must satisfy `basic_edge_weight_function` +- Use `container_value_fn(vec)` to adapt a `std::vector` or similar container ## Examples @@ -205,12 +206,13 @@ std::vector pred(num_vertices(g)); init_shortest_paths(dist, pred); -auto cycle = bellman_ford_shortest_paths(g, 0u, dist, pred, +auto cycle = bellman_ford_shortest_paths(g, 0u, container_value_fn(dist), container_value_fn(pred), [](const auto& g, const auto& uv) { return edge_value(g, uv); }); if (!cycle) { // No negative cycle — dist[v] is the shortest distance from source 0 // dist[0] = 0, dist[1] = 6, dist[2] = 7, dist[3] = 2, dist[4] = 4 + // Unreachable vertices retain infinite_distance() } ``` @@ -228,7 +230,7 @@ std::vector pred(num_vertices(g)); init_shortest_paths(dist, pred); -auto cycle = bellman_ford_shortest_paths(g, 0u, dist, pred, +auto cycle = bellman_ford_shortest_paths(g, 0u, container_value_fn(dist), container_value_fn(pred), [](const auto& g, const auto& uv) { return edge_value(g, uv); }); if (cycle) { @@ -245,7 +247,7 @@ if (cycle) { Use `find_negative_cycle` to obtain the full cycle from the predecessor array. ```cpp -auto cycle = bellman_ford_shortest_paths(g, 0u, dist, pred, +auto cycle = bellman_ford_shortest_paths(g, 0u, container_value_fn(dist), container_value_fn(pred), [](const auto& g, const auto& uv) { return edge_value(g, uv); }); if (cycle) { @@ -272,7 +274,7 @@ std::vector pred(num_vertices(g)); init_shortest_paths(dist, pred); std::array sources{0u, 3u}; -auto cycle = bellman_ford_shortest_paths(g, sources, dist, pred, +auto cycle = bellman_ford_shortest_paths(g, sources, container_value_fn(dist), container_value_fn(pred), [](const auto& g, const auto& uv) { return edge_value(g, uv); }); // dist[v] = shortest distance from nearest source to v @@ -287,11 +289,12 @@ When you don't need predecessors (and can't reconstruct paths), use std::vector dist(num_vertices(g)); init_shortest_paths(dist); -auto cycle = bellman_ford_shortest_distances(g, 0u, dist, +auto cycle = bellman_ford_shortest_distances(g, 0u, container_value_fn(dist), [](const auto& g, const auto& uv) { return edge_value(g, uv); }); if (!cycle) { // dist[v] = shortest distance from source 0 to v + // Unreachable vertices retain infinite_distance() // No path reconstruction available (no predecessors) } ``` @@ -320,7 +323,7 @@ struct NegativeCycleInspector { }; NegativeCycleInspector inspector; -auto cycle = bellman_ford_shortest_paths(g, 0u, dist, pred, +auto cycle = bellman_ford_shortest_paths(g, 0u, container_value_fn(dist), container_value_fn(pred), [](const auto& g, const auto& uv) { return edge_value(g, uv); }, inspector); @@ -330,24 +333,24 @@ auto cycle = bellman_ford_shortest_paths(g, 0u, dist, pred, ## Mandates - `G` must satisfy `adjacency_list` -- `Distances` must satisfy `vertex_property_map_for` -- `Predecessors` must satisfy `vertex_property_map_for` +- `DistanceFn` must satisfy `distance_fn_for` +- `PredecessorFn` must satisfy `predecessor_fn_for` (or use `_null_predecessor`) - `WF` must satisfy `basic_edge_weight_function` - All overloads are `[[nodiscard]]` — the compiler warns if the return value is discarded ## Preconditions -- `distances` and `predecessors` must be pre-sized for all vertex IDs in `g` -- Call `init_shortest_paths(distances, predecessors)` before invoking the algorithm +- `distance(g, uid)` must be valid for all vertex IDs in `g` +- Call `init_shortest_paths(dist, pred)` on the underlying containers before invoking the algorithm - All source vertex IDs must be valid vertex IDs in `g` - **Always check the return value** — if a negative cycle exists, distances are undefined for affected vertices ## Effects -- Writes shortest-path distances to `distances[v]` for all reachable vertices +- Writes shortest-path distances via `distance(g, v)` for all reachable vertices (when no negative cycle exists) -- Writes predecessor vertex IDs to `predecessors[v]` for path reconstruction +- Writes predecessor vertex IDs via `predecessor(g, v)` for path reconstruction (`bellman_ford_shortest_paths` only) - Does not modify the graph `g` - Invokes visitor callbacks during relaxation and verification passes diff --git a/docs/user-guide/algorithms/connected_components.md b/docs/user-guide/algorithms/connected_components.md index a36d36a..4120427 100644 --- a/docs/user-guide/algorithms/connected_components.md +++ b/docs/user-guide/algorithms/connected_components.md @@ -77,21 +77,24 @@ vertex v. ### `connected_components` — undirected ```cpp -size_t connected_components(G&& g, Component& component); +size_t connected_components(G&& g, ComponentFn&& component); ``` DFS-based algorithm for undirected graphs. Returns the number of connected -components. Assigns `component[v]` = component ID (0-based). +components. `component(g, uid)` is called with each vertex ID to assign its +component ID (0-based). ### `kosaraju` — strongly connected components ```cpp -void kosaraju(G&& g, GT&& g_transpose, Component& component); +void kosaraju(G&& g, GT&& g_transpose, ComponentFn&& component); + +// Bidirectional overload — no transpose graph needed +void kosaraju(G&& g, ComponentFn&& component); ``` -Kosaraju's two-pass DFS algorithm for directed graphs. Requires both the -original graph `g` and its transpose `g_transpose` (edges reversed). Fills -`component[v]` with the SCC ID. +Kosaraju's two-pass DFS algorithm for directed graphs. Fills +`component(g, uid)` with the SCC ID for each vertex. ### `afforest` — union-find with neighbor sampling @@ -105,19 +108,19 @@ void afforest(G&& g, GT&& g_transpose, Component& component, Union-find-based algorithm with neighbor sampling for large or parallel-friendly workloads. The `neighbor_rounds` parameter controls how many initial sampling rounds are performed before falling back to full edge iteration. Call -`compress(component)` afterwards for canonical (root) component IDs on a -single-machine. +`compress(component)` afterwards for canonical (root) component IDs. -The two-graph variant accepts a transpose `g_transpose` for directed-graph -support. The transpose must also satisfy `adjacency_list`. +> **Note:** `afforest` retains a container-based `Component&` interface (not the +> function-based API) because its internal union-find helpers (`link`, `compress`, +> `sample_frequent_element`) require direct subscript access to the component array. ## Parameters | Parameter | Description | |-----------|-------------| | `g` | Graph satisfying `adjacency_list` | -| `g_transpose` | Transpose graph (for `kosaraju` and `afforest` with transpose). `kosaraju` requires `adjacency_list`; `afforest` requires `adjacency_list`. | -| `component` | Subscriptable by `vertex_id_t`. For index graphs, a pre-sized `std::vector`; for mapped graphs, use `make_vertex_property_map(g, init)`. Must satisfy `vertex_property_map_for`. | +| `g_transpose` | Transpose graph (for `kosaraju` and `afforest` with transpose). Must satisfy `adjacency_list`. | +| `component` | For `connected_components` and `kosaraju`: callable `(const G&, vertex_id_t) -> ComponentID&` returning a mutable reference. For containers: wrap with `container_value_fn(comp)`. Must satisfy `vertex_property_fn_for`. For `afforest`: a subscriptable container (`vector` or `unordered_map`), still using the container API. | | `neighbor_rounds` | Number of neighbor-sampling rounds for `afforest` (default: 2) | **Return value (`connected_components` only):** `size_t` — number of connected @@ -143,7 +146,8 @@ components. `kosaraju` and `afforest` return `void`. **Container Requirements:** - Required: `adjacency_list` -- `component` must satisfy `vertex_property_map_for` +- `component` (`connected_components` and `kosaraju`) must satisfy `vertex_property_fn_for` +- `component` (`afforest`) must satisfy `vertex_property_map_for` - `kosaraju`: transpose graph must also satisfy `adjacency_list` ## Examples @@ -167,7 +171,7 @@ using Graph = container::dynamic_graph comp(num_vertices(g)); -size_t num_cc = connected_components(g, comp); +size_t num_cc = connected_components(g, container_value_fn(comp)); // num_cc == 2 // comp[0] == comp[1] == comp[2] (same component) @@ -188,7 +192,7 @@ Graph g({{0, 1}, {1, 2}, {2, 0}, {2, 3}}); Graph g_t({{1, 0}, {2, 1}, {0, 2}, {3, 2}}); std::vector comp(num_vertices(g)); -kosaraju(g, g_t, comp); +kosaraju(g, g_t, container_value_fn(comp)); // comp[0] == comp[1] == comp[2] (cycle forms an SCC) // comp[3] != comp[0] (3 is its own SCC — not on any cycle) @@ -217,7 +221,7 @@ bidirectional edge pairs. undirected_adjacency_list g({{0, 1, 1}, {1, 2, 1}, {3, 4, 1}}); std::vector comp(num_vertices(g)); -size_t num_cc = connected_components(g, comp); +size_t num_cc = connected_components(g, container_value_fn(comp)); // num_cc == 2 // Same results as vov with bidirectional edges, but simpler construction @@ -270,19 +274,22 @@ compress(comp); ## Mandates - `G` must satisfy `adjacency_list` -- `Component` must satisfy `vertex_property_map_for` +- `connected_components` and `kosaraju`: `ComponentFn` must satisfy `vertex_property_fn_for` +- `afforest`: `Component` must satisfy `vertex_property_map_for` - For `kosaraju`: `GT` must satisfy `adjacency_list` ## Preconditions -- `component` must be pre-sized for all vertex IDs in `g` +- `component(g, uid)` must be valid for all vertex IDs in `g` (`connected_components`, `kosaraju`) +- `component` must be pre-sized for all vertex IDs in `g` (`afforest`) - For `connected_components`: undirected graphs must store both directions of each edge (or use `undirected_adjacency_list`) - For `kosaraju`: the transpose graph must contain all edges reversed ## Effects -- Writes component IDs to `component[v]` for all vertices +- Writes component IDs via `component(g, uid)` for all vertices (`connected_components`, `kosaraju`) +- Writes component IDs to `component[uid]` for all vertices (`afforest`) - Does not modify the graph `g` (or `g_transpose`) - For `afforest`: call `compress(component)` afterwards for canonical root IDs diff --git a/docs/user-guide/algorithms/dijkstra.md b/docs/user-guide/algorithms/dijkstra.md index 2067210..e4db6cc 100644 --- a/docs/user-guide/algorithms/dijkstra.md +++ b/docs/user-guide/algorithms/dijkstra.md @@ -82,7 +82,7 @@ function, an optional visitor, and optional comparator/combiner functors. ```cpp // Multi-source, distances + predecessors constexpr void dijkstra_shortest_paths(G&& g, const Sources& sources, - Distances& distances, Predecessors& predecessors, + DistanceFn&& distance, PredecessorFn&& predecessor, WF&& weight = /* default returns 1 */, Visitor&& visitor = empty_visitor(), Compare&& compare = less<>{}, @@ -90,7 +90,7 @@ constexpr void dijkstra_shortest_paths(G&& g, const Sources& sources, // Single-source, distances + predecessors constexpr void dijkstra_shortest_paths(G&& g, const vertex_id_t& source, - Distances& distances, Predecessors& predecessors, + DistanceFn&& distance, PredecessorFn&& predecessor, WF&& weight = /* default returns 1 */, Visitor&& visitor = empty_visitor(), Compare&& compare = less<>{}, @@ -98,7 +98,7 @@ constexpr void dijkstra_shortest_paths(G&& g, const vertex_id_t& source, // Multi-source, distances only constexpr void dijkstra_shortest_distances(G&& g, const Sources& sources, - Distances& distances, + DistanceFn&& distance, WF&& weight = /* default returns 1 */, Visitor&& visitor = empty_visitor(), Compare&& compare = less<>{}, @@ -106,7 +106,7 @@ constexpr void dijkstra_shortest_distances(G&& g, const Sources& sources, // Single-source, distances only constexpr void dijkstra_shortest_distances(G&& g, const vertex_id_t& source, - Distances& distances, + DistanceFn&& distance, WF&& weight = /* default returns 1 */, Visitor&& visitor = empty_visitor(), Compare&& compare = less<>{}, @@ -119,8 +119,8 @@ constexpr void dijkstra_shortest_distances(G&& g, const vertex_id_t& source, |-----------|-------------| | `g` | Graph satisfying `adjacency_list` | | `source` / `sources` | Source vertex ID or range of source vertex IDs | -| `distances` | Subscriptable by `vertex_id_t`. For index graphs, a pre-sized `std::vector`; for mapped graphs, use `make_vertex_property_map(g, init)`. Must satisfy `vertex_property_map_for`. | -| `predecessors` | Subscriptable by `vertex_id_t`. For index graphs, a pre-sized `std::vector`; for mapped graphs, use `make_vertex_property_map(g, init)`. Must satisfy `vertex_property_map_for`. | +| `distance` | Callable `(const G&, vertex_id_t) -> Distance&` returning a mutable reference to the per-vertex distance. For containers: wrap with `container_value_fn(dist)`. Must satisfy `distance_fn_for`. | +| `predecessor` | Callable `(const G&, vertex_id_t) -> Predecessor&` returning a mutable reference to the per-vertex predecessor. For containers: wrap with `container_value_fn(pred)`. Must satisfy `predecessor_fn_for`. Use `_null_predecessor` when path reconstruction is not needed. | | `weight` | Callable `WF(g, uv)` returning edge weight. Must satisfy `basic_edge_weight_function`. Default: returns `1` for every edge (unweighted). | | `visitor` | Optional visitor struct with callback methods (see below). Default: `empty_visitor{}`. | | `compare` | Comparison function for distance values. Default: `std::less<>{}`. | @@ -160,11 +160,12 @@ need to define the events you care about — missing methods are silently skippe - ✅ Disconnected graphs (unreachable vertices retain infinity distance) - ✅ Empty graphs (no-op) -**Container Requirements:** +**Property Function Requirements:** - Required: `adjacency_list` -- `distances` must satisfy `vertex_property_map_for` -- `predecessors` must satisfy `vertex_property_map_for` +- `distance` must satisfy `distance_fn_for` +- `predecessor` must satisfy `predecessor_fn_for` - `weight` must satisfy `basic_edge_weight_function` +- Use `container_value_fn(vec)` to adapt a `std::vector` or similar container ## Examples @@ -201,7 +202,7 @@ std::vector pred(num_vertices(g)); // Initialize distances to infinity, predecessors to self init_shortest_paths(dist, pred); -dijkstra_shortest_paths(g, 0u, dist, pred, +dijkstra_shortest_paths(g, 0u, container_value_fn(dist), container_value_fn(pred), [](const auto& g, const auto& uv) { return edge_value(g, uv); }); // dist[0] = 0, dist[1] = 8, dist[2] = 5, dist[3] = 6, dist[4] = 2 @@ -217,11 +218,11 @@ When you only need distances and don't need to reconstruct paths, use std::vector dist(num_vertices(g)); init_shortest_paths(dist); // one-argument form: distances only -dijkstra_shortest_distances(g, 0u, dist, +dijkstra_shortest_distances(g, 0u, container_value_fn(dist), [](const auto& g, const auto& uv) { return edge_value(g, uv); }); // dist[v] = shortest distance from source 0 to v -// Unreachable vertices remain at numeric_limits::max() +// Unreachable vertices remain at infinite_distance() ``` ### Example 3: Multi-Source Shortest Paths @@ -237,7 +238,7 @@ init_shortest_paths(dist, pred); // Sources can be any range: vector, array, initializer_list std::array sources{0u, 2u}; -dijkstra_shortest_paths(g, sources, dist, pred, +dijkstra_shortest_paths(g, sources, container_value_fn(dist), container_value_fn(pred), [](const auto& g, const auto& uv) { return edge_value(g, uv); }); // dist[v] = shortest distance from the nearest source to v @@ -250,12 +251,12 @@ After running `dijkstra_shortest_paths`, reconstruct the shortest path from source to any target by walking the predecessor array backwards. ```cpp -// After running dijkstra_shortest_paths(g, source, dist, pred, weight) ... +// After running dijkstra_shortest_paths(g, source, container_value_fn(dist), container_value_fn(pred), weight) ... unsigned target = 3; unsigned source = 0; -if (dist[target] == std::numeric_limits::max()) { +if (dist[target] == infinite_distance()) { // target is unreachable from source } else { // Build path in reverse @@ -289,7 +290,7 @@ std::vector pred(num_vertices(g)); init_shortest_paths(dist, pred); // No weight function — default returns 1 per edge -dijkstra_shortest_paths(g, 0u, dist, pred); +dijkstra_shortest_paths(g, 0u, container_value_fn(dist), container_value_fn(pred)); // dist[0] = 0, dist[1] = 1, dist[2] = 1, dist[3] = 2, dist[4] = 3 // These are hop counts — same as BFS distances @@ -324,7 +325,7 @@ std::vector pred(num_vertices(g)); init_shortest_paths(dist, pred); RelaxationTracker tracker; -dijkstra_shortest_paths(g, 0u, dist, pred, +dijkstra_shortest_paths(g, 0u, container_value_fn(dist), container_value_fn(pred), [](const auto& g, const auto& uv) { return edge_value(g, uv); }, tracker); @@ -348,8 +349,8 @@ struct IdVisitor { ## Mandates - `G` must satisfy `adjacency_list` -- `Distances` must satisfy `vertex_property_map_for` -- `Predecessors` must satisfy `vertex_property_map_for` +- `DistanceFn` must satisfy `distance_fn_for` +- `PredecessorFn` must satisfy `predecessor_fn_for` (or use `_null_predecessor`) - `WF` must satisfy `basic_edge_weight_function` - Visitor callbacks (if present) must accept appropriate graph and vertex/edge parameters @@ -357,14 +358,14 @@ struct IdVisitor { - All edge weights must be **non-negative**. For signed weight types, a negative weight throws `std::out_of_range` at runtime. -- `distances` and `predecessors` must be pre-sized for all vertex IDs in `g` -- Call `init_shortest_paths(distances, predecessors)` before invoking the algorithm +- `distance(g, uid)` must be valid for all vertex IDs in `g` +- Call `init_shortest_paths(distances, predecessors)` on the underlying containers before invoking the algorithm - All source vertex IDs must be valid vertex IDs in `g` ## Effects -- Writes shortest-path distances to `distances[v]` for all reachable vertices -- Writes predecessor vertex IDs to `predecessors[v]` for path reconstruction +- Writes shortest-path distances via `distance(g, v)` for all reachable vertices +- Writes predecessor vertex IDs via `predecessor(g, v)` for path reconstruction (`dijkstra_shortest_paths` only) - Does not modify the graph `g` - Invokes visitor callbacks in Dijkstra traversal order diff --git a/docs/user-guide/algorithms/label_propagation.md b/docs/user-guide/algorithms/label_propagation.md index c124226..e469339 100644 --- a/docs/user-guide/algorithms/label_propagation.md +++ b/docs/user-guide/algorithms/label_propagation.md @@ -83,13 +83,13 @@ Key behaviors: ```cpp // Basic: all vertices start with labels -void label_propagation(G&& g, Label& label, +void label_propagation(G&& g, LabelFn&& label, Gen&& rng = /* default */, T max_iters = std::numeric_limits::max()); // With empty-label sentinel: unlabeled vertices don't participate -void label_propagation(G&& g, Label& label, - range_value_t