Fishnet 2.0.1
Framework for Graph-Based Analysis of GIS Vector Data
Loading...
Searching...
No Matches
WeightedGraph.hpp
Go to the documentation of this file.
1#pragma once
3#include <unordered_map>
4#include <algorithm>
5
6namespace fishnet::graph{
14template<typename GraphImpl, typename E= GraphImpl::edge_type, typename N= E::node_type>
16}
17
18namespace fishnet::graph::__impl {
26 template<class G,Annotation A, WeightFunction<typename G::node_type,A> W>
27 class WeightedGraphDecorator: public GraphDecorator<WeightedGraphDecorator<G,A,W>,G,WeightEdge<typename G::edge_type,A,W>>{
28 private:
29 using E = G::edge_type;
30 using WE= WeightEdge<E,A,W>;
31 using N = G::node_type;
32 using WeightMap = std::unordered_map<E,A>;
34 WeightMap weightMap; // weights are stored in a map from edge to annotation, allowing heterogenous weights retrieved by the weight function or by the user
35 public:
36 using edge_type=WE;
37 using adj_container_type = G::adj_container_type;
38 static_assert(! WeightedEdge<E, typename E::node_type, A,W>); // underlying edge type must not be weighted
39 private:
40 inline WE toWeightedEdge(const E & e)const{
41 if (weightMap.contains(e)){
42 return WE(e.getFrom(),e.getTo(),weightMap.at(e));
43 }
44 return WE(e);
45 }
46
47 std::vector<WE> toWeightedEdges(util::forward_range_of<E> auto && edges)const {
48 std::vector<WE> weighted;
49 std::ranges::transform(edges,std::back_inserter(weighted),[this](const E & e){return toWeightedEdge(e);});
50 return weighted;
51 }
52
53 public:
54 WeightedGraphDecorator():Base(){}
55
56 WeightedGraphDecorator(adj_container_type && adjContainer):Base(std::move(adjContainer)){}
57
58 WeightedGraphDecorator(util::forward_range_of<N> auto & nodes):Base(nodes){};
59
60 WeightedGraphDecorator(util::forward_range_of<N> auto && nodes):Base(nodes){};
61
62 bool addEdge(const WE & edge){
63 auto withoutWeight = edge.unweighted();
64 if(this->g.addEdge(withoutWeight)){
65 if(not weightMap.try_emplace(withoutWeight,edge.getWeight()).second){
66 weightMap[withoutWeight] = edge.getWeight();
67 }
68 return true;
69 }
70 return false;
71 }
72
73 void addEdges(util::forward_range_of<WE> auto && edges) {
74 std::ranges::for_each(edges,[this]( auto && edge){this->addEdge(edge);});
75 }
76
77 void addEdges(util::forward_range_of<std::pair<N,N>> auto && nodePairs) {
78 std::ranges::for_each(nodePairs,[this]( auto && pair){this->addEdge(pair.first,pair.second);});
79 }
80
81 bool addEdge( const N & from, const N & to){
82 return Base::addEdge(from,to);
83 }
84
85 bool addEdge( N && from, N && to){
86 return Base::addEdge(from,to);
87 }
88
89 bool addEdge( const N & from, const N & to, const A & annotation){
90 auto e = E(from,to);
91 if (Base::addEdge(e)) {
92 if(not weightMap.try_emplace(e,annotation).second){
93 weightMap[e] = annotation;
94 }
95 return true;
96 }
97 return false;
98 }
99
100 bool addEdge( N && from, N && to, const A & annotation){
101 auto e = E(from,to);
102 if (Base::addEdge(e)){
103 if(not weightMap.try_emplace(E(from,to),annotation).second){
104 weightMap[e] = annotation;
105 }
106 return true;
107 }
108 return false;
109 }
110
111 bool containsEdge(const WE & edge)const{
112 auto unweighted = edge.unweighted();
113 return Base::containsEdge(unweighted) && toWeightedEdge(unweighted).getWeight() == edge.getWeight();
114 }
115
116 bool containsEdge(const N & from, const N & to) const{
117 return Base::containsEdge(from,to);
118 }
119
120 bool containsEdge(const N & from, const N & to, const A & annotation){
121 return containsEdge(WE(from,to,annotation));
122 }
123
124 inline WE makeEdge(const N & from, const N & to) const noexcept{
125 return toWeightedEdge(this->g.makeEdge(from,to));
126 }
127
128 inline static WE makeWeightedEdge(const N & from, const N & to) {
129 return WE(from,to);
130 }
131
132 inline WE makeEdge(const N & from, const N & to, const A & annotation){
133 return WE(from,to,annotation);
134 }
135
136 inline static WE makeWeightedEdge(const N & from, const N & to, const A & annotation){
137 return WE(from,to,annotation);
138 }
139
140 void removeEdge(const N & from, const N & to){
141 E e {from,to};
142 if (weightMap.contains(e)){
143 weightMap.erase(e);
144 }
145 Base::removeEdge(from,to);
146 }
147
151 void removeEdge(const WE & e){
152 auto unweighted = e.unweighted();
153 if(not weightMap.contains(unweighted) && WE(unweighted).getWeight()==e.getWeight()){
154 Base::removeEdge(unweighted);
155 }else if(weightMap.contains(unweighted) && weightMap.at(unweighted) == e.getWeight()) {
156 weightMap.erase(unweighted);
157 Base::removeEdge(unweighted);
158 }
159 }
160
161 inline auto getEdges() const {
162 return toWeightedEdges(this->g.getEdges());
163 }
164
165 inline auto getOutboundEdges(const N & node)const{
166 return toWeightedEdges(this->g.getOutboundEdges(node));
167 }
168
169 inline auto getInboundEdges(const N & node) const{
170 return toWeightedEdges(this->g.getInboundEdges(node));
171 }
172
173 void clear(){
174 weightMap.clear();
175 Base::clear();
176 }
177 };
178}
179namespace fishnet::graph{
187template<Graph G,Annotation A, WeightFunction<typename G::node_type,A> W>
188using Weighted = __impl::WeightedGraphDecorator<G,A,W>;
189}
Abstract Graph Decorator using CRTP.
Definition GraphDecorator.hpp:14
bool addEdge(const N &from, const N &to)
Definition GraphDecorator.hpp:61
void removeEdge(const N &from, const N &to)
Definition GraphDecorator.hpp:89
void clear()
Definition GraphDecorator.hpp:129
bool containsEdge(const N &from, const N &to) const noexcept
Definition GraphDecorator.hpp:81
Interface for graph types. Every graph type has to inherit from AbstractGraph.
Definition GraphModel.hpp:23
Definition Edge.hpp:9
Interface for a weighted Edge.
Definition Edge.hpp:47
Interface for a weighted graph.
Definition WeightedGraph.hpp:15
Definition CollectionConcepts.hpp:27
Definition AdjacencyContainer.hpp:4
__impl::WeightedGraphDecorator< G, A, W > Weighted
Weighted Graph Decorator type.
Definition WeightedGraph.hpp:188
__impl::WeightedEdgeDecorator< E, A, W > WeightEdge
Definition Edge.hpp:192