nxpp
Header-only graph utilities on top of Boost Graph Library
Loading...
Searching...
No Matches
attributes.hpp
Go to the documentation of this file.
1#pragma once
2
11#include "graph.hpp"
12
13namespace nxpp {
14
15template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
16static void throw_if_multigraph_attr_add_is_ambiguous() {
17 if constexpr (Multi) {
18 throw std::runtime_error(
19 "Multigraph endpoint-based add_edge(..., attrs) is ambiguous. "
20 "Use add_edge_with_id(...) and then set_edge_attr(edge_id, ...)."
21 );
22 }
23}
24
25template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
26template <bool W>
27requires(W)
29 const NodeID& u,
30 const NodeID& v,
31 EdgeWeight w,
32 const EdgeAttrMap& attrs
33) {
34 throw_if_multigraph_attr_add_is_ambiguous<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>();
35 add_edge(u, v, w);
36 assign_edge_attrs(get_edge_desc(u, v), attrs);
37}
38
39template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
41 const NodeID& u,
42 const NodeID& v,
43 const EdgeAttrMap& attrs
44) {
45 throw_if_multigraph_attr_add_is_ambiguous<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>();
46 if constexpr (Weighted) {
47 add_edge(u, v, static_cast<EdgeWeight>(1.0), attrs);
48 } else {
49 add_edge(u, v);
50 assign_edge_attrs(get_edge_desc(u, v), attrs);
51 }
52}
53
54template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
55template <bool W>
56requires(W)
58 const NodeID& u,
59 const NodeID& v,
60 EdgeWeight w,
61 const std::pair<std::string, std::any>& attr
62) {
63 throw_if_multigraph_attr_add_is_ambiguous<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>();
64 add_edge(u, v, w);
65 assign_edge_attr(get_edge_desc(u, v), attr);
66}
67
68template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
70 const NodeID& u,
71 const NodeID& v,
72 const std::pair<std::string, std::any>& attr
73) {
74 throw_if_multigraph_attr_add_is_ambiguous<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>();
75 if constexpr (Weighted) {
76 add_edge(u, v, static_cast<EdgeWeight>(1.0), attr);
77 } else {
78 add_edge(u, v);
79 assign_edge_attr(get_edge_desc(u, v), attr);
80 }
81}
82
83template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
84template <bool W>
85requires(W)
87 const NodeID& u,
88 const NodeID& v,
89 EdgeWeight w,
90 std::initializer_list<std::pair<std::string, std::any>> attrs
91) {
92 throw_if_multigraph_attr_add_is_ambiguous<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>();
93 add_edge(u, v, w);
94 assign_edge_attrs(get_edge_desc(u, v), attrs);
95}
96
97template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
99 const NodeID& u,
100 const NodeID& v,
101 std::initializer_list<std::pair<std::string, std::any>> attrs
102) {
103 throw_if_multigraph_attr_add_is_ambiguous<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>();
104 if constexpr (Weighted) {
105 add_edge(u, v, static_cast<EdgeWeight>(1.0), attrs);
106 } else {
107 add_edge(u, v);
108 assign_edge_attrs(get_edge_desc(u, v), attrs);
109 }
110}
111
112template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
114 auto node_it = node_properties.find(u);
115 if (node_it == node_properties.end()) {
116 return false;
117 }
118 return node_it->second.find(key) != node_it->second.end();
119}
120
121template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
122bool Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>::has_edge_attr(const NodeID& u, const NodeID& v, const std::string& key) const {
123 if (!has_edge(u, v)) {
124 return false;
125 }
126 auto e = get_edge_desc(u, v);
127 auto edge_it = edge_properties.find(get_edge_id(e));
128 if (edge_it == edge_properties.end()) {
129 return false;
130 }
131 return edge_it->second.find(key) != edge_it->second.end();
132}
133
134template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
136 auto edge_it = edge_properties.find(edge_id);
137 if (edge_it == edge_properties.end()) {
138 return false;
139 }
140 return edge_it->second.find(key) != edge_it->second.end();
141}
142
143template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
144template <typename T>
146 auto node_it = node_properties.find(u);
147 if (node_it == node_properties.end()) {
148 throw std::runtime_error("Node attribute lookup failed: node has no attributes.");
149 }
150 auto attr_it = node_it->second.find(key);
151 if (attr_it == node_it->second.end()) {
152 throw std::runtime_error("Node attribute lookup failed: key not found.");
153 }
154 try {
155 return std::any_cast<T>(attr_it->second);
156 } catch (const std::bad_any_cast&) {
157 throw std::runtime_error("Node attribute lookup failed: stored type does not match requested type.");
158 }
159}
160
161template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
162template <typename T>
164 auto e = get_edge_desc(u, v);
165 auto edge_it = edge_properties.find(get_edge_id(e));
166 if (edge_it == edge_properties.end()) {
167 throw std::runtime_error("Edge attribute lookup failed: edge has no attributes.");
168 }
169 auto attr_it = edge_it->second.find(key);
170 if (attr_it == edge_it->second.end()) {
171 throw std::runtime_error("Edge attribute lookup failed: key not found.");
172 }
173 try {
174 return std::any_cast<T>(attr_it->second);
175 } catch (const std::bad_any_cast&) {
176 throw std::runtime_error("Edge attribute lookup failed: stored type does not match requested type.");
177 }
178}
179
180template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
181template <typename T>
183 auto node_it = node_properties.find(u);
184 if (node_it == node_properties.end()) {
185 return std::nullopt;
186 }
187 auto attr_it = node_it->second.find(key);
188 if (attr_it == node_it->second.end()) {
189 return std::nullopt;
190 }
191 if (const auto* value = std::any_cast<T>(&(attr_it->second))) {
192 return *value;
193 }
194 return std::nullopt;
195}
196
197template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
198template <typename T>
199std::optional<T> Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>::try_get_edge_attr(const NodeID& u, const NodeID& v, const std::string& key) const {
200 if (!has_edge(u, v)) {
201 return std::nullopt;
202 }
203 auto e = get_edge_desc(u, v);
204 auto edge_it = edge_properties.find(get_edge_id(e));
205 if (edge_it == edge_properties.end()) {
206 return std::nullopt;
207 }
208 auto attr_it = edge_it->second.find(key);
209 if (attr_it == edge_it->second.end()) {
210 return std::nullopt;
211 }
212 if (const auto* value = std::any_cast<T>(&(attr_it->second))) {
213 return *value;
214 }
215 return std::nullopt;
216}
217
218template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
220 if (key == "weight") {
221 if constexpr (Weighted) {
222 return static_cast<double>(get_edge_weight(u, v));
223 } else {
224 throw std::runtime_error("Edge attribute lookup failed: graph has no built-in edge weight.");
225 }
226 }
227
228 auto e = get_edge_desc(u, v);
229 auto edge_it = edge_properties.find(get_edge_id(e));
230 if (edge_it == edge_properties.end()) {
231 throw std::runtime_error("Edge attribute lookup failed: edge has no attributes.");
232 }
233 auto attr_it = edge_it->second.find(key);
234 if (attr_it == edge_it->second.end()) {
235 throw std::runtime_error("Edge attribute lookup failed: key not found.");
236 }
237
238 const auto& value = attr_it->second;
239 if (const auto* vptr = std::any_cast<int>(&value)) return static_cast<double>(*vptr);
240 if (const auto* vptr = std::any_cast<long>(&value)) return static_cast<double>(*vptr);
241 if (const auto* vptr = std::any_cast<long long>(&value)) return static_cast<double>(*vptr);
242 if (const auto* vptr = std::any_cast<float>(&value)) return static_cast<double>(*vptr);
243 if (const auto* vptr = std::any_cast<double>(&value)) return *vptr;
244
245 throw std::runtime_error("Edge attribute lookup failed: stored value is not numeric.");
246}
247
248template <typename NodeID, typename EdgeWeight, bool Directed, bool Multi, bool Weighted, typename OutEdgeSelector, typename VertexSelector>
249template <bool W>
250requires(W)
252 auto it_u = id_to_bgl.find(u);
253 auto it_v = id_to_bgl.find(v);
254 if (it_u == id_to_bgl.end() || it_v == id_to_bgl.end()) throw std::runtime_error("Node lookup failed: node not found.");
255 auto [e, exists] = boost::edge(it_u->second, it_v->second, g);
256 if (!exists) throw std::runtime_error("Edge lookup failed: edge not found.");
257 return weight_map[e];
258}
259
260} // namespace nxpp
Graph wrapper around Boost Graph Library with Python-inspired helpers.
Definition graph.hpp:272
double get_edge_numeric_attr(const NodeID &u, const NodeID &v, const std::string &key) const
Reads an endpoint-selected edge attribute as a numeric value.
Definition attributes.hpp:219
std::optional< T > try_get_node_attr(const NodeID &u, const std::string &key) const
Attempts to read a typed node attribute without throwing.
Definition attributes.hpp:182
bool has_node_attr(const NodeID &u, const std::string &key) const
Returns whether a node has the named attribute.
Definition attributes.hpp:113
T get_node_attr(const NodeID &u, const std::string &key) const
Reads a typed node attribute.
Definition attributes.hpp:145
bool has_edge_attr(const NodeID &u, const NodeID &v, const std::string &key) const
Returns whether an endpoint-selected edge has the named attribute.
Definition attributes.hpp:122
std::optional< T > try_get_edge_attr(const NodeID &u, const NodeID &v, const std::string &key) const
Attempts to read a typed edge attribute selected by endpoints.
Definition attributes.hpp:199
T get_edge_attr(const NodeID &u, const NodeID &v, const std::string &key) const
Reads a typed edge attribute selected by endpoints.
Definition attributes.hpp:163
Core graph wrapper, proxy surface, and public alias presets.