23#include <unordered_map>
24#include <unordered_set>
43template <
typename EdgeT =
void, IDVT IDT = std::
string>
47 using _CN = std::map<IDT, _ET>;
56 template <
typename T = EdgeT>
57 using EdgeT__ =
typename std::conditional<std::is_void_v<T>, int, T>::type;
66 template <
typename T = EdgeT>
67 using EdgeT_R_ =
typename std::conditional<std::is_void_v<T>, int, T>::type&;
76 template <
typename T = EdgeT>
77 using EdgeT_CR_ =
const typename std::conditional<std::is_void_v<T>, int, T>::type&;
109 bool hasEdge(IDT from_id, IDT to_id)
const noexcept;
141 EdgeT
edge(IDT from_id, IDT to_id) const
176 template <typename Ret,
NonFunc Fn, typename... Args>
177 Ret
edge(IDT from_id, IDT to_id, Fn func, Args... args) const
200 template <typename Ret, typename... Args>
201 Ret
edge(IDT from_id, IDT to_id, std::function<Ret(
EdgeT_, Args...)> func, Args... args) const
226 std::vector<std::pair<IDT, IDT>>
edges() const;
263 void insertNode(IDT
id, const std::map<IDT, EdgeT>& map,
bool nodes_exist = false)
286 requires std::is_void_v<EdgeT>;
300 void insertEdge(IDT from_id, IDT to_id,
bool to_exists = false)
301 requires std::is_void_v<EdgeT>;
346 requires
EdgeVT<EdgeT> && std::is_arithmetic_v<EdgeT>;
375 template <typename Ret,
NonFunc Fn, typename... Args>
376 std::pair<Ret, std::vector<IDT>>
maxWeightPath(IDT from_id, IDT to_id, Fn func, Args... args) const
392 template <typename Ret, typename... Args>
393 std::pair<Ret, std::vector<IDT>>
maxWeightPath(IDT from_id, IDT to_id, std::function<Ret(
EdgeT_, Args...)> func,
409 requires
EdgeVT<EdgeT> && std::is_arithmetic_v<EdgeT>;
426 template <typename Ret,
NonFunc Fn, typename... Args>
427 std::pair<Ret, std::vector<IDT>>
minWeightPath(IDT from_id, IDT to_id, Fn func, Args... args) const
443 template <typename Ret, typename... Args>
444 std::pair<Ret, std::vector<IDT>>
minWeightPath(IDT from_id, IDT to_id, std::function<Ret(
EdgeT_, Args...)> func,
461 template <typename Ret, typename... Args>
463 std::function<Ret(
EdgeT_, Args...)> func, Args... args) const
540 EdgeT operator()(IDT from_id, IDT to_id) const
581template <typename EdgeT,
IDVT IDT>
583 return g.contains(
id);
586template <
typename EdgeT, IDVT IDT>
588 auto&& from_n =
g.find(from_id);
589 return from_n !=
g.end() && from_n->second.contains(to_id);
592template <
typename EdgeT, IDVT IDT>
597template <
typename EdgeT, IDVT IDT>
600 for (
auto&& cn :
g) s += cn.second.size();
604template <
typename EdgeT, IDVT IDT>
609template <
typename EdgeT, IDVT IDT>
612 auto&& from_n =
g.find(from_id);
613 if (from_n ==
g.end()) [[unlikely]]
615 auto&& to_n = from_n->second.find(to_id);
616 if (to_n == from_n->second.end()) [[unlikely]]
621template <
typename EdgeT, IDVT IDT>
624 auto&& from_n =
g.find(from_id);
625 if (from_n ==
g.end()) [[unlikely]]
627 auto&& to_n = from_n->second.find(to_id);
628 if (to_n == from_n->second.end()) [[unlikely]]
633template <
typename EdgeT, IDVT IDT>
634template <
typename Ret,
NonFunc Fn,
typename... Args>
637 static_assert(std::is_invocable_r_v<Ret, Fn, DGraphBase<EdgeT, IDT>::EdgeT_, Args...>,
638 "3rd argument (non std::function) must be invocable in method 'edge'.");
639 return func(
edge(from_id, to_id), args...);
642template <
typename EdgeT, IDVT IDT>
643template <
typename Ret,
typename... Args>
647 return func(
edge(from_id, to_id), args...);
650template <
typename EdgeT, IDVT IDT>
653 std::vector<IDT> cn_nodes;
655 for (
auto&& n : cn.second) cn_nodes.push_back(n.first);
656 std::sort(cn_nodes.begin(), cn_nodes.end());
657 cn_nodes.erase(std::unique(cn_nodes.begin(), cn_nodes.end()), cn_nodes.end());
658 return std::includes(nodes.begin(), nodes.end(), cn_nodes.begin(), cn_nodes.end());
661template <
typename EdgeT, IDVT IDT>
663 std::vector<IDT> keys;
664 std::transform(
g.begin(),
g.end(), std::back_inserter(keys), [](
const auto& pair) { return pair.first; });
668template <
typename EdgeT, IDVT IDT>
670 std::vector<std::pair<IDT, IDT>> e;
671 for (
auto&& [from_id, cn] :
g) {
672 for (
auto&&
edge : cn) e.push_back({ from_id,
edge.second });
677template <
typename EdgeT, IDVT IDT>
682template <
typename EdgeT, IDVT IDT>
688 if (
auto&& key = n.first; !
g.contains(key))
g[key] =
_CN();
692template <
typename EdgeT, IDVT IDT>
698template <
typename EdgeT, IDVT IDT>
704template <
typename EdgeT, IDVT IDT>
710template <
typename EdgeT, IDVT IDT>
712 requires std::is_void_v<EdgeT> {
716template <
typename EdgeT, IDVT IDT>
719 g[from_id][to_id] = data;
722template <
typename EdgeT, IDVT IDT>
724 requires std::is_void_v<EdgeT> {
726 if (!to_exists && !
g.contains(to_id))
g[to_id] =
_CN();
729template <
typename EdgeT, IDVT IDT>
734 if (!to_exists && !
g.contains(to_id))
g[to_id] =
_CN();
737template <
typename EdgeT, IDVT IDT>
742 std::unordered_set<IDT> visited;
744 visited.insert(from_id);
751 if (neighbor == to_id)
return true;
752 if (!visited.count(neighbor)) {
753 visited.insert(neighbor);
761template <
typename EdgeT, IDVT IDT>
762inline std::pair<typename DGraphBase<EdgeT, IDT>::EdgeT_, std::vector<IDT>>
765 return maxWeightPath<EdgeT>(from_id, to_id, [](EdgeT e) {
return e; });
768template <
typename EdgeT, IDVT IDT>
769template <
typename Ret,
NonFunc Fn,
typename... Args>
774 static_assert(std::is_invocable_r_v<Ret, Fn,
EdgeT_, Args...>,
775 "3rd argument (non std::function) must be invocable in method 'maxWeightPath'.");
777 return maxWeightPath<Ret>(from_id, to_id, std::function<Ret(
EdgeT_, Args...)>(func), args...);
780template <
typename EdgeT, IDVT IDT>
781template <
typename Ret,
typename... Args>
783 std::function<Ret(
EdgeT_, Args...)> func,
786 return minOrMaxWeightPath<Ret>(
false, from_id, to_id, func, args...);
789template <
typename EdgeT, IDVT IDT>
790inline std::pair<typename DGraphBase<EdgeT, IDT>::EdgeT_, std::vector<IDT>>
793 return minWeightPath<EdgeT>(from_id, to_id, [](EdgeT e) {
return e; });
796template <
typename EdgeT, IDVT IDT>
797template <
typename Ret,
NonFunc Fn,
typename... Args>
802 static_assert(std::is_invocable_r_v<Ret, Fn,
EdgeT_, Args...>,
803 "3rd argument (non std::function) must be invocable in method 'maxWeightPath'.");
805 return minWeightPath<Ret>(from_id, to_id, std::function<Ret(
EdgeT_, Args...)>(func), args...);
808template <
typename EdgeT, IDVT IDT>
809template <
typename Ret,
typename... Args>
811 std::function<Ret(
EdgeT_, Args...)> func,
814 return minOrMaxWeightPath<Ret>(
true, from_id, to_id, func, args...);
817template <
typename EdgeT, IDVT IDT>
818template <
typename Ret,
typename... Args>
819inline std::pair<Ret, std::vector<IDT>>
827 if (from_id == to_id)
return { func(
g.at(from_id).at(to_id), args...), { from_id } };
830 std::map<IDT, Ret> dist;
831 std::map<IDT, IDT> prev;
832 std::set<std::pair<Ret, IDT>> pq;
835 if constexpr (std::is_same_v<IDT, std::string>) default_ID =
"__default_ID";
836 else default_ID = IDT(-1);
839 Ret bound = min ? std::numeric_limits<Ret>::infinity() : Ret(0);
842 for (
auto&& [
id, _] :
g) {
844 prev[id] = default_ID;
845 pq.insert({ dist[id],
id });
848 pq.erase({ bound, from_id });
849 pq.insert({ dist[from_id], from_id });
851 while (!pq.empty()) {
852 auto curr_id = pq.begin()->second;
853 pq.erase(pq.begin());
855 if (curr_id == to_id)
break;
857 for (
auto&& [nei_id, weight] :
g.at(curr_id)) {
858 auto alt = dist[curr_id] + func(weight);
859 if (min ? (alt < dist[nei_id]) : (alt > dist[nei_id])) {
860 pq.erase({ dist[nei_id], nei_id });
862 prev[nei_id] = curr_id;
863 pq.insert({ dist[nei_id], nei_id });
869 std::vector<IDT> path;
871 while (curr_id != default_ID && prev.find(curr_id) != prev.end()) {
872 path.push_back(curr_id);
873 curr_id = prev[curr_id];
875 std::reverse(path.begin(), path.end());
878 if (path.size() < 1)
throw runtime_error(
"no path found between nodes in method");
880 return { dist[to_id], path };
883template <
typename EdgeT, IDVT IDT>
888template <
typename EdgeT, IDVT IDT>
894template <
typename EdgeT, IDVT IDT>
896 for (
auto&& [
id, cn] :
dg.g) {
897 if (
auto&& i =
g.find(
id); i ==
g.end())
g[id] = cn;
898 else i->second.insert(cn.begin(), cn.end());
902template <
typename EdgeT, IDVT IDT>
907template <
typename EdgeT, IDVT IDT>
909 for (
auto&& cn :
g) cn.second.clear();
912template <
typename EdgeT, IDVT IDT>
914 return this->
g == dg.
g;
917template <
typename EdgeT, IDVT IDT>
919 return this->
g != dg.
g;
922template <
typename EdgeT, IDVT IDT>
928template <
typename EdgeT, IDVT IDT>
931 return edge(from_id, to_id);
934template <
typename EdgeT, IDVT IDT>
937 return edge(from_id, to_id);
940template <
typename EdgeT, IDVT IDT>
943 for (
auto&& cn :
g) s += cn.second.erase(
id);
947template <
typename EdgeT, IDVT IDT>
952template <
typename EdgeT, IDVT IDT>
Directed graph base class.
Definition: base.hpp:44
EdgeT_CR_<> EdgeT_CR
Definition: base.hpp:81
bool hasEdge(IDT from_id, IDT to_id) const noexcept
Check if the graph has an edge linking from_id and to_id.
Definition: base.hpp:587
void merge(const DGraphBase< EdgeT, IDT > &dg)
Merge a graph into the main graph.
Definition: base.hpp:895
EdgeT_R_<> EdgeT_R
Definition: base.hpp:80
size_t size() const noexcept
The total number of nodes in the graph.
Definition: base.hpp:605
std::pair< Ret, std::vector< IDT > > minOrMaxWeightPath(bool min, IDT from_id, IDT to_id, std::function< Ret(EdgeT_, Args...)> func, Args... args) const
Obtain the minimum/maximum weight and its corresponding path between two nodes.
Definition: base.hpp:820
size_t numEdges() const noexcept
The total number of edges in the graph.
Definition: base.hpp:598
std::pair< EdgeT_, std::vector< IDT > > minWeightPath(IDT from_id, IDT to_id) const
Obtain the minimum weight and its corresponding path between two nodes.
Definition: base.hpp:791
const std::map< IDT, _CN > & graph() const
Return the const reference to the graph map.
Definition: base.hpp:948
void removeNode(IDT id, bool keep_edge=false)
Remove the node from the graph.
Definition: base.hpp:699
size_t numNodes() const noexcept
The total number of nodes in the graph.
Definition: base.hpp:593
bool isConnected(IDT from_id, IDT to_id) const
Check whether to node are connected.
Definition: base.hpp:738
DGraphBase & operator+=(const DGraphBase< EdgeT, IDT > &dg)
Merge two graphs.
Definition: base.hpp:923
std::vector< std::pair< IDT, IDT > > edges() const
Get all edge connections in the graph.
Definition: base.hpp:669
std::vector< IDT > nodesID() const
Get all nodes IS in the graph.
Definition: base.hpp:662
void clear()
Clear the whole graph.
Definition: base.hpp:903
bool strictCheck() const
Check if the graph is strictly valid.
Definition: base.hpp:651
DGraphBase()=default
Construct a new DGraphBase object.
std::map< IDT, _ET > _CN
Definition: base.hpp:47
EdgeT edge(IDT from_id, IDT to_id) const
Get the edge data between two nodes.
Definition: base.hpp:610
bool operator==(const DGraphBase< EdgeT, IDT > &dg) const
Check if two graphs are identical.
Definition: base.hpp:913
void insertNode(IDT id)
Insert a node.
Definition: base.hpp:678
std::map< IDT, _CN > g
Definition: base.hpp:578
void insertEdgeToExists(IDT from_id, IDT to_id)
Definition: base.hpp:711
void insertSubGraph(const DGraphBase< EdgeT, IDT > &dg)
Insert subgraph into the main graph.
Definition: base.hpp:884
EdgeT operator()(IDT from_id, IDT to_id) const
Get the edge data between two nodes.
Definition: base.hpp:929
EdgeT__<> EdgeT_
Definition: base.hpp:79
typename std::conditional< std::is_void_v< T >, int, T >::type & EdgeT_R_
Reference to edge type that avoids void.
Definition: base.hpp:67
void removeNodeIfExists(IDT id, bool keep_edge=false)
Remove the node from the graph if it exists.
Definition: base.hpp:705
bool operator!=(const DGraphBase< EdgeT, IDT > &dg) const
Check if two graphs are different.
Definition: base.hpp:918
size_t removeNodeConnectedEdges(IDT id)
Remove edges connected to a node.
Definition: base.hpp:941
bool hasNode(IDT id) const noexcept
Check if the graph has a node with id.
Definition: base.hpp:582
void insertEdge(IDT from_id, IDT to_id, bool to_exists=false)
Insert an edge to the graph without data.
Definition: base.hpp:723
void clearEdges()
Clear all edges of the graph.
Definition: base.hpp:908
const typename std::conditional< std::is_void_v< T >, int, T >::type & EdgeT_CR_
Const reference to edge type that avoids void.
Definition: base.hpp:77
std::pair< EdgeT_, std::vector< IDT > > maxWeightPath(IDT from_id, IDT to_id) const
Obtain the maximum weight and its corresponding path between two nodes.
Definition: base.hpp:763
typename std::conditional< std::is_void_v< T >, int, T >::type EdgeT__
Edge type that avoids void.
Definition: base.hpp:57
Definition: except.hpp:14
Definition: except.hpp:11
Common Utilities for DG-CPP.
Definition: common.hpp:25
Definition: common.hpp:19
Definition: common.hpp:27
static std::map< IDT, Edge< EdgeT > > mapAsEdgeMap(const std::map< IDT, EdgeT > &map)
Definition: edge.hpp:48
Directed Graph namespace.
Definition: base.hpp:35