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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ While the `gl::graph` class is the key element of the library, it's not the only
- [The vertex and edge classes - representation of the graph's elements](/docs/graph_elements.md)
- [I/O operations](/docs/io.md)
- [Graph topology generators](/docs/topologies.md)
- [Algorithms](/docs/algoithms.md)
- [Algorithms](/docs/algorithms.md)
- [Core utility types](/docs/core_util_types.md)
- [Additional functionality](/docs/additional_functionality.md)

Expand Down
98 changes: 46 additions & 52 deletions docs/algoithms.md → docs/algorithms.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/graph.md
Original file line number Diff line number Diff line change
Expand Up @@ -551,5 +551,5 @@ This section provides links to additional resources and documentation that can h
- [The vertex and edge classes - representation of the graph's elements](/docs/graph_elements.md)
- [I/O operations](/docs/io.md)
- [Graph topology generators](/docs/topologies.md)
- [Algorithms](/docs/algoithms.md)
- [Algorithms](/docs/algorithms.md)
- [Core utility types](/docs/core_util_types.md)
86 changes: 19 additions & 67 deletions docs/graph_elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,6 @@ By default, the `edge_descriptor` class does not carry any properties and assume

### Template parameters

- **`VertexType`**: The type of the vertex descriptors connected by this edge.
- *Constraints*: must satisfy the **`type_traits::c_instantiation_of<vertex_descriptor>`** concept
- **`DirectionalTag`**: A tag type indicating whether the edge is directed or undirected.
- *Default value*: `directed_t`
- *Constraints*: must satisfy the **`type_traits::c_edge_directional_tag`** concept (either `directed_t` or `undirected_t`)
Expand All @@ -99,15 +97,14 @@ By default, the `edge_descriptor` class does not carry any properties and assume
### Member types

- **`type`**: Alias for the `edge_descriptor` itself.
- **`vertex_type`**: Type of the vertex descriptors connected by this edge.
- **`directional_tag`**: The tag indicating whether the edge is directed or undirected.
- **`properties_type`**: Type of the edge properties as defined by the `Properties` template parameter.

### Constructors

- **`edge_descriptor(const vertex_type& first, const vertex_type& second)`**:
- **`edge_descriptor(const types::id_type first, const types::id_type second)`**:
- Constructs an edge between two vertices.
- **`edge_descriptor(const vertex_type& first, const vertex_type& second, const properties_type& properties)`**:
- **`edge_descriptor(const types::id_type first, const types::id_type second, const properties_type& properties)`**:
- Constructs an edge between two vertices with specified properties.
- *Constraints*: the `properties_type` must be non-default.
- **Move constructor and assignment operator**: *default*
Expand All @@ -133,88 +130,48 @@ The destructor is *defaulted*, allowing proper cleanup of the `edge_descriptor`
- **`incident_vertices() const`**:
- *Description*: Returns a pair of references to the two vertices connected by the edge.
- *Returned value*: $(u, v)$
- *Return type*: `types::homogeneous_pair<const vertex_type&>`

- **`incident_vertex_ids() const`**:
- *Description*: Returns the unique IDs of the vertices connected by the edge.
- *Returned value*: $(u_{id}, v_{id})$
- *Return type*: `types::homogeneous_pair<types::id_type>`
- *Return type*: `types::homogeneous_pair<const types::id_type>`

- **`first() const`**:
- *Description*: Returns a reference to the first vertex of the edge.
- *Returned value*: $u$
- *Return type*: `const vertex_type&`
- *Return type*: `types::id_type`

- **`second() const`**:
- *Description*: Returns a reference to the second vertex of the edge.
- *Returned value*: $v$
- *Return type*: `const vertex_type&`
- *Return type*: `const types::id_type`

- **`incident_vertex(vertex) const`**:
- **`incident_vertex(vertex_id) const`**:
- *Description*: Returns the vertex on the other end of the edge relative to the provided vertex. Throws an error if the provided vertex is not incident with the edge.
- *Returned value*:
- $v$ if $\text{vertex} = u$
- $u$ if $\text{vertex} = v$
- $v$ if $\text{vertex-id} = u$
- $u$ if $\text{vertex-id} = v$
- error otherwise
- *Parameters*:
- `vertex: const vertex_type&` – the vertex for which the opposite vertex is requested.
- *Return type*: `const vertex_type&`

- **`incident_vertex(vertex_id) const`**:
- *Description*: Returns the vertex on the other end of the edge relative to the provided vertex ID. Throws an error if the provided vertex ID is invalid.
- *Returned value*:
- $v$ if $\text{vertex-id} = u_{id}$
- $u$ if $\text{vertex-id} = v_{id}$
- error otherwise
- *Parameters*:
- `vertex_id: const types::id_type` – the vertex ID for which the opposite vertex ID is requested.
- *Return type*: `types::id_type`

- **`is_incident_with(vertex) const`**:
- *Description*: Returns `true` if the provided vertex is connected to the edge.
- *Returned value*: $\text{vertex} \in {u, v}$
- *Parameters*:
- `vertex: const vertex_type&` – the vertex to check for incidence with the edge.
- *Return type*: `bool`
- `vertex_id: const types::id_type` – the vertex for which the opposite vertex is requested.
- *Return type*: `const types::id_type`

- **`is_incident_with(vertex_id) const`**:
- *Description*: Returns `true` if a vertex with the given ID is connected to the edge.
- *Returned value*: $\text{vertex-id} \in {u_{id}, v_{id}}$
- *Returned value*: $\text{vertex-id} \in {u, v}$
- *Parameters*:
- `vertex_id: const types::id_type` – the vertex ID to check for incidence with the edge.
- *Return type*: `bool`

- **`is_incident_from(vertex) const`**:
- *Description*: Returns `true` if the provided vertex is the source of the edge (for directed edges).
- *Returned value*:
- For directed edges: $\text{vertex} = u$
- For undirected edges: `is_incident_with(vertex)`
- *Parameters*:
- `vertex: const vertex_type&` – the vertex to check if it is the source.
- *Return type*: `bool`

- **`is_incident_from(vertex_id) const`**:
- *Description*: Returns `true` if a vertex with the given ID is the source of the edge.
- *Returned value*:
- For directed edges: $\text{vertex-id} = u_{id}$
- For undirected edges: `is_incident_with(vertex)`
- For directed edges: $\text{vertex-id} = u$
- For undirected edges: `is_incident_with(vertex_id)`
- *Parameters*:
- `vertex_id: const types::id_type` – the vertex ID to check if it is the source.
- *Return type*: `bool`

- **`is_incident_to(vertex) const`**:
- *Description*: Returns `true` if the provided vertex is the target vertex of the edge (for directed edges).
- *Returned value*:
- For directed edges: $\text{vertex} = v$
- For undirected edges: `is_incident_with(vertex)`
- *Parameters*:
- `vertex: const vertex_type&` – the vertex to check if it is the target.
- *Return type*: `bool`

- **`is_incident_to(vertex_id) const`**:
- *Description*: Returns `true` if a vertex with the given ID is the target of the edge.
- *Returned value*:
- For directed edges: $\text{vertex-id} = v_{id}$
- For directed edges: $\text{vertex-id} = v$
- For undirected edges: `is_incident_with(vertex)`
- *Parameters*:
- `vertex_id: const types::id_type` – the vertex ID to check if it is the target.
Expand All @@ -231,28 +188,23 @@ The destructor is *defaulted*, allowing proper cleanup of the `edge_descriptor`

```cpp
template <
type_traits::c_instantiation_of<vertex_descriptor> VertexType,
type_traits::c_edge_directional_tag DirectionalTag = directed_t,
type_traits::c_properties Properties = types::empty_properties>
using edge = edge_descriptor<VertexType, DirectionalTag, Properties>;
using edge = edge_descriptor<DirectionalTag, Properties>;
```

- `directed_edge`: An alias for `edge_descriptor` specifically for directed edges.

```cpp
template <
type_traits::c_instantiation_of<vertex_descriptor> VertexType,
type_traits::c_properties Properties = types::empty_properties>
using directed_edge = edge_descriptor<VertexType, directed_t, Properties>;
template <type_traits::c_properties Properties = types::empty_properties>
using directed_edge = edge_descriptor<directed_t, Properties>;
```

- `undirected_edge`: An alias for `edge_descriptor` specifically for undirected edges.

```cpp
template <
type_traits::c_instantiation_of<vertex_descriptor> VertexType,
type_traits::c_properties Properties = types::empty_properties>
using undirected_edge = edge_descriptor<VertexType, undirected_t, Properties>;
template <type_traits::c_properties Properties = types::empty_properties>
using undirected_edge = edge_descriptor<undirected_t, Properties>;
```

<br />
Expand Down
14 changes: 6 additions & 8 deletions include/gl/algorithm/breadth_first_search.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ namespace gl::algorithm {
template <
result_discriminator ResultDiscriminator = algorithm::ret,
type_traits::c_graph GraphType,
type_traits::c_optional_vertex_callback<GraphType, void> PreVisitCallback =
algorithm::empty_callback,
type_traits::c_optional_vertex_callback<GraphType, void> PostVisitCallback =
algorithm::empty_callback>
type_traits::c_optional_id_callback<void> PreVisitCallback = algorithm::empty_callback,
type_traits::c_optional_id_callback<void> PostVisitCallback = algorithm::empty_callback>
impl::alg_return_type<ResultDiscriminator, predecessors_descriptor> breadth_first_search(
const GraphType& graph,
const std::optional<types::id_type>& root_vertex_id_opt = no_root_vertex,
Expand All @@ -35,8 +33,8 @@ impl::alg_return_type<ResultDiscriminator, predecessors_descriptor> breadth_firs
impl::bfs(
graph,
impl::init_range(root_vertex_id_opt.value()),
impl::default_visit_vertex_predicate<GraphType>(visited),
impl::default_visit_callback<GraphType, ResultDiscriminator>(visited, pd),
impl::default_visit_vertex_predicate(visited),
impl::default_visit_callback<ResultDiscriminator>(visited, pd),
impl::default_enqueue_vertex_predicate<GraphType, true>(visited),
pre_visit,
post_visit
Expand All @@ -47,8 +45,8 @@ impl::alg_return_type<ResultDiscriminator, predecessors_descriptor> breadth_firs
impl::bfs(
graph,
impl::init_range(root_id),
impl::default_visit_vertex_predicate<GraphType>(visited),
impl::default_visit_callback<GraphType, ResultDiscriminator>(visited, pd),
impl::default_visit_vertex_predicate(visited),
impl::default_visit_callback<ResultDiscriminator>(visited, pd),
impl::default_enqueue_vertex_predicate<GraphType, true>(visited),
pre_visit,
post_visit
Expand Down
20 changes: 8 additions & 12 deletions include/gl/algorithm/coloring.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ using bicoloring_type = std::vector<types::binary_color>;

template <
type_traits::c_graph GraphType,
type_traits::c_optional_vertex_callback<GraphType, void> PreVisitCallback =
algorithm::empty_callback,
type_traits::c_optional_vertex_callback<GraphType, void> PostVisitCallback =
algorithm::empty_callback>
type_traits::c_optional_id_callback<void> PreVisitCallback = algorithm::empty_callback,
type_traits::c_optional_id_callback<void> PostVisitCallback = algorithm::empty_callback>
[[nodiscard]] std::optional<bicoloring_type> bipartite_coloring(
const GraphType& graph,
const PreVisitCallback& pre_visit = {},
Expand All @@ -28,8 +26,7 @@ template <
coloring_opt.emplace(graph.n_vertices(), bin_color_value::unset);
auto& coloring = coloring_opt.value();

for (const auto root_vertex : graph.vertices()) {
const auto root_id = root_vertex.id();
for (const auto root_id : graph.vertex_ids()) {
if (coloring[root_id].is_set())
continue;

Expand All @@ -41,19 +38,18 @@ template <
impl::init_range(root_id),
algorithm::empty_callback{}, // visit predicate
algorithm::empty_callback{}, // visit callback
[&coloring](const vertex_type& vertex, const edge_type& in_edge)
[&coloring](const types::id_type vertex_id, const edge_type& in_edge)
-> predicate_result { // enqueue predicate
if (in_edge.is_loop())
return false;

const auto vertex_id = vertex.id();
const auto source_id = in_edge.incident_vertex(vertex).id();
const auto pred_id = in_edge.incident_vertex(vertex_id);

if (coloring[vertex_id] == coloring[source_id])
if (coloring[vertex_id] == coloring[pred_id])
return predicate_result::unknown; // graph is not bipartite

if (not coloring[vertex.id()].is_set()) {
coloring[vertex.id()] = coloring[source_id].next();
if (not coloring[vertex_id].is_set()) {
coloring[vertex_id] = coloring[pred_id].next();
return true;
}

Expand Down
42 changes: 19 additions & 23 deletions include/gl/algorithm/depth_first_search.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ namespace gl::algorithm {
template <
result_discriminator ResultDiscriminator = algorithm::ret,
type_traits::c_graph GraphType,
type_traits::c_optional_vertex_callback<GraphType, void> PreVisitCallback =
algorithm::empty_callback,
type_traits::c_optional_vertex_callback<GraphType, void> PostVisitCallback =
algorithm::empty_callback>
type_traits::c_optional_id_callback<void> PreVisitCallback = algorithm::empty_callback,
type_traits::c_optional_id_callback<void> PostVisitCallback = algorithm::empty_callback>
impl::alg_return_type<ResultDiscriminator, predecessors_descriptor> depth_first_search(
const GraphType& graph,
const std::optional<types::id_type>& root_vertex_id_opt = no_root_vertex,
Expand All @@ -33,21 +31,21 @@ impl::alg_return_type<ResultDiscriminator, predecessors_descriptor> depth_first_
if (root_vertex_id_opt) {
impl::dfs(
graph,
graph.get_vertex(root_vertex_id_opt.value()),
impl::default_visit_vertex_predicate<GraphType>(visited),
impl::default_visit_callback<GraphType, ResultDiscriminator>(visited, pd),
root_vertex_id_opt.value(),
impl::default_visit_vertex_predicate(visited),
impl::default_visit_callback<ResultDiscriminator>(visited, pd),
impl::default_enqueue_vertex_predicate<GraphType>(visited),
pre_visit,
post_visit
);
}
else {
for (const auto& root_vertex : graph.vertices())
for (const auto root_vertex_id : graph.vertex_ids())
impl::dfs(
graph,
root_vertex,
impl::default_visit_vertex_predicate<GraphType>(visited),
impl::default_visit_callback<GraphType, ResultDiscriminator>(visited, pd),
root_vertex_id,
impl::default_visit_vertex_predicate(visited),
impl::default_visit_callback<ResultDiscriminator>(visited, pd),
impl::default_enqueue_vertex_predicate<GraphType>(visited),
pre_visit,
post_visit
Expand All @@ -61,10 +59,8 @@ impl::alg_return_type<ResultDiscriminator, predecessors_descriptor> depth_first_
template <
result_discriminator ResultDiscriminator = algorithm::ret,
type_traits::c_graph GraphType,
type_traits::c_optional_vertex_callback<GraphType, void> PreVisitCallback =
algorithm::empty_callback,
type_traits::c_optional_vertex_callback<GraphType, void> PostVisitCallback =
algorithm::empty_callback>
type_traits::c_optional_id_callback<void> PreVisitCallback = algorithm::empty_callback,
type_traits::c_optional_id_callback<void> PostVisitCallback = algorithm::empty_callback>
impl::alg_return_type<ResultDiscriminator, predecessors_descriptor> recursive_depth_first_search(
const GraphType& graph,
const std::optional<types::id_type>& root_vertex_id_opt = no_root_vertex,
Expand All @@ -83,23 +79,23 @@ impl::alg_return_type<ResultDiscriminator, predecessors_descriptor> recursive_de
const auto root_id = root_vertex_id_opt.value();
impl::r_dfs(
graph,
graph.get_vertex(root_id),
root_id,
impl::default_visit_vertex_predicate<GraphType>(visited),
impl::default_visit_callback<GraphType, ResultDiscriminator>(visited, pd),
root_id, // pred_id
impl::default_visit_vertex_predicate(visited),
impl::default_visit_callback<ResultDiscriminator>(visited, pd),
impl::default_enqueue_vertex_predicate<GraphType>(visited),
pre_visit,
post_visit
);
}
else {
for (const auto& root_vertex : graph.vertices())
for (const auto& root_id : graph.vertex_ids())
impl::r_dfs(
graph,
root_vertex,
root_vertex.id(),
impl::default_visit_vertex_predicate<GraphType>(visited),
impl::default_visit_callback<GraphType, ResultDiscriminator>(visited, pd),
root_id,
root_id, // pred_id
impl::default_visit_vertex_predicate(visited),
impl::default_visit_callback<ResultDiscriminator>(visited, pd),
impl::default_enqueue_vertex_predicate<GraphType>(visited),
pre_visit,
post_visit
Expand Down
19 changes: 8 additions & 11 deletions include/gl/algorithm/dijkstra.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,8 @@ template <type_traits::c_graph GraphType>

template <
type_traits::c_graph GraphType,
type_traits::c_optional_vertex_callback<GraphType, void> PreVisitCallback =
algorithm::empty_callback,
type_traits::c_optional_vertex_callback<GraphType, void> PostVisitCallback =
algorithm::empty_callback>
type_traits::c_optional_id_callback<void> PreVisitCallback = algorithm::empty_callback,
type_traits::c_optional_id_callback<void> PostVisitCallback = algorithm::empty_callback>
[[nodiscard]] paths_descriptor_type<GraphType> dijkstra_shortest_paths(
const GraphType& graph,
const types::id_type source_id,
Expand All @@ -94,22 +92,21 @@ template <
impl::init_range(source_id),
algorithm::empty_callback{}, // visit predicate
algorithm::empty_callback{}, // visit callback
[&paths, &negative_edge](const vertex_type& vertex, const edge_type& in_edge)
[&paths, &negative_edge](const types::id_type vertex_id, const edge_type& in_edge)
-> predicate_result { // enqueue predicate
const auto vertex_id = vertex.id();
const auto source_id = in_edge.incident_vertex(vertex).id();
const auto pred_id = in_edge.incident_vertex(vertex_id);

const auto edge_weight = get_weight<GraphType>(in_edge);
if (edge_weight < constants::zero) {
negative_edge = std::cref(in_edge);
return predicate_result::unknown;
}

const auto new_distance = paths.distances[source_id] + edge_weight;
const auto new_distance = paths.distances[pred_id] + edge_weight;
if (not paths.predecessors[vertex_id].has_value()
or new_distance < paths.distances[vertex_id]) {
paths.distances[vertex_id] = new_distance;
paths.predecessors[vertex_id].emplace(source_id);
paths.predecessors[vertex_id].emplace(pred_id);
return true;
}

Expand All @@ -121,8 +118,8 @@ template <
const auto& edge = negative_edge.value().get();
throw std::invalid_argument(std::format(
"[alg::dijkstra_shortest_paths] Found an edge with a negative weight: [{}, {} | w={}]",
edge.first().id(),
edge.second().id(),
edge.first(),
edge.second(),
get_weight<GraphType>(edge)
));
}
Expand Down
Loading