Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion docs/user-guide/algorithms/articulation_points.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ the order is unspecified.
## Signature

```cpp
void articulation_points(G&& g, OutputIterator cut_vertices);
void articulation_points(G&& g, OutputIterator cut_vertices,
const Alloc& alloc = Alloc());
```

## Parameters
Expand All @@ -77,6 +78,7 @@ void articulation_points(G&& g, OutputIterator cut_vertices);
|-----------|-------------|
| `g` | Graph satisfying `adjacency_list` |
| `cut_vertices` | Output iterator receiving vertex IDs of articulation points. Each vertex appears exactly once. |
| `alloc` | Allocator for internal stack storage. Default: `std::allocator<std::byte>{}`. |

## Supported Graph Properties

Expand Down
7 changes: 5 additions & 2 deletions docs/user-guide/algorithms/bfs.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,13 @@ integer-indexed) and map-based (sparse vertex ID) graphs are supported.
```cpp
// Multi-source BFS
void breadth_first_search(G&& g, const Sources& sources,
Visitor&& visitor = empty_visitor());
Visitor&& visitor = empty_visitor(),
const Alloc& alloc = Alloc());

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

## Parameters
Expand All @@ -89,6 +91,7 @@ void breadth_first_search(G&& g, const vertex_id_t<G>& source,
| `g` | Graph satisfying `adjacency_list` |
| `source` / `sources` | Source vertex ID or range of source vertex IDs |
| `visitor` | Optional visitor struct with callback methods (see below). Default: `empty_visitor{}`. |
| `alloc` | Allocator for internal queue storage. Default: `std::allocator<std::byte>{}`. |

## Visitor Events

Expand Down
4 changes: 3 additions & 1 deletion docs/user-guide/algorithms/biconnected_components.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ Key properties of the output:
## Signature

```cpp
void biconnected_components(G&& g, OuterContainer& components);
void biconnected_components(G&& g, OuterContainer& components,
const Alloc& alloc = Alloc());
```

Where `OuterContainer` is typically `std::vector<std::vector<vertex_id_t<G>>>`.
Expand All @@ -86,6 +87,7 @@ Where `OuterContainer` is typically `std::vector<std::vector<vertex_id_t<G>>>`.
|-----------|-------------|
| `g` | Graph satisfying `adjacency_list` |
| `components` | Output container of containers. Each inner container holds vertex IDs in one biconnected component. Cleared and refilled by the algorithm. |
| `alloc` | Allocator for internal stack storage. Default: `std::allocator<std::byte>{}`. |

## Supported Graph Properties

Expand Down
10 changes: 7 additions & 3 deletions docs/user-guide/algorithms/connected_components.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ vertex v.
### `connected_components` — undirected

```cpp
size_t connected_components(G&& g, ComponentFn&& component);
size_t connected_components(G&& g, ComponentFn&& component,
const Alloc& alloc = Alloc());
```

DFS-based algorithm for undirected graphs. Returns the number of connected
Expand All @@ -91,10 +92,12 @@ component ID (0-based).
### `kosaraju` — strongly connected components

```cpp
void kosaraju(G&& g, GT&& g_transpose, ComponentFn&& component);
void kosaraju(G&& g, GT&& g_transpose, ComponentFn&& component,
const Alloc& alloc = Alloc());

// Bidirectional overload — no transpose graph needed
void kosaraju(G&& g, ComponentFn&& component);
void kosaraju(G&& g, ComponentFn&& component,
const Alloc& alloc = Alloc());
```

Kosaraju's two-pass DFS algorithm for directed graphs. Fills
Expand Down Expand Up @@ -126,6 +129,7 @@ rounds are performed before falling back to full edge iteration. Call
| `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<G>) -> ComponentID&` returning a mutable reference. For containers: wrap with `container_value_fn(comp)`. Must satisfy `vertex_property_fn_for<ComponentFn, G>`. 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) |
| `alloc` | Allocator for internal stack storage (`connected_components` and `kosaraju` only). Default: `std::allocator<std::byte>{}`. |

**Return value (`connected_components` only):** `size_t` — number of connected
components. `kosaraju` and `afforest` return `void`.
Expand Down
4 changes: 3 additions & 1 deletion docs/user-guide/algorithms/dfs.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ sorting, strongly connected components, and many other graph analyses.

```cpp
void depth_first_search(G&& g, const vertex_id_t<G>& source,
Visitor&& visitor = empty_visitor());
Visitor&& visitor = empty_visitor(),
const Alloc& alloc = Alloc());
```

## Parameters
Expand All @@ -93,6 +94,7 @@ void depth_first_search(G&& g, const vertex_id_t<G>& source,
| `g` | Graph satisfying `adjacency_list` |
| `source` | Source vertex ID to start DFS from |
| `visitor` | Optional visitor struct with callback methods (see below). Default: `empty_visitor{}`. |
| `alloc` | Allocator for internal stack storage. Default: `std::allocator<std::byte>{}`. |

## Visitor Events

Expand Down
13 changes: 9 additions & 4 deletions docs/user-guide/algorithms/dijkstra.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,31 +86,35 @@ constexpr void dijkstra_shortest_paths(G&& g, const Sources& sources,
WF&& weight = /* default returns 1 */,
Visitor&& visitor = empty_visitor(),
Compare&& compare = less<>{},
Combine&& combine = plus<>{});
Combine&& combine = plus<>{},
const Alloc& alloc = Alloc());

// Single-source, distances + predecessors
constexpr void dijkstra_shortest_paths(G&& g, const vertex_id_t<G>& source,
DistanceFn&& distance, PredecessorFn&& predecessor,
WF&& weight = /* default returns 1 */,
Visitor&& visitor = empty_visitor(),
Compare&& compare = less<>{},
Combine&& combine = plus<>{});
Combine&& combine = plus<>{},
const Alloc& alloc = Alloc());

// Multi-source, distances only
constexpr void dijkstra_shortest_distances(G&& g, const Sources& sources,
DistanceFn&& distance,
WF&& weight = /* default returns 1 */,
Visitor&& visitor = empty_visitor(),
Compare&& compare = less<>{},
Combine&& combine = plus<>{});
Combine&& combine = plus<>{},
const Alloc& alloc = Alloc());

// Single-source, distances only
constexpr void dijkstra_shortest_distances(G&& g, const vertex_id_t<G>& source,
DistanceFn&& distance,
WF&& weight = /* default returns 1 */,
Visitor&& visitor = empty_visitor(),
Compare&& compare = less<>{},
Combine&& combine = plus<>{});
Combine&& combine = plus<>{},
const Alloc& alloc = Alloc());
```

## Parameters
Expand All @@ -125,6 +129,7 @@ constexpr void dijkstra_shortest_distances(G&& g, const vertex_id_t<G>& source,
| `visitor` | Optional visitor struct with callback methods (see below). Default: `empty_visitor{}`. |
| `compare` | Comparison function for distance values. Default: `std::less<>{}`. |
| `combine` | Combine function for distance + weight. Default: `std::plus<>{}`. |
| `alloc` | Allocator for internal priority queue storage. Default: `std::allocator<std::byte>{}`. |

## Visitor Events

Expand Down
17 changes: 12 additions & 5 deletions docs/user-guide/algorithms/mst.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,18 @@ in-place to save memory).

```cpp
// Copy-sort: input edge list is not modified
auto kruskal(EdgeList& edges, OutputIterator tree);
auto kruskal(EdgeList& edges, OutputIterator tree,
const Alloc& alloc = Alloc());

auto kruskal(EdgeList& edges, OutputIterator tree, Compare compare);
auto kruskal(EdgeList& edges, OutputIterator tree, Compare compare,
const Alloc& alloc = Alloc());

// In-place sort: sorts edges in-place for lower memory usage
auto inplace_kruskal(EdgeList& edges, OutputIterator tree);
auto inplace_kruskal(EdgeList& edges, OutputIterator tree,
const Alloc& alloc = Alloc());

auto inplace_kruskal(EdgeList& edges, OutputIterator tree, Compare compare);
auto inplace_kruskal(EdgeList& edges, OutputIterator tree, Compare compare,
const Alloc& alloc = Alloc());
```

**Returns** `std::pair<EV, size_t>` — total MST weight and number of connected
Expand All @@ -111,6 +115,7 @@ components.
| `edges` | Range of edge descriptors with `.source_id`, `.target_id`, `.value` |
| `tree` | Output iterator receiving MST edges |
| `compare` | Edge-value comparator. Default: `std::less<>{}`. Use `std::greater<>{}` for max spanning tree. |
| `alloc` | Allocator for internal union-find storage (`inplace_kruskal`) or edge copy + union-find (`kruskal`). Default: `std::allocator<std::byte>{}`. |

## Prim's Algorithm

Expand All @@ -125,7 +130,8 @@ auto prim(G&& g,
const vertex_id_t<G>& seed,
WeightFn&& weight, PredecessorFn&& predecessor,
WF weight_fn = edge_value(g, uv),
Compare compare = std::less<>{});
Compare compare = std::less<>{},
const Alloc& alloc = Alloc());
```

**Returns** the total MST weight.
Expand All @@ -140,6 +146,7 @@ auto prim(G&& g,
| `predecessor` | Callable `(const G&, vertex_id_t<G>) -> P&` returning a mutable reference to the per-vertex predecessor. For containers: wrap with `container_value_fn(pred)`. Must satisfy `predecessor_fn_for<PredecessorFn, G>`. |
| `weight_fn` | Callable `WF(g, uv)` returning edge weight. Default: `edge_value(g, uv)`. |
| `compare` | Comparator for weight values (default: `std::less<>{}`) |
| `alloc` | Allocator for internal priority queue storage. Default: `std::allocator<std::byte>{}`. |

## Edge Descriptor

Expand Down
4 changes: 3 additions & 1 deletion docs/user-guide/algorithms/tarjan_scc.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ only **one DFS pass**, making it simpler to use when a transpose is unavailable.
## Algorithm

```cpp
size_t tarjan_scc(G&& g, ComponentFn&& component);
size_t tarjan_scc(G&& g, ComponentFn&& component,
const Alloc& alloc = Alloc());
```

Single-pass iterative DFS using low-link values. Fills `component(g, uid)` with
Expand All @@ -70,6 +71,7 @@ the SCC ID for each vertex and returns the total number of SCCs.
|-----------|-------------|
| `g` | Graph satisfying `adjacency_list` |
| `component` | Callable `(const G&, vertex_id_t<G>) -> ComponentID&` returning a mutable reference. For containers: wrap with `container_value_fn(comp)`. Must satisfy `vertex_property_fn_for<ComponentFn, G>`. |
| `alloc` | Allocator for internal stack storage. Default: `std::allocator<std::byte>{}`. |

**Return value:** `size_t` — number of strongly connected components.

Expand Down
10 changes: 7 additions & 3 deletions docs/user-guide/algorithms/topological_sort.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,16 @@ Three overloads cover different use cases:

```cpp
// Full-graph topological sort
bool topological_sort(const G& g, OutputIterator result);
bool topological_sort(const G& g, OutputIterator result,
const Alloc& alloc = Alloc());

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

// Multi-source topological sort
bool topological_sort(const G& g, const Sources& sources, OutputIterator result);
bool topological_sort(const G& g, const Sources& sources, OutputIterator result,
const Alloc& alloc = Alloc());
```

> **Note:** Topological sort takes `const G&` (not a forwarding reference), unlike
Expand All @@ -102,6 +105,7 @@ bool topological_sort(const G& g, const Sources& sources, OutputIterator result)
| `g` | Graph satisfying `adjacency_list` (taken by `const&`) |
| `source` / `sources` | Source vertex ID or range of source vertex IDs |
| `result` | Output iterator receiving vertex IDs in topological order |
| `alloc` | Allocator for internal stack storage. Default: `std::allocator<std::byte>{}`. |

**Return value:** `true` if the graph is a DAG (valid ordering produced),
`false` if a cycle was detected.
Expand Down
9 changes: 6 additions & 3 deletions include/graph/algorithm/articulation_points.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ using adj_list::find_vertex;
*
* @tparam G The graph type. Must satisfy adjacency_list concept.
* @tparam Iter The output iterator type. Must be output_iterator<vertex_id_t<G>>.
* @tparam Alloc Allocator type for internal DFS stack storage. Defaults to std::allocator<std::byte>.
*
* @param g The graph. Callers must supply both directions of each undirected edge.
* @param cut_vertices The output iterator where articulation point vertex IDs will be written.
* @param alloc Allocator instance used for the internal DFS stack (default: Alloc())
*
* @return void. Articulation point IDs are written to the output iterator.
*
Expand Down Expand Up @@ -115,9 +117,9 @@ using adj_list::find_vertex;
* // result contains {1, 2} (in some order)
* ```
*/
template <adjacency_list G, class Iter>
template <adjacency_list G, class Iter, class Alloc = std::allocator<std::byte>>
requires std::output_iterator<Iter, vertex_id_t<G>>
void articulation_points(G&& g, Iter cut_vertices) {
void articulation_points(G&& g, Iter cut_vertices, const Alloc& alloc = Alloc()) {
using vid_t = vertex_id_t<G>;

const size_t N = num_vertices(g);
Expand Down Expand Up @@ -154,7 +156,8 @@ void articulation_points(G&& g, Iter cut_vertices) {
bool parent_edge_skipped;
};

std::stack<dfs_frame> stk;
using FrameAlloc = typename std::allocator_traits<Alloc>::template rebind_alloc<dfs_frame>;
std::stack<dfs_frame, std::deque<dfs_frame, FrameAlloc>> stk{std::deque<dfs_frame, FrameAlloc>(FrameAlloc(alloc))};

// Outer loop: handle disconnected graphs
for (auto [start] : views::basic_vertexlist(g)) {
Expand Down
14 changes: 10 additions & 4 deletions include/graph/algorithm/biconnected_components.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,17 @@ using adj_list::find_vertex;
* @tparam G The graph type. Must satisfy adjacency_list concept.
* @tparam OuterContainer A container of containers for the output components.
* Typically std::vector<std::vector<vertex_id_t<G>>>.
* @tparam Alloc Allocator type for internal edge stack and DFS stack storage.
* Defaults to std::allocator<std::byte>.
*
* @param g The graph to process. Callers must supply both directions of each
* undirected edge.
* @param components [out] Output container; one inner container is push_back'd per biconnected
* component found. Articulation-point vertices appear in multiple inner
* containers. No ordering guarantee on the order of components or vertex
* IDs within a component.
* @param alloc Allocator instance used for the internal edge stack and DFS stack
* (default: Alloc())
*
* @return void. Results are stored in the components output parameter.
*
Expand Down Expand Up @@ -141,8 +145,8 @@ using adj_list::find_vertex;
* }
* ```
*/
template <adjacency_list G, class OuterContainer>
void biconnected_components(G&& g, OuterContainer& components) {
template <adjacency_list G, class OuterContainer, class Alloc = std::allocator<std::byte>>
void biconnected_components(G&& g, OuterContainer& components, const Alloc& alloc = Alloc()) {
using vid_t = vertex_id_t<G>;
using inner_type = typename OuterContainer::value_type;

Expand All @@ -163,7 +167,8 @@ void biconnected_components(G&& g, OuterContainer& components) {
// When a biconnected component boundary is detected, edges are popped to
// extract the vertex set of that component.
using edge_pair = std::pair<vid_t, vid_t>;
std::stack<edge_pair> edge_stk;
using EdgePairAlloc = typename std::allocator_traits<Alloc>::template rebind_alloc<edge_pair>;
std::stack<edge_pair, std::deque<edge_pair, EdgePairAlloc>> edge_stk{std::deque<edge_pair, EdgePairAlloc>(EdgePairAlloc(alloc))};

// Deduce the iterator type for edge ranges returned by edges(g, uid).
// edge_descriptor_view iterators store the underlying edge_storage (an
Expand All @@ -182,7 +187,8 @@ void biconnected_components(G&& g, OuterContainer& components) {
bool parent_edge_skipped;
};

std::stack<dfs_frame> stk;
using FrameAlloc = typename std::allocator_traits<Alloc>::template rebind_alloc<dfs_frame>;
std::stack<dfs_frame, std::deque<dfs_frame, FrameAlloc>> stk{std::deque<dfs_frame, FrameAlloc>(FrameAlloc(alloc))};

// Helper: pop edges from edge_stk until (u, v) is popped (inclusive).
// Collect unique vertex IDs and push_back as a new component.
Expand Down
Loading
Loading