1#ifndef GRAPHLIB_INTERNAL_ABSTRACT_GRAPH_H
2#define GRAPHLIB_INTERNAL_ABSTRACT_GRAPH_H
11#include <unordered_map>
36namespace GraphLib::Internal {
38template <val
id_data_type D, val
id_
id_type I, val
id_edge_type<I> E>
56template <val
id_data_type D, val
id_
id_type I, val
id_edge_type<I> E>
103 return data_map_.size() == std::numeric_limits<id_type>::max();
163 throw std::invalid_argument(
"Node does not exist");
176 return adj_list_.get_neighboring_node_ids(
id);
188 return adj_list_.has_edge(from_id, to_id);
204 throw std::invalid_argument(
"Edge does not exist");
206 return adj_list_.get_edge(from_id, to_id);
227 std::cout <<
"data_map_: \n";
229 std::cout << i.first <<
" : " << i.second <<
"\n";
231 std::cout <<
"---\n";
241 std::cout << *
this <<
"\n";
255 throw std::invalid_argument(
"The Data is not printable");
269 std::vector<id_type> nodes;
271 nodes.push_back(pair.first);
275 std::cout <<
"Dimension: " << dim <<
"\n";
276 std::cout <<
"Nodes: ";
277 for (
auto& node : nodes) {
278 std::cout << node <<
" ";
284 std::cout <<
"Adjacency Matrix: \n | ";
285 for (
auto& node : nodes) {
286 std::cout << node <<
" ";
289 for (
size_t idx {}; idx < dim; idx++) {
295 for (
auto& base_node : nodes) {
296 std::cout << base_node <<
" | ";
297 for (
auto& node : nodes) {
298 if (
adj_list_.has_edge(base_node, node)) {
300 std::cout <<
adj_list_.get_edge(base_node, node).weight;
307 std::cout <<
"\n |\n";
330 throw std::overflow_error(
"The Graph is full, no new nodes can be added");
346 const auto [it, inserted] =
data_map_.insert({id, data});
348 throw std::runtime_error(
"Insertion failed: key might already exist");
353 std::cout <<
"Graph is FULL now. We can't add a new node\n";
384 throw std::overflow_error(
"The Graph is full, no new nodes can be added");
386 throw std::runtime_error(
"Cannot insert: the given ID already exists");
388 const auto [it, inserted] =
data_map_.insert({id, data});
390 throw std::runtime_error(
"Insertion failed");
418 throw std::invalid_argument(
"Node with this ID does not exist");
435 throw std::invalid_argument(
"Node does not exist");
486 throw std::invalid_argument(
"Node with origin ID does not exist");
489 throw std::invalid_argument(
"Node with target ID to_id does not exist");
491 if (
adj_list_.has_edge(from_id, edge.node_id)) {
492 throw std::invalid_argument(
"An edge from origin ID to target ID already exists");
498 auto reverse_edge = edge;
499 reverse_edge.node_id = from_id;
500 adj_list_.add_edge(edge.node_id, reverse_edge);
526template <val
id_data_type D, val
id_
id_type I, val
id_edge_type<I> E>
std::ostream & operator<<(std::ostream &os, const Graph< D, I, E > &graph)
Stream insertion operator for any valid graph type.
Generic adjacency list implementation for directed graphs.
Represents a directed (by nature) Adjacency List Graph Structure.
Abstract base class for a generic graph structure.
bool is_full()
Checks if the graph has reached the maximum number of nodes.
const data_type & get_node_data(const id_type id) const
Access the data associated with a node by its ID.
const std::set< id_type > get_neighbors(const id_type id) const
Get neighbors (adjacent node IDs) of a given node.
virtual void add_edge_impl(const id_type from_id, const edge_type edge)
Helper to add an edge including reverse edge if undirected.
std::unordered_map< id_type, data_type > data_map_
Maps node IDs to node data.
virtual bool is_directed() const =0
Check if the graph is directed.
D data_type
Alias for the data type of nodes.
virtual void add_edge(const id_type from_id, const id_type to_id)=0
Add an edge from one node to another.
virtual bool is_weighted() const =0
Check if the graph edges are weighted.
friend std::ostream & operator(std::ostream &os, const Graph< data_type, id_type, edge_type > &graph)
friend for outputting to a std::ostream.
edge_type get_edge(const id_type from_id, const id_type to_id) const
Retrieve the edge information between two nodes.
size_t edge_count() const
Get the number of edges in the graph.
bool node_exists(const id_type id) const
Check if a node with the specified ID exists.
id_type add_node()
Add a new node with default data.
I id_type
Alias for the node ID type.
E edge_type
Alias for the edge type.
bool has_edge(const id_type from_id, const id_type to_id) const
Check if an edge exists between two nodes.
void add_node_with_id(const id_type id, const data_type data)
Insert a new node with a specified ID and associated data.
AdjacencyList< id_type, edge_type > adj_list_
Stores edges as adjacency list.
void print_adjacency_matrix() const
Prints the adjacency matrix of the graph.
void remove_node(const id_type id)
Remove a node by ID.
void print_with_data(std::ostream &os) const
Outputs the graph as an adjacency list to the given stream but with its data.
virtual ~Graph()=default
Virtual destructor for safe polymorphic use.
std::unordered_set< id_type > get_nodes() const
Retrieve the set of all node IDs in the graph.
id_type add_node(const data_type data)
Add a new node with the given data.
id_type node_count() const
Get the number of nodes in the graph.
void add_node_with_id(const id_type id)
Insert a new node with a specified ID.
void set_node_data(const id_type id, const data_type data)
Update the data of a node.
virtual void remove_edge(const id_type from_id, const id_type to_id)=0
Remove an edge from one node to another.
std::set< edge_type > get_edges(const id_type from_id) const
Get all edges originating from a given node.
std::queue< id_type > reusable_ids_
Queue of reusable node IDs freed from removed nodes.
void print_data_map() const
Prints the contents of the data_map_ to standard output.
id_type highest_id_
IDs start at 1 to avoid off-by-one errors when giving node count.
constexpr bool operator==(const Graph &other) const
Equality comparison between graphs.
void print_adjacency_list() const
Outputs the graph as an adjacency list to the given stream.
Checks whether a type supports streaming to std::ostream.
Checks whether a type is an aggregate and derived from WeightedEdge<I, W>.
Defines C++20 concepts used for type constraints in the GraphLib library.