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