Skip to content

Commit e838684

Browse files
authored
YT-CPPHGL-24: Prepare the HGL module documentation
- Added documentation comments to the public API elements of the HGL module - Prepared the tutorial pages and images for the HGL module's documentation - Extended the groups.dox file with HGL module's group definitions - Moved the hypergraph property algorithms to a dedicated file: `hgl/algorithm/properties.hpp" - Aligned the implementation of the undirected hypergraph projection to properly handle single-vertex hyperedges (convert them into self-loops)
1 parent d2f4b51 commit e838684

85 files changed

Lines changed: 6077 additions & 982 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/config/groups.dox

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@
4444

4545
/// @defgroup GL-IO I/O Utility
4646
/// @ingroup GL
47-
/// @brief Comprehensive I/O stream support, parsing algorithms, and range-based formatting.
47+
/// @brief I/O stream operations, formatting, and serialization of graph data.
4848
///
4949
/// This group provides the necessary infrastructure to seamlessly serialize, deserialize, and
50-
/// visualize complex graph structures. By offering a robust set of stream manipulators, formatting
51-
/// traits, and configuration options, it allows users to easily translate in-memory graphs to
52-
/// and from standard streams, files, or custom string representations.
50+
/// visualize complex graph structures. By offering a robust set of stream manipulators, range
51+
/// formatting utilities, and configuration options, it allows users to easily translate
52+
/// in-memory graphs to and from standard streams, files, or custom string representations.
5353

5454
/// @defgroup GL-Traits Traits & Concepts
5555
/// @ingroup GL
@@ -83,3 +83,78 @@
8383
/// operations, these utilities are completely independent of graph theory semantics. They provide
8484
/// a curated set of highly reusable, general-purpose tools that can smoothly integrate into any
8585
/// modern C++ codebase.
86+
87+
/// @defgroup HGL Hypergraph Library (HGL)
88+
/// @brief The top-level module defining the general-purpose C++ template hypergraph library.
89+
///
90+
/// This module provides a comprehensive suite of memory-efficient hypergraph representations,
91+
/// highly customizable algorithms, and robust I/O facilities. Designed strictly around modern
92+
/// C++ paradigms, the library leverages templates and concepts to deliver an API that is fast,
93+
/// generic, and type-safe. It supports both undirected hypergraphs and backward-forward (bf)
94+
/// directed hypergraphs.
95+
96+
/// @defgroup HGL-Core Core Hypergraph Components
97+
/// @ingroup HGL
98+
/// @brief Fundamental hypergraph data structures, element descriptors, and configuration tags.
99+
///
100+
/// This group establishes the primary user interface for the HGL module, centered around the highly
101+
/// configurable @ref hgl::hypergraph "hypergraph" class. It provides the core data types, such as vertex
102+
/// and hyperedge descriptors, required to safely navigate and manipulate graph elements.
103+
///
104+
/// Furthermore, this module defines the declarative tags (e.g., directedness and backend
105+
/// implementation types) that dictate both the behavioral semantics and the underlying memory
106+
/// layout of the instantiated hypergraphs.
107+
108+
/// @defgroup HGL-Algorithm Hypergraph Algorithms
109+
/// @ingroup HGL
110+
/// @brief Generic hypergraph algorithms, search templates, and related utilities.
111+
///
112+
/// This module provides hypergraph-specific algorithmic templates and implementations
113+
/// (such as forward and backward searches) designed to natively navigate the complex,
114+
/// high-order structure of hyperedges.
115+
116+
/// @defgroup HGL-IO I/O Utility
117+
/// @ingroup HGL
118+
/// @brief I/O stream operations, formatting, and serialization of hypergraph data.
119+
///
120+
/// Provides the necessary infrastructure to seamlessly serialize, deserialize, and visualize
121+
/// complex hypergraph structures. It utilizes shared stream manipulation options and range
122+
/// formatting utilities to easily translate in-memory hypergraphs to and from standard
123+
/// streams and files.
124+
125+
/// @defgroup HGL-Traits Traits & Concepts
126+
/// @ingroup HGL
127+
/// @brief Type traits, template constraints, and compile-time metaprogramming utilities.
128+
///
129+
/// These components form the strict conceptual backbone of the HGL module, used extensively
130+
/// to ensure internal type safety and correctness, while also constraining user-defined types
131+
/// to required structural contracts.
132+
///
133+
/// @section concepts_link Detailed Concept Specifications
134+
/// For a detailed list of all HGL module's concepts and their formal requirements, please refer to
135+
/// the [HGL Concepts Documentation](hgl_concepts.md#hgl-concepts-documentation) page.
136+
///
137+
/// > [!NOTE]
138+
/// >
139+
/// > Because hypergraphs share the same underlying implementation design and mechanisms as standard
140+
/// > graphs, they seamlessly reuse the same fundamental C++20 concepts. Therefore the HGL module
141+
/// > pulls in all standard graph traits, concept checkers, and metaprogramming utilities from the
142+
/// > GL module. To get an overview of these traits and concepts, please refer to the GL module's
143+
/// > @ref GL-Traits documentation page.
144+
145+
/// @defgroup HGL-Types Generic Types
146+
/// @ingroup HGL
147+
/// @brief Independent, high-performance data structures and utility types.
148+
///
149+
/// This module houses a variety of general-purpose data structures and types. Though they are
150+
/// utilized natively by hypergraph implementations, these components are carefully decoupled
151+
/// from specific hypergraph logic, they can be seamlessly extracted and utilized in broader
152+
/// contexts.
153+
154+
/// @defgroup HGL-Util General Utilities
155+
/// @ingroup HGL
156+
/// @brief Practical, domain-agnostic C++ helpers, mathematical functions, and polyfills.
157+
///
158+
/// These utilities provide a curated set of general-purpose tools that support the
159+
/// library's internal algorithms and hypergraph modeling operations, completely
160+
/// independent of strict hypergraph theory semantics.

docs/gl/algorithms/overview.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ The CPP-GL algorithms module is designed with a strict architectural separation
44

55
This separation ensures maximum code reuse, provides strict zero-cost abstractions, and allows power users to inject highly customized logic directly into the traversal control flow.
66

7+
---
8+
79
## The Architectural Separation
810

911
### 1. The Generic Templates (Engines)
@@ -19,13 +21,15 @@ The core generic templates include:
1921

2022
### 2. The Concrete Algorithms
2123

22-
Concrete algorithms (like `dijkstra_shortest_paths`, `topological_sort`, or `breadth_first_search`) are essentially lightweight wrappers around the generic engines. They are responsible for:
24+
Concrete algorithms (like `dijkstra_shortest_paths`, `topological_sort`, or `breadth_first_search`) are essentially simple wrappers around the generic engines. They are responsible for:
2325
- Allocating and managing memory for algorithm state tracking (e.g., `std::vector<bool> visited` arrays, distance maps).
2426
- Defining the specific logic inside the lambda callbacks and predicates.
2527
- Managing the final return types and structures.
2628

2729
By separating these layers, CPP-GL guarantees that all algorithms inherently benefit from the exact same optimized design and element management.
2830

31+
---
32+
2933
## Core Algorithm Elements
3034

3135
To interact with the generic templates or understand the concrete algorithms, you must be familiar with a few foundational types and tags used uniformly across the library.
@@ -63,7 +67,9 @@ CPP-GL manages this via the [**gl::algorithm::result_discriminator**](../../cpp-
6367
- `ret`: The algorithm will allocate memory and return a stateful object (e.g., `predecessors_map<G>`).
6468
- `noret`: The algorithm will execute purely for side-effects and return `void` (or a simple success boolean).
6569

66-
## Available Concrete Algorithms
70+
---
71+
72+
## Available Algorithms
6773

6874
Explore the specific layers of the algorithm module below:
6975

docs/gl/algorithms/pathfinding.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ std::cout << "Path: "
6666
> [!INFO] Algorithmic Complexity
6767
>
6868
> The time complexity depends heavily on the underlying representation of GraphType and the priority queue overhead:
69-
> - **Adjacency List Representations:** $\mathcal{O}((|V| + |E|) \log |V|)$. The queue operations scale with the number of edges, making this optimal for sparse graphs.
70-
> - **Adjacency Matrix Representations:** $\mathcal{O}(|V|^2 + |E| \log |V|)$. Iterating over adjacent vertices requires scanning the entire $|V|$-length matrix row, shifting the bottleneck to row traversal.
69+
> - **Adjacency List Representations:** $O((|V| + |E|) \log |V|)$. The queue operations scale with the number of edges, making this optimal for sparse graphs.
70+
> - **Adjacency Matrix Representations:** $O(|V|^2 + |E| \log |V|)$. Iterating over adjacent vertices requires scanning the entire $|V|$-length matrix row, shifting the bottleneck to row traversal.
7171
7272
---
7373

docs/gl/algorithms/templates.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ The library provides four primary traversal engines.
1515

1616
## The Callback Sequence
1717

18-
The true power of the generic templates lies in their callback/predicate hooks. Every iteration of the engine loop rigidly follows a defined sequence. By injecting custom lambdas (or omitting them via the [**empty_callback**](../../cpp-gl/structgl_1_1algorithm_1_1empty__callback.md)), you dictate the algorithm's behavior.
18+
The true power of the generic templates lies in their callback/predicate hooks. Every iteration of the engine loop rigidly follows a defined sequence. By injecting custom callbacks (or omitting them via the [**empty_callback**](../../cpp-gl/structgl_1_1algorithm_1_1empty__callback.md)), you dictate the algorithm's behavior.
1919

2020
### Execution Flowchart
2121

docs/gl/algorithms/topological_algs.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ else {
4848
> [!INFO] Algorithmic Complexity
4949
>
5050
> The time complexity depends on the underlying representation of `GraphType`:
51-
> - **Adjacency List Representations:** $\mathcal{O}(|V| + |E|)$.
52-
> - **Adjacency Matrix Representations:** $\mathcal{O}(|V|^2)$. Iterating over adjacent vertices requires scanning the entire $|V|$-length matrix row.
51+
> - **Adjacency List Representations:** $O(|V| + |E|)$.
52+
> - **Adjacency Matrix Representations:** $O(|V|^2)$. Iterating over adjacent vertices requires scanning the entire $|V|$-length matrix row.
5353
5454
---
5555

@@ -87,5 +87,5 @@ else {
8787
> [!INFO] Algorithmic Complexity
8888
>
8989
> The time complexity depends on the underlying representation of `GraphType`:
90-
> - **Adjacency List Representations:** $\mathcal{O}(|V| + |E|)$.
91-
> - **Adjacency Matrix Representations:** $\mathcal{O}(|V|^2)$. Iterating over adjacent vertices requires scanning the entire $|V|$-length matrix row.
90+
> - **Adjacency List Representations:** $O(|V| + |E|)$.
91+
> - **Adjacency Matrix Representations:** $O(|V|^2)$. Iterating over adjacent vertices requires scanning the entire $|V|$-length matrix row.

docs/gl/algorithms/traversal.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ gl::algorithm::breadth_first_search<gl::algorithm::noret>( // (2)!
5151
3. Traverses all vertices in the graph, automatically jumping to new roots if disconnected components are found.
5252
4. A custom PreVisitCallback executed exactly when a vertex is marked as visited.
5353
54-
<!-- TODO: Diagram -->
55-
5654
---
5755
5856
## Depth-First Search (DFS)
@@ -110,6 +108,6 @@ The following diagram illustrates the fundamental difference in exploration orde
110108
111109
The time complexity for all three traversals (BFS, Iterative DFS, and Recursive DFS) depends entirely on the underlying representation of `GraphType`:
112110
113-
- **Adjacency List Representations:** $\mathcal{O}(|V| + |E|)$. The algorithm strictly evaluates existing edges, making this optimal for sparse graphs.
111+
- **Adjacency List Representations:** $O(|V| + |E|)$. The algorithm strictly evaluates existing edges, making this optimal for sparse graphs.
114112
115-
- **Adjacency Matrix Representations:** $\mathcal{O}(|V|^2)$. To find adjacent unvisited vertices, the algorithm must scan the entire $|V|$-length matrix row for every visited vertex, shifting the bottleneck from edge evaluation to row traversal.
113+
- **Adjacency Matrix Representations:** $O(|V|^2)$. To find adjacent unvisited vertices, the algorithm must scan the entire $|V|$-length matrix row for every visited vertex, shifting the bottleneck from edge evaluation to row traversal.

docs/gl/architecture.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ The **GL (Graph Library)** module is engineered around a singular philosophy: pr
66

77
This section explores the core architectural decisions of the GL module:
88

9-
- [Core Concepts](#core-concepts): Learn how the gl::graph template operates, the difference between IDs and descriptors, and how to navigate topologies.
9+
- [Core Concepts](#core-concepts): Learn how the `gl::graph` template operates, the difference between IDs and descriptors, and how to navigate topologies.
1010
- [Graph Representation Models](#graph-representation-models): Understand the diverse memory models available and their performance characteristics.
1111
- [Properties & Custom Data](#properties-custom-data): Discover how to inject arbitrary data directly into your graph elements with strict type safety.
1212

@@ -82,7 +82,7 @@ When you add new vertices or edges to the graph, the library guarantees that exi
8282
>
8383
> Because a property-less vertex descriptor is essentially just a wrapper around an ID, there is zero overhead to using it instead of a raw ID, and it will never invalidate when new elements are added.
8484
>
85-
> This means that performing operations like the following is completely safe:
85+
> This means that performing operations like the following are completely safe:
8686
> ```cpp
8787
> const auto v1 = graph.add_vertex();
8888
> const auto v2 = graph.add_vertex();
@@ -232,7 +232,7 @@ By keeping all vertex and edge data in adjacent memory blocks, these models prov
232232
>
233233
> While the flat adjacency list model is highly efficient for graph storage and traversal, it is highly inefficient to construct element-by-element. The most efficient approach for utilizing flat list graphs is to construct your graph using the standard list model first, and then convert it into the flat list model using the generic [**gl::to**](../cpp-gl/group__GL-Core.md#function-to) conversion function. This exact methodology is utilized internally by the [**graph topology generators**](topologies.md) defined within the library.
234234
235-
### Operation Complexity
235+
### Operation Complexities
236236
237237
Depending on the chosen representation model, the computational complexity of standard graph operations will differ. The table below outlines these complexities.
238238

docs/gl/io.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ int main() {
2121
auto e = g.add_edge(v0, v1);
2222

2323
std::cout << "Vertex: " << v0 << '\n'; // (1)!
24-
std::cout << "Edge: " << e << '\n'; // (2)!
25-
std::cout << "Graph:\n" << g << '\n'; // (3)!
24+
std::cout << "Edge: " << e << '\n'; // (2)!
25+
std::cout << "Graph:\n" << g << '\n'; // (3)!
2626
}
2727
```
2828

@@ -87,12 +87,11 @@ int main() {
8787
using graph_type = gl::directed_graph<gl::name_property, gl::name_property>;
8888
auto graph = gl::topology::biclique<graph_type>(2uz, 3uz); // (1)!
8989

90-
std::size_t v_idx = 0uz, e_idx = 0uz;
9190
for (const auto& vertex : graph.vertices()) { // (2)!
92-
vertex->name = std::format("vertex_{}", ++v_idx);
91+
vertex->name = std::format("vertex_{}", vertex.id() + 1);
9392
for (const auto& edge : graph.out_edges(vertex))
9493
if (edge->name.empty())
95-
edge->name = std::format("edge_{}", ++e_idx);
94+
edge->name = std::format("edge_{}", edge.id() + 1);
9695
}
9796

9897
std::cout << graph << std::endl; // (3)!
@@ -170,7 +169,6 @@ For disk storage and network transmission, CPP-GL defines the **Graph Specificat
170169
<edge-list>
171170
```
172171

173-
<!-- TODO: ensure element col wide enough -->
174172
| **Element** | **Description** |
175173
| :----------------- | :-------------- |
176174
| `dir-spec` | `1` if the graph is directed<br/>`0` if the graph is undirected |

docs/gl/quick_start.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ int main() {
4242
return 1;
4343
}
4444

45-
auto path_to_target = gl::algorithm::reconstruct_path(paths.predecessors, target_id); // (7)!
45+
auto path_to_target
46+
= gl::algorithm::reconstruct_path(paths.predecessors, target_id); // (7)!
4647
std::cout << "Shortest path distance to vertex " << target_id << ": "
4748
<< paths.distances[target_id] << "\nPath: "
48-
<< gl::io::range_formatter(path_to_target, " -> ", "", "") << '\n'; // (8)!
49+
<< gl::io::range_formatter(path_to_target, " -> ", "", "") // (8)!
50+
<< '\n';
4951

5052
return 0;
5153
}
@@ -69,6 +71,9 @@ Path: 0 -> 2 -> 3 -> 1 -> 4
6971
### Understanding the Code
7072

7173
- **Traits (`gl::list_graph_traits`):** CPP-GL relies heavily on template abstraction. Instead of passing multiple arguments to the `gl::graph` constructor, you pass a single *Traits* struct as its template parameter. This strictly dictates whether the graph uses an adjacency list or matrix, if it is directed, what custom properties (like `gl::weight_property`) exist on its elements and what id type is used for its elements.
74+
7275
- **Property Access (`->weight`):** Adding an edge returns a descriptor handle. You access the specific payload fields associated with that edge by using the overloaded `->` operator, ensuring highly performant and type-safe data manipulation.
76+
7377
- **Algorithm Separation:** Search engines and algorithms (like `dijkstra_shortest_paths`) exist entirely outside the graph class. They accept the graph as a `const` reference, mathematically guaranteeing that algorithms will never accidentally mutate your topology.
78+
7479
- **Formatting (`gl::io::range_formatter`):** The library includes lightweight utility formatters so you can easily stream sequences, paths, and standard ranges directly to the console with complete control over delimiters and brackets.

0 commit comments

Comments
 (0)