11#if !__has_include(<boost/graph/adjacency_list.hpp>)
12#error "FATAL: nxpp requires the Boost Graph Library (BGL)."
15#if defined(__GNUC__) && !defined(__clang__)
16#pragma GCC diagnostic push
17#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
19#include <boost/graph/adjacency_list.hpp>
20#if defined(__GNUC__) && !defined(__clang__)
21#pragma GCC diagnostic pop
38#include <initializer_list>
44 std::copy_constructible<T> &&
45 std::equality_comparable<T> &&
46 requires(
const T& lhs,
const T& rhs) {
47 { std::less<T>{}(lhs, rhs) } -> std::convertible_to<bool>;
54 typename NodeID = std::string,
55 typename EdgeWeight = double,
56 bool Directed =
false,
59 typename OutEdgeSelector = boost::vecS,
60 typename VertexSelector = boost::vecS
66template <
typename GraphWrapper>
68 static void invalidate(
const void*) {}
69 static void clear(
const void*) {}
81enum vertex_wrapper_index_t { vertex_wrapper_index };
82BOOST_INSTALL_PROPERTY(vertex, wrapper_index);
85 property_kind<vertex_wrapper_index_t>::type,
88 "nxpp Boost property extension must install vertex_wrapper_index_t as a vertex property"
95template <
typename GraphType,
bool HasWeight>
98template <
typename GraphType>
100 using map_type =
typename boost::property_map<GraphType, boost::edge_weight_t>::type;
102 static map_type get(GraphType& g) {
103 return boost::get(boost::edge_weight, g);
107template <
typename GraphType>
111 static map_type get(GraphType&) {
122template <
typename Key,
typename Value>
125 using storage_type = std::map<Key, Value>;
126 using iterator =
typename storage_type::iterator;
127 using const_iterator =
typename storage_type::const_iterator;
129 Value& operator[](
const Key& key) {
134 [[nodiscard]]
const Value&
operator[](
const Key& key)
const {
138 Value& at(
const Key& key) {
142 [[nodiscard]]
const Value& at(
const Key& key)
const {
146 iterator begin() {
return data.begin(); }
147 iterator end() {
return data.end(); }
148 const_iterator begin()
const {
return data.begin(); }
149 const_iterator end()
const {
return data.end(); }
150 const_iterator cbegin()
const {
return data.cbegin(); }
151 const_iterator cend()
const {
return data.cend(); }
157template <
typename Key,
typename Value>
160 using storage_type = std::vector<std::pair<Key, Value>>;
161 using iterator =
typename storage_type::iterator;
162 using const_iterator =
typename storage_type::const_iterator;
174 void reserve(std::size_t count) {
178 void push_back(
const Key& key,
const Value& value) {
179 data.emplace_back(key, value);
182 void push_back(
const Key& key, Value&& value) {
183 data.emplace_back(key, std::move(value));
186 Value& at(
const Key& key) {
188 if (it == data.end()) {
189 throw std::out_of_range(
"indexed_lookup_map::at");
194 [[nodiscard]]
const Value& at(
const Key& key)
const {
196 if (it == data.end()) {
197 throw std::out_of_range(
"indexed_lookup_map::at");
202 Value& operator[](
const Key& key) {
207 [[nodiscard]]
const Value&
operator[](
const Key& key)
const {
211 [[nodiscard]]
bool contains(
const Key& key)
const {
212 return find(key) != data.end();
215 iterator find(
const Key& key) {
216 auto it = lower_bound_for(key);
217 if (it == data.end() || key < it->first) {
223 [[nodiscard]] const_iterator find(
const Key& key)
const {
224 auto it = lower_bound_for(key);
225 if (it == data.end() || key < it->first) {
231 iterator begin() {
return data.begin(); }
232 iterator end() {
return data.end(); }
233 const_iterator begin()
const {
return data.begin(); }
234 const_iterator end()
const {
return data.end(); }
235 const_iterator cbegin()
const {
return data.cbegin(); }
236 const_iterator cend()
const {
return data.cend(); }
238 [[nodiscard]]
bool empty()
const {
return data.empty(); }
239 [[nodiscard]] std::size_t size()
const {
return data.size(); }
242 iterator lower_bound_for(
const Key& key) {
243 return std::lower_bound(
247 [](
const auto& entry,
const Key& value) { return entry.first < value; }
251 const_iterator lower_bound_for(
const Key& key)
const {
252 return std::lower_bound(
256 [](
const auto& entry,
const Key& value) { return entry.first < value; }
271 typename OutEdgeSelector,
272 typename VertexSelector
290 using NodeType = NodeID;
291 using EdgeWeightType = EdgeWeight;
292 using OutEdgeListSelector = OutEdgeSelector;
293 using VertexListSelector = VertexSelector;
294 using DirectedSelector =
typename std::conditional<Directed, boost::bidirectionalS, boost::undirectedS>::type;
295 using VertexProperty = boost::property<
296 boost::vertex_name_t,
298 boost::property<boost::vertex_wrapper_index_t, std::size_t>
300 using EdgeProperty =
typename std::conditional<
302 boost::property<boost::edge_weight_t, EdgeWeight, boost::property<boost::edge_index_t, std::size_t>>,
303 boost::property<boost::edge_index_t, std::size_t>
305 using GraphType = boost::adjacency_list<OutEdgeSelector, VertexSelector, DirectedSelector,
306 VertexProperty, EdgeProperty>;
307 using VertexDesc =
typename boost::graph_traits<GraphType>::vertex_descriptor;
308 using EdgeDesc =
typename boost::graph_traits<GraphType>::edge_descriptor;
310 using VertexNameMap =
typename boost::property_map<GraphType, boost::vertex_name_t>::type;
311 using WrapperIndexMap =
typename boost::property_map<GraphType, boost::vertex_wrapper_index_t>::type;
312 using VertexIndexMap = WrapperIndexMap;
313 using EdgeIdMap =
typename boost::property_map<GraphType, boost::edge_index_t>::type;
314 using IdMap = std::map<NodeID, VertexDesc>;
315 using AttrMap = std::map<std::string, std::any>;
316 using NodeAttrStorage = std::map<NodeID, AttrMap>;
317 using EdgeAttrStorage = std::map<std::size_t, AttrMap>;
318 using EdgeIdIndex = std::map<std::size_t, EdgeDesc>;
319 static constexpr bool is_directed = Directed;
320 static constexpr bool has_builtin_edge_weight = Weighted;
325 "nxpp::Graph requires NodeID to satisfy nxpp::ValidNodeID: copy-constructible, equality comparable, and orderable with std::less."
329 WeightMap weight_map;
330 VertexNameMap vertex_name_map;
331 VertexIndexMap vertex_index_map;
332 EdgeIdMap edge_id_map;
334 std::vector<NodeID> bgl_to_id;
335 std::size_t next_edge_id = 0;
336 NodeAttrStorage node_properties;
337 EdgeAttrStorage edge_properties;
338 EdgeIdIndex edge_id_to_desc;
342 !(Multi && std::is_same_v<OutEdgeSelector, boost::setS>),
343 "nxpp does not support Multi=true with boost::setS because setS suppresses parallel edges."
346 using EdgeAttrMap = AttrMap;
348 static std::any normalize_attr_any(std::any value) {
349 if (value.type() ==
typeid(
const char*)) {
350 return std::string(std::any_cast<const char*>(value));
352 if (value.type() ==
typeid(
char*)) {
353 return std::string(std::any_cast<char*>(value));
358 template <
typename T>
359 static std::any make_attr_any(
const T& value) {
360 if constexpr (std::is_convertible_v<T, const char*> && !std::is_same_v<std::decay_t<T>, std::string>) {
361 return std::string(value);
363 return std::any(value);
367 static std::runtime_error invalid_flow_capacity_error() {
368 return std::runtime_error(
"Flow capacity setup failed: capacity must be a non-negative integral value representable as long.");
371 template <
typename T>
372 static long checked_flow_capacity_value(T value) {
373 if constexpr (std::is_same_v<T, bool>) {
374 throw invalid_flow_capacity_error();
375 }
else if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
376 if (value < 0 ||
static_cast<long double>(value) >
static_cast<long double>(std::numeric_limits<long>::max())) {
377 throw invalid_flow_capacity_error();
379 return static_cast<long>(value);
380 }
else if constexpr (std::is_integral_v<T> && std::is_unsigned_v<T>) {
381 if (
static_cast<long double>(value) >
static_cast<long double>(std::numeric_limits<long>::max())) {
382 throw invalid_flow_capacity_error();
384 return static_cast<long>(value);
385 }
else if constexpr (std::is_floating_point_v<T>) {
386 if (!std::isfinite(value) || value < 0 || value >
static_cast<T
>(std::numeric_limits<long>::max()) ||
387 std::trunc(value) != value) {
388 throw invalid_flow_capacity_error();
390 return static_cast<long>(value);
392 throw invalid_flow_capacity_error();
396 template <
typename T>
397 static std::optional<long> try_flow_capacity_any_cast(
const std::any& value) {
398 if (
const auto* typed_value = std::any_cast<T>(&value)) {
399 return checked_flow_capacity_value(*typed_value);
404 long get_edge_flow_capacity(std::size_t edge_id,
const std::string& key)
const {
405 if (key ==
"weight") {
406 if constexpr (Weighted) {
407 return checked_flow_capacity_value(get_edge_weight(edge_id));
409 throw std::runtime_error(
"Edge attribute lookup failed: graph has no built-in edge weight.");
413 auto edge_it = edge_properties.find(edge_id);
414 if (edge_it == edge_properties.end()) {
415 throw std::runtime_error(
"Edge attribute lookup failed: edge has no attributes.");
417 auto attr_it = edge_it->second.find(key);
418 if (attr_it == edge_it->second.end()) {
419 throw std::runtime_error(
"Edge attribute lookup failed: key not found.");
422 const auto& value = attr_it->second;
423 if (
auto capacity = try_flow_capacity_any_cast<int>(value))
return *capacity;
424 if (
auto capacity = try_flow_capacity_any_cast<long>(value))
return *capacity;
425 if (
auto capacity = try_flow_capacity_any_cast<long long>(value))
return *capacity;
426 if (
auto capacity = try_flow_capacity_any_cast<unsigned int>(value))
return *capacity;
427 if (
auto capacity = try_flow_capacity_any_cast<unsigned long>(value))
return *capacity;
428 if (
auto capacity = try_flow_capacity_any_cast<unsigned long long>(value))
return *capacity;
429 if (
auto capacity = try_flow_capacity_any_cast<float>(value))
return *capacity;
430 if (
auto capacity = try_flow_capacity_any_cast<double>(value))
return *capacity;
431 if (
auto capacity = try_flow_capacity_any_cast<long double>(value))
return *capacity;
433 throw std::runtime_error(
"Flow capacity setup failed: capacity attribute is not numeric.");
436 std::size_t vertex_index_of(VertexDesc v)
const {
437 return boost::get(vertex_index_map, v);
440 const NodeID& node_id_of(VertexDesc v)
const {
441 return boost::get(vertex_name_map, v);
444 template <
typename Value,
typename BuildValue>
447 result.reserve(id_to_bgl.size());
448 for (
const auto& [
id, desc] : id_to_bgl) {
449 result.push_back(
id, build_value(desc));
454 template <
typename Value>
456 const std::vector<std::optional<Value>>& values
459 for (
const auto& [
id, desc] : id_to_bgl) {
461 if (index < values.size() && values[index].has_value()) {
462 result.push_back(
id, *values[index]);
468 void rebuild_vertex_maps() {
472 std::size_t index = 0;
473 for (
auto [v, vend] = boost::vertices(g); v != vend; ++v, ++index) {
474 boost::put(vertex_index_map, *v, index);
475 NodeID
id = boost::get(vertex_name_map, *v);
477 bgl_to_id.push_back(
id);
481 void rebind_property_maps() {
483 vertex_name_map = boost::get(boost::vertex_name, g);
484 vertex_index_map = boost::get(boost::vertex_wrapper_index, g);
485 edge_id_map = boost::get(boost::edge_index, g);
488 VertexDesc get_or_create_vertex(
const NodeID&
id) {
489 auto it = id_to_bgl.find(
id);
490 if (it != id_to_bgl.end()) {
493 VertexDesc v = boost::add_vertex(g);
494 boost::put(vertex_name_map, v,
id);
495 boost::put(vertex_index_map, v, bgl_to_id.size());
497 bgl_to_id.push_back(
id);
501 std::optional<VertexDesc> find_vertex_by_id(
const NodeID&
id)
const {
502 for (
auto [v, vend] = boost::vertices(g); v != vend; ++v) {
503 if (boost::get(vertex_name_map, *v) ==
id) {
510 std::size_t get_edge_id(EdgeDesc e)
const {
511 return boost::get(edge_id_map, e);
514 void set_edge_id(EdgeDesc e, std::size_t edge_id) {
515 edge_id_map[e] = edge_id;
516 edge_id_to_desc[edge_id] = e;
519 std::size_t assign_next_edge_id(EdgeDesc e) {
520 const auto edge_id = next_edge_id++;
521 set_edge_id(e, edge_id);
525 void erase_edge_id_index(std::size_t edge_id) {
526 edge_id_to_desc.erase(edge_id);
529 void rebuild_edge_id_index() {
530 edge_id_to_desc.clear();
531 for (
auto [e, eend] = boost::edges(g); e != eend; ++e) {
532 edge_id_to_desc[get_edge_id(*e)] = *e;
536 std::optional<EdgeDesc> try_find_edge_desc_by_id(std::size_t edge_id)
const {
537 auto edge_it = edge_id_to_desc.find(edge_id);
538 if (edge_it != edge_id_to_desc.end()) {
539 return edge_it->second;
544 EdgeDesc get_edge_desc_by_id(std::size_t edge_id)
const {
545 auto edge_desc = try_find_edge_desc_by_id(edge_id);
546 if (!edge_desc.has_value()) {
547 throw std::runtime_error(
"Edge lookup failed: edge not found.");
552 std::vector<std::size_t> collect_edge_ids_between(VertexDesc u, VertexDesc v)
const {
554 for (
auto [e, eend] = boost::out_edges(u, g); e != eend; ++e) {
555 if constexpr (Directed) {
556 if (boost::target(*e, g) == v) {
557 edge_ids.push_back(get_edge_id(*e));
560 const auto source = boost::source(*e, g);
561 const auto target = boost::target(*e, g);
562 if ((source == u && target == v) || (source == v && target == u)) {
563 const auto edge_id = get_edge_id(*e);
573 void erase_incident_edge_properties(VertexDesc v) {
575 for (
auto [e, eend] = boost::out_edges(v, g); e != eend; ++e) {
576 edge_ids.push_back(get_edge_id(*e));
578 if constexpr (Directed) {
579 for (
auto [e, eend] = boost::in_edges(v, g); e != eend; ++e) {
580 if (boost::source(*e, g) != v) {
581 edge_ids.push_back(get_edge_id(*e));
586 edge_properties.erase(edge_id);
587 erase_edge_id_index(edge_id);
591 void assign_edge_attrs(EdgeDesc e,
const EdgeAttrMap& attrs) {
592 auto& edge_attr_map = edge_properties[get_edge_id(e)];
593 for (
const auto& [key, value] : attrs) {
594 edge_attr_map[key] = normalize_attr_any(value);
598 void assign_edge_attrs(EdgeDesc e, std::initializer_list<std::pair<std::string, std::any>> attrs) {
599 auto& edge_attr_map = edge_properties[get_edge_id(e)];
600 for (
const auto& [key, value] : attrs) {
601 edge_attr_map[key] = normalize_attr_any(value);
605 void assign_edge_attr(EdgeDesc e,
const std::pair<std::string, std::any>& attr) {
606 edge_properties[get_edge_id(e)][attr.first] = normalize_attr_any(attr.second);
609 template <
typename NodeRange>
610 Graph build_subgraph(
const NodeRange& selected_nodes)
const {
612 std::set<NodeID> selected;
614 for (
const auto&
node : selected_nodes) {
616 throw std::invalid_argument(
"Subgraph extraction failed: node not found.");
618 if (!selected.insert(
node).second) {
623 auto node_attr_it = node_properties.find(
node);
624 if (node_attr_it != node_properties.end()) {
625 result.node_properties[
node] = node_attr_it->second;
629 for (
auto [edge, edge_end] = boost::edges(g); edge != edge_end; ++edge) {
630 const NodeID& source = node_id_of(boost::source(*edge, g));
631 const NodeID& target = node_id_of(boost::target(*edge, g));
632 if (!selected.contains(source) || !selected.contains(target)) {
636 auto [new_edge, added] = boost::add_edge(result.id_to_bgl.at(source), result.id_to_bgl.at(target), result.g);
638 if constexpr (Weighted) {
639 result.weight_map[new_edge] = weight_map[*edge];
641 const auto new_edge_id = result.next_edge_id++;
642 result.set_edge_id(new_edge, new_edge_id);
644 const auto old_edge_id = get_edge_id(*edge);
645 const auto edge_attr_it = edge_properties.find(old_edge_id);
646 if (edge_attr_it != edge_properties.end()) {
647 result.edge_properties[new_edge_id] = edge_attr_it->second;
658 vertex_name_map(boost::get(boost::vertex_name, g)),
659 vertex_index_map(boost::get(boost::vertex_wrapper_index, g)),
660 edge_id_map(boost::get(boost::edge_index, g)),
666 vertex_name_map(boost::get(boost::vertex_name, g)),
667 vertex_index_map(boost::get(boost::vertex_wrapper_index, g)),
668 edge_id_map(boost::get(boost::edge_index, g)),
671 next_edge_id(other.next_edge_id),
672 node_properties(other.node_properties),
673 edge_properties(other.edge_properties) {
674 rebuild_vertex_maps();
675 rebuild_edge_id_index();
679 : g(std::move(other.g)),
681 vertex_name_map(boost::get(boost::vertex_name, g)),
682 vertex_index_map(boost::get(boost::vertex_wrapper_index, g)),
683 edge_id_map(boost::get(boost::edge_index, g)),
686 next_edge_id(other.next_edge_id),
687 node_properties(std::move(other.node_properties)),
688 edge_properties(std::move(other.edge_properties)) {
689 rebuild_vertex_maps();
690 rebuild_edge_id_index();
691 other.clear_min_cost_flow_state();
696 if (
this == &other) {
700 clear_min_cost_flow_state();
702 rebind_property_maps();
703 next_edge_id = other.next_edge_id;
704 node_properties = other.node_properties;
705 edge_properties = other.edge_properties;
706 rebuild_vertex_maps();
707 rebuild_edge_id_index();
712 if (
this == &other) {
716 clear_min_cost_flow_state();
717 g = std::move(other.g);
718 rebind_property_maps();
719 next_edge_id = other.next_edge_id;
720 node_properties = std::move(other.node_properties);
721 edge_properties = std::move(other.edge_properties);
722 rebuild_vertex_maps();
723 rebuild_edge_id_index();
724 other.clear_min_cost_flow_state();
730 clear_min_cost_flow_state();
741 invalidate_min_cost_flow_state();
742 get_or_create_vertex(
id);
752 for (
const auto& n :
nodes) {
763 [[nodiscard]] EdgeDesc
get_edge_desc(
const NodeID& u,
const NodeID& v)
const {
764 auto it_u = id_to_bgl.find(u);
765 auto it_v = id_to_bgl.find(v);
766 if (it_u == id_to_bgl.end() || it_v == id_to_bgl.end())
throw std::runtime_error(
"Node lookup failed: node not found.");
767 auto [e, exists] = boost::edge(it_u->second, it_v->second, g);
768 if (!exists)
throw std::runtime_error(
"Edge lookup failed: edge not found.");
779 [[nodiscard]]
bool has_edge(
const NodeID& u,
const NodeID& v)
const {
780 auto it_u = id_to_bgl.find(u);
781 auto it_v = id_to_bgl.find(v);
782 if (it_u == id_to_bgl.end() || it_v == id_to_bgl.end())
return false;
783 auto [e, exists] = boost::edge(it_u->second, it_v->second, g);
788 [[nodiscard]]
bool has_edge_id(std::size_t edge_id)
const;
790 [[nodiscard]] std::vector<std::size_t>
edge_ids()
const;
792 [[nodiscard]] std::vector<std::size_t>
edge_ids(
const NodeID& u,
const NodeID& v)
const;
794 [[nodiscard]] std::pair<NodeID, NodeID>
get_edge_endpoints(std::size_t edge_id)
const;
796 template <
bool W = Weighted>
809 void add_edge(
const NodeID& u,
const NodeID& v, EdgeWeight w = 1.0) {
810 invalidate_min_cost_flow_state();
811 VertexDesc bu = get_or_create_vertex(u);
812 VertexDesc bv = get_or_create_vertex(v);
814 if constexpr (!Multi) {
815 auto [e, exists] = boost::edge(bu, bv, g);
822 auto [e, added] = boost::add_edge(bu, bv, g);
825 assign_next_edge_id(e);
828 template <
bool W = Weighted>
836 std::size_t add_edge_with_id(
const NodeID& u,
const NodeID& v, EdgeWeight w = 1.0);
838 template <
bool W = Weighted>
849 void add_edge(
const NodeID& u,
const NodeID& v) {
850 invalidate_min_cost_flow_state();
851 VertexDesc bu = get_or_create_vertex(u);
852 VertexDesc bv = get_or_create_vertex(v);
854 if constexpr (!Multi) {
855 auto [e, exists] = boost::edge(bu, bv, g);
861 auto [e, added] = boost::add_edge(bu, bv, g);
863 assign_next_edge_id(e);
866 template <
bool W = Weighted>
874 std::size_t add_edge_with_id(
const NodeID& u,
const NodeID& v);
885 template <
bool W = Weighted>
887 void add_edge(
const NodeID& u,
const NodeID& v, EdgeWeight w,
const EdgeAttrMap& attrs);
896 void add_edge(
const NodeID& u,
const NodeID& v,
const EdgeAttrMap& attrs);
898 template <
bool W = Weighted>
908 void add_edge(
const NodeID& u,
const NodeID& v, EdgeWeight w,
const std::pair<std::string, std::any>& attr);
911 void add_edge(
const NodeID& u,
const NodeID& v,
const std::pair<std::string, std::any>& attr);
913 template <
bool W = Weighted>
923 void add_edge(
const NodeID& u,
const NodeID& v, EdgeWeight w, std::initializer_list<std::pair<std::string, std::any>> attrs);
926 void add_edge(
const NodeID& u,
const NodeID& v, std::initializer_list<std::pair<std::string, std::any>> attrs);
927 template <
bool W = Weighted>
930 void add_edges_from(
const std::vector<std::tuple<NodeID, NodeID, EdgeWeight>>&
edges) {
931 for (
const auto& edge :
edges) {
932 add_edge(std::get<0>(edge), std::get<1>(edge), std::get<2>(edge));
938 for (
const auto& edge :
edges) {
939 add_edge(edge.first, edge.second);
951 invalidate_min_cost_flow_state();
955 node_properties.clear();
956 edge_properties.clear();
958 vertex_name_map = boost::get(boost::vertex_name, g);
959 vertex_index_map = boost::get(boost::vertex_wrapper_index, g);
960 edge_id_map = boost::get(boost::edge_index, g);
978 template <
typename NodeRange>
980 return build_subgraph(selected_nodes);
984 [[nodiscard]]
Graph subgraph(std::initializer_list<NodeID> selected_nodes)
const {
985 return build_subgraph(selected_nodes);
998 invalidate_min_cost_flow_state();
999 auto it_u = id_to_bgl.find(u);
1000 auto it_v = id_to_bgl.find(v);
1001 if (it_u == id_to_bgl.end() || it_v == id_to_bgl.end()) {
1002 throw std::runtime_error(
"Node lookup failed: node not found.");
1004 auto [e, exists] = boost::edge(it_u->second, it_v->second, g);
1006 throw std::runtime_error(
"Edge lookup failed: edge not found.");
1008 for (
auto edge_id : collect_edge_ids_between(it_u->second, it_v->second)) {
1009 edge_properties.erase(edge_id);
1010 erase_edge_id_index(edge_id);
1012 if constexpr (!Directed && Multi) {
1013 const auto bu = it_u->second;
1014 const auto bv = it_v->second;
1015 boost::remove_edge_if(
1016 [
this, bu, bv](
const EdgeDesc& edge) {
1017 const auto source = boost::source(edge, g);
1018 const auto target = boost::target(edge, g);
1019 return (source == bu && target == bv) || (source == bv && target == bu);
1024 boost::remove_edge(it_u->second, it_v->second, g);
1052 invalidate_min_cost_flow_state();
1053 auto it = id_to_bgl.find(u);
1054 if (it == id_to_bgl.end()) {
1055 throw std::runtime_error(
"Node lookup failed: node not found.");
1057 VertexDesc v = it->second;
1059 erase_incident_edge_properties(v);
1060 boost::clear_vertex(v, g);
1061 boost::remove_vertex(v, g);
1063 node_properties.erase(u);
1064 rebuild_vertex_maps();
1065 rebuild_edge_id_index();
1080 std::vector<NodeID> unique_nodes;
1081 std::set<NodeID> seen;
1083 if (seen.insert(
node).second) {
1084 unique_nodes.push_back(
node);
1088 for (
const auto&
node : unique_nodes) {
1090 throw std::runtime_error(
"Node lookup failed: node not found.");
1094 if (unique_nodes.empty()) {
1098 invalidate_min_cost_flow_state();
1099 for (
const auto&
node : unique_nodes) {
1100 auto vertex = find_vertex_by_id(
node);
1101 if (!vertex.has_value()) {
1105 erase_incident_edge_properties(*vertex);
1106 boost::clear_vertex(*vertex, g);
1107 boost::remove_vertex(*vertex, g);
1108 node_properties.erase(
node);
1111 rebuild_vertex_maps();
1112 rebuild_edge_id_index();
1121 [[nodiscard]] std::vector<NodeID>
neighbors(
const NodeID& u)
const {
1122 auto it = id_to_bgl.find(u);
1123 if (it == id_to_bgl.end()) {
1124 throw std::runtime_error(
"Node lookup failed: node not found.");
1126 std::vector<NodeID> res;
1127 for (
auto [e, eend] = boost::out_edges(it->second, g); e != eend; ++e) {
1128 res.push_back(node_id_of(boost::target(*e, g)));
1134 [[nodiscard]] std::vector<NodeID>
successors(
const NodeID& u)
const {
1145 auto it = id_to_bgl.find(u);
1146 if (it == id_to_bgl.end()) {
1147 throw std::runtime_error(
"Node lookup failed: node not found.");
1150 std::vector<NodeID> res;
1151 if constexpr (Directed) {
1152 for (
auto [e, eend] = boost::in_edges(it->second, g); e != eend; ++e) {
1153 res.push_back(node_id_of(boost::source(*e, g)));
1156 for (
auto [e, eend] = boost::out_edges(it->second, g); e != eend; ++e) {
1157 res.push_back(node_id_of(boost::target(*e, g)));
1165 return id_to_bgl.find(u) != id_to_bgl.end();
1175 [[nodiscard]]
bool has_node_attr(
const NodeID& u,
const std::string& key)
const;
1183 [[nodiscard]]
bool has_edge_attr(
const NodeID& u,
const NodeID& v,
const std::string& key)
const;
1185 [[nodiscard]]
bool has_edge_attr(std::size_t edge_id,
const std::string& key)
const;
1187 template <
typename T>
1194 [[nodiscard]] T
get_node_attr(
const NodeID& u,
const std::string& key)
const;
1196 template <
typename T>
1203 [[nodiscard]] T
get_edge_attr(
const NodeID& u,
const NodeID& v,
const std::string& key)
const;
1205 template <
typename T>
1211 [[nodiscard]] T
get_edge_attr(std::size_t edge_id,
const std::string& key)
const;
1213 template <
typename T>
1220 [[nodiscard]] std::optional<T>
try_get_node_attr(
const NodeID& u,
const std::string& key)
const;
1222 template <
typename T>
1230 [[nodiscard]] std::optional<T>
try_get_edge_attr(
const NodeID& u,
const NodeID& v,
const std::string& key)
const;
1232 template <
typename T>
1234 [[nodiscard]] std::optional<T>
try_get_edge_attr(std::size_t edge_id,
const std::string& key)
const;
1243 [[nodiscard]]
double get_edge_numeric_attr(
const NodeID& u,
const NodeID& v,
const std::string& key)
const;
1247 template <
bool W = Weighted>
1256 [[nodiscard]] EdgeWeight get_edge_weight(
const NodeID& u,
const NodeID& v)
const;
1258 template <
bool W = Weighted>
1261 [[nodiscard]] EdgeWeight get_edge_weight(std::size_t edge_id)
const;
1263 template <
bool W = Weighted>
1266 void set_edge_weight(std::size_t edge_id, EdgeWeight w);
1268 template <
typename T>
1275 void set_edge_attr(std::size_t edge_id,
const std::string& key,
const T& value);
1283 [[nodiscard]] std::vector<NodeID>
nodes()
const {
1284 std::vector<NodeID> res;
1285 for (
auto [v, vend] = boost::vertices(g); v != vend; ++v) {
1286 res.push_back(node_id_of(*v));
1298 [[nodiscard]] std::vector<std::pair<NodeID, NodeID>>
edges()
const {
1299 std::vector<std::pair<NodeID, NodeID>> res;
1300 for (
auto [e, eend] = boost::edges(g); e != eend; ++e) {
1301 NodeID source_id = node_id_of(boost::source(*e, g));
1302 NodeID target_id = node_id_of(boost::target(*e, g));
1303 res.emplace_back(source_id, target_id);
1309 [[nodiscard]] std::vector<std::pair<NodeID, NodeID>>
edge_pairs()
const {
1314 template <
bool W = Weighted>
1316 [[nodiscard]] std::vector<std::tuple<NodeID, NodeID, EdgeWeight>>
weighted_edges()
const {
1317 std::vector<std::tuple<NodeID, NodeID, EdgeWeight>> res;
1318 for (
auto [e, eend] = boost::edges(g); e != eend; ++e) {
1319 NodeID source_id = node_id_of(boost::source(*e, g));
1320 NodeID target_id = node_id_of(boost::target(*e, g));
1321 res.emplace_back(source_id, target_id, weight_map[*e]);
1327 [[nodiscard]]
const GraphType&
get_impl()
const {
return g; }
1334 static const AttrMap empty;
1335 auto it = node_properties.find(u);
1336 return it == node_properties.end() ? empty : it->second;
1339 [[nodiscard]]
const AttrMap&
edge_attrs(std::size_t edge_id)
const {
1340 static const AttrMap empty;
1341 auto it = edge_properties.find(edge_id);
1342 return it == edge_properties.end() ? empty : it->second;
1345 [[nodiscard]]
const NodeID&
get_node_id(VertexDesc v)
const {
return node_id_of(v); }
1360 template <
typename T>
1363 if constexpr (Weighted) graph->add_edge(u, v,
static_cast<EdgeWeight
>(1.0));
1364 else graph->add_edge(u, v);
1367 graph->edge_properties[graph->get_edge_id(e)][key] = Graph::make_attr_any(val);
1371 template <
typename T>
1372 operator T()
const {
1373 return graph->template get_edge_attr<T>(u, v, key);
1381 EdgeProxy(
Graph* g, NodeID u, NodeID v) : graph(g), u(u), v(v) {}
1384 template <
bool W = Weighted>
1387 graph->add_edge(u, v, w);
1391 template <
bool W = Weighted>
1393 operator EdgeWeight()
const {
1394 return graph->get_edge_weight(u, v);
1397 EdgeAttrProxy operator[](
const std::string& key) {
1398 return {graph, u, v, key};
1401 EdgeAttrProxy operator[](
const char* key) {
1402 return {graph, u, v, std::string(key)};
1415 template <
typename T>
1418 graph->node_properties[u][key] = Graph::make_attr_any(val);
1422 template <
typename T>
1423 operator T()
const {
1424 return graph->template get_node_attr<T>(u, key);
1433 template <
typename T>
1434 operator T()
const {
1435 return graph->template get_edge_attr<T>(u, v, key);
1445 template <
bool W = Weighted>
1447 operator EdgeWeight()
const {
1448 return graph->get_edge_weight(u, v);
1452 return {graph, u, v, key};
1456 return {graph, u, v, std::string(key)};
1489 return {graph, u, key};
1493 return {graph, u, std::string(key)};
1525 throw std::out_of_range(
"Graph::operator[] const: node not found");
1548 [[nodiscard]]
auto bfs_edges(
const NodeID& start)
const;
1567 [[nodiscard]]
auto bfs_tree(
const NodeID& start)
const;
1591 template <
typename Visitor>
1607 template <
typename OnVertex,
typename OnTreeEdge>
1608 void bfs_visit(
const NodeID& start, OnVertex&& on_vertex, OnTreeEdge&& on_tree_edge)
const;
1617 [[nodiscard]]
auto dfs_edges(
const NodeID& start)
const;
1636 [[nodiscard]]
auto dfs_tree(
const NodeID& start)
const;
1671 template <
typename Visitor>
1687 template <
typename OnTreeEdge,
typename OnBackEdge>
1688 void dfs_visit(
const NodeID& start, OnTreeEdge&& on_tree_edge, OnBackEdge&& on_back_edge)
const;
1698 [[nodiscard]]
auto shortest_path(
const NodeID& source_id,
const NodeID& target_id)
const;
1721 [[nodiscard]]
auto shortest_path(
const NodeID& source_id,
const NodeID& target_id,
const std::string& weight)
const;
1730 [[nodiscard]]
double shortest_path_length(
const NodeID& source_id,
const NodeID& target_id)
const;
1753 [[nodiscard]]
double shortest_path_length(
const NodeID& source_id,
const NodeID& target_id,
const std::string& weight)
const;
1763 template <
bool W = Weighted>
1765 [[nodiscard]]
auto dijkstra_path(
const NodeID& source_id,
const NodeID& target_id)
const;
1766 template <
bool W = Weighted>
1782 template <
bool W = Weighted>
1784 [[nodiscard]]
auto dijkstra_path(
const NodeID& source_id,
const NodeID& target_id,
const std::string& weight)
const;
1794 template <
bool W = Weighted>
1805 template <
bool W = Weighted>
1817 template <
bool W = Weighted>
1819 [[nodiscard]]
auto dijkstra_path_length(
const NodeID& source_id,
const NodeID& target_id)
const;
1820 template <
bool W = Weighted>
1836 template <
bool W = Weighted>
1838 [[nodiscard]]
auto dijkstra_path_length(
const NodeID& source_id,
const NodeID& target_id,
const std::string& weight)
const;
1848 template <
bool W = Weighted>
1850 [[nodiscard]]
auto bellman_ford_path(
const NodeID& source_id,
const NodeID& target_id)
const;
1851 template <
bool W = Weighted>
1863 template <
bool W = Weighted>
1876 template <
bool W = Weighted>
1878 [[nodiscard]]
auto bellman_ford_path(
const NodeID& source_id,
const NodeID& target_id,
const std::string& weight)
const;
1888 template <
bool W = Weighted>
1891 template <
bool W = Weighted>
1904 template <
bool W = Weighted>
1906 [[nodiscard]]
auto bellman_ford_path_length(
const NodeID& source_id,
const NodeID& target_id,
const std::string& weight)
const;
1916 template <
bool W = Weighted>
1930 template <
bool W = Weighted>
1944 template <
bool W = Weighted>
1976 template <
bool W = Weighted>
1989 template <
bool W = Weighted>
2000 template <
bool W = Weighted>
2012 template <
bool W = Weighted>
2026 [[nodiscard]]
auto edmonds_karp_maximum_flow(
const NodeID& source_id,
const NodeID& target_id,
const std::string& capacity_attr =
"capacity")
const;
2037 [[nodiscard]]
auto push_relabel_maximum_flow_result(
const NodeID& source_id,
const NodeID& target_id,
const std::string& capacity_attr =
"capacity")
const;
2048 [[nodiscard]]
auto maximum_flow(
const NodeID& source_id,
const NodeID& target_id,
const std::string& capacity_attr =
"capacity")
const;
2059 [[nodiscard]]
auto minimum_cut(
const NodeID& source_id,
const NodeID& target_id,
const std::string& capacity_attr =
"capacity")
const;
2071 [[nodiscard]]
auto max_flow_min_cost_cycle_canceling(
const NodeID& source_id,
const NodeID& target_id,
const std::string& capacity_attr =
"capacity",
const std::string& weight_attr =
"weight")
const;
2073 [[nodiscard]]
long push_relabel_maximum_flow(
const NodeID& source_id,
const NodeID& target_id,
const std::string& capacity_attr =
"capacity",
const std::string& weight_attr =
"weight")
const;
2086 [[nodiscard]]
auto cycle_canceling(
const std::string& weight_attr =
"weight")
const;
2110 [[nodiscard]]
auto max_flow_min_cost_successive_shortest_path(
const NodeID& source_id,
const NodeID& target_id,
const std::string& capacity_attr =
"capacity",
const std::string& weight_attr =
"weight")
const;
2122 [[nodiscard]]
auto max_flow_min_cost(
const NodeID& source_id,
const NodeID& target_id,
const std::string& capacity_attr =
"capacity",
const std::string& weight_attr =
"weight")
const;
2129 [[nodiscard]] std::
size_t num_edges() const noexcept;
2153 [[nodiscard]] auto
pagerank(
double tolerance = 1e-6, std::
size_t max_iterations = 100) const;
2167 void invalidate_min_cost_flow_state()
const {
2169 static_cast<const void*
>(
this)
2173 void clear_min_cost_flow_state()
const {
2174 detail::MinCostFlowCacheHooks<Graph<NodeID, EdgeWeight, Directed, Multi, Weighted, OutEdgeSelector, VertexSelector>>
::clear(
2175 static_cast<const void*
>(
this)
2179 [[nodiscard]]
auto floyd_warshall_matrix_with_order()
const;
2182template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
2184 return static_cast<int>(boost::num_vertices(g));
2187template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
2189 return static_cast<std::size_t
>(boost::num_edges(g));
2193template <
typename GraphWrapper>
2195[[deprecated(
"Use G.num_vertices() instead.")]]
2197 return G.num_vertices();
2200template <
typename GraphWrapper>
2202[[deprecated(
"Use G.num_edges() instead.")]]
2204 return G.num_edges();
Definition graph.hpp:1439
Definition graph.hpp:1471
Definition graph.hpp:1377
Definition graph.hpp:1482
Definition graph.hpp:1460
Graph wrapper around Boost Graph Library with Python-inspired helpers.
Definition graph.hpp:288
const IdMap & get_id_to_bgl_map() const
Returns the maintained node-ID-to-vertex translation table.
Definition graph.hpp:1331
auto bellman_ford_path(const NodeID &source_id, const NodeID &target_id) const
Computes a shortest path using Bellman-Ford and built-in weights.
Definition shortest_paths.hpp:710
auto minimum_spanning_tree() const
Convenience alias for kruskal_minimum_spanning_tree().
Definition spanning_tree.hpp:112
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
void add_nodes_from(const std::vector< NodeID > &nodes)
Adds a batch of nodes from a vector of node IDs.
Definition graph.hpp:751
auto edmonds_karp_maximum_flow(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity") const
Computes a maximum flow using the Edmonds-Karp algorithm.
Definition flow.hpp:494
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
void add_edges_from(const std::vector< std::pair< NodeID, NodeID > > &edges)
Adds a batch of unweighted edges from (u, v) pairs.
Definition graph.hpp:937
auto successive_shortest_path_nonnegative_weights(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight") const
Computes a max-flow min-cost result using successive shortest path.
Definition flow.hpp:672
auto dijkstra_path(const NodeID &source_id, const NodeID &target_id) const
Computes the shortest path using the built-in edge-weight property.
Definition shortest_paths.hpp:449
auto bellman_ford_shortest_paths(const NodeID &source_id) const
Returns distances and predecessors for all nodes using Bellman-Ford.
Definition shortest_paths.hpp:742
std::size_t num_edges() const noexcept
Returns the number of edges currently stored in the graph without materializing the edge list.
Definition graph.hpp:2188
auto dijkstra_path_length(const NodeID &source_id) const
Returns built-in-weight shortest-path distances from a source node.
Definition shortest_paths.hpp:533
auto dfs_predecessors(const NodeID &start) const
Returns the DFS predecessor assigned to each discovered node.
Definition traversal.hpp:671
bool has_node_attr(const NodeID &u, const std::string &key) const
Returns whether a node has the named attribute.
Definition attributes.hpp:114
auto dijkstra_shortest_paths(const NodeID &source_id) const
Returns distances and predecessors for all nodes reachable from a source.
Definition shortest_paths.hpp:499
auto bfs_tree(const NodeID &start) const
Materializes the breadth-first-search tree rooted at start.
Definition traversal.hpp:579
std::vector< std::tuple< NodeID, NodeID, EdgeWeight > > weighted_edges() const
Returns all weighted edges as (u, v, w) tuples.
Definition graph.hpp:1316
auto pagerank(double tolerance=1e-6, std::size_t max_iterations=100) const
Computes PageRank scores for every node.
Definition centrality.hpp:50
void set_edge_attr(std::size_t edge_id, const std::string &key, const T &value)
Stores a typed attribute on an edge identified by edge ID.
Definition multigraph.hpp:184
auto bfs_edges_view(const NodeID &start) const
Returns a lazy input range over breadth-first-search tree edges.
Definition traversal.hpp:570
EdgeDesc get_edge_desc(const NodeID &u, const NodeID &v) const
Returns the underlying Boost edge descriptor for an existing edge.
Definition graph.hpp:763
void remove_edge(const NodeID &u, const NodeID &v)
Removes all edges between two endpoints.
Definition graph.hpp:997
const AttrMap & edge_attrs(std::size_t edge_id) const
Returns the user-defined attributes stored on an edge ID, or an empty map.
Definition graph.hpp:1339
std::vector< NodeID > neighbors(const NodeID &u) const
Returns the outgoing neighbors of a node.
Definition graph.hpp:1121
std::pair< NodeID, NodeID > get_edge_endpoints(std::size_t edge_id) const
Returns the endpoints of an edge identified by its wrapper-managed ID.
Definition multigraph.hpp:40
auto strongly_connected_component_roots() const
Returns one representative root node for each strong component.
Definition components.hpp:233
T get_node_attr(const NodeID &u, const std::string &key) const
Reads a typed node attribute.
Definition attributes.hpp:146
auto max_flow_min_cost(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight") const
Convenience alias for the default max-flow min-cost wrapper.
Definition flow.hpp:704
Graph subgraph(std::initializer_list< NodeID > selected_nodes) const
Convenience overload for braced node lists such as G.subgraph({"A", "B"}).
Definition graph.hpp:984
std::vector< NodeID > predecessors(const NodeID &u) const
Returns predecessor nodes for directed graphs.
Definition graph.hpp:1144
void bfs_visit(const NodeID &start, OnVertex &&on_vertex, OnTreeEdge &&on_tree_edge) const
Runs breadth-first search with lightweight callback hooks.
Definition traversal.hpp:618
auto num_vertices() const noexcept
Returns the number of vertices currently stored in the graph.
Definition graph.hpp:2183
auto betweenness_centrality() const
Computes normalized betweenness centrality for every node.
Definition centrality.hpp:133
std::vector< NodeID > nodes() const
Returns all node IDs currently stored in the graph.
Definition graph.hpp:1283
auto prim_minimum_spanning_tree(const NodeID &root_id) const
Returns the parent map produced by Prim's minimum-spanning-tree algorithm.
Definition spanning_tree.hpp:90
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
auto dfs_edges_view(const NodeID &start) const
Returns a lazy input range over depth-first-search tree edges.
Definition traversal.hpp:653
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
void dfs_visit(const NodeID &start, OnTreeEdge &&on_tree_edge, OnBackEdge &&on_back_edge) const
Runs depth-first search with lightweight callback hooks.
Definition traversal.hpp:712
auto dfs_successors(const NodeID &start) const
Groups DFS tree children by their discovered parent.
Definition traversal.hpp:681
auto bfs_edges(const NodeID &start) const
Returns the tree edges discovered by breadth-first search.
Definition traversal.hpp:555
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
bool has_node(const NodeID &u) const
Returns whether the graph already contains the given node ID.
Definition graph.hpp:1164
const std::vector< NodeID > & get_bgl_to_id_map() const
Returns the maintained vertex-index-to-node-ID translation table.
Definition graph.hpp:1329
void depth_first_search(const NodeID &start, Visitor &visitor) const
Runs depth-first search with an object-style visitor.
Definition traversal.hpp:696
auto max_flow_min_cost_successive_shortest_path(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight") const
Convenience alias for successive_shortest_path_nonnegative_weights().
Definition flow.hpp:699
void add_node(const NodeID &id)
Ensures that a node with the given ID exists in the graph.
Definition graph.hpp:740
auto minimum_cut(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity") const
Computes a minimum cut between source and target using the named capacity attribute.
Definition flow.hpp:543
auto maximum_flow(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity") const
Computes the maximum flow value and edge assignments using the named capacity attribute.
Definition flow.hpp:540
auto topological_sort() const
Returns a topological ordering for a directed acyclic graph.
Definition topological_sort.hpp:29
auto dag_shortest_paths(const NodeID &source_id) const
Returns shortest-path distances in a directed acyclic graph.
Definition shortest_paths.hpp:828
const GraphType & get_impl() const
Exposes the underlying Boost graph for advanced integrations.
Definition graph.hpp:1327
auto strongly_connected_component_map() const
Alias for strong_component_map().
Definition components.hpp:230
void clear()
Clears the entire graph and all wrapper-managed metadata.
Definition graph.hpp:950
std::size_t get_vertex_index(VertexDesc v) const
Returns the wrapper-maintained dense vertex index used by algorithms.
Definition graph.hpp:1347
void breadth_first_search(const NodeID &start, Visitor &visitor) const
Runs breadth-first search with an object-style visitor.
Definition traversal.hpp:603
auto connected_component_groups() const
Groups each connected component as a vector of node IDs.
Definition components.hpp:136
long push_relabel_maximum_flow(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight") const
Runs push-relabel and stages residual state for a later cycle_canceling() call. Any later graph mutat...
Definition flow.hpp:619
const AttrMap & node_attrs(const NodeID &u) const
Returns the user-defined attributes stored on a node, or an empty map.
Definition graph.hpp:1333
auto dfs_edges(const NodeID &start) const
Returns the tree edges discovered by depth-first search.
Definition traversal.hpp:632
auto bfs_successors(const NodeID &start) const
Groups BFS tree children by their discovered parent.
Definition traversal.hpp:588
void remove_node(const NodeID &u)
Removes a node and all of its incident edges.
Definition graph.hpp:1051
auto cycle_canceling(const std::string &weight_attr="weight") const
Runs cycle canceling on the previously cached residual network.
Definition flow.hpp:649
const NodeID & get_node_id(VertexDesc v) const
Returns the wrapper-side node ID associated with a Boost vertex descriptor.
Definition graph.hpp:1345
void remove_nodes_from(const std::vector< NodeID > &nodes)
Removes a batch of nodes and all of their incident edges.
Definition graph.hpp:1079
auto connected_component_map() const
Returns the connected-component index assigned to each node.
Definition components.hpp:224
auto strong_component_map() const
Returns the component index assigned to each node in a directed graph.
Definition components.hpp:190
auto bellman_ford_path_length(const NodeID &source_id, const NodeID &target_id) const
Returns the Bellman-Ford shortest-path length with built-in weights.
Definition shortest_paths.hpp:798
std::vector< std::size_t > edge_ids() const
Returns all wrapper-managed edge IDs currently present in the graph.
Definition multigraph.hpp:21
auto max_flow_min_cost_cycle_canceling(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity", const std::string &weight_attr="weight") const
Computes a max-flow min-cost result using cycle canceling.
Definition flow.hpp:589
bool has_edge_id(std::size_t edge_id) const
Returns whether an edge with the given wrapper-managed ID exists.
Definition multigraph.hpp:16
auto degree_centrality() const
Computes normalized degree centrality for every node.
Definition centrality.hpp:20
std::vector< std::pair< NodeID, NodeID > > edge_pairs() const
Compatibility alias for edges().
Definition graph.hpp:1309
auto strong_components() const
Returns the number of strongly connected components in a directed graph.
Definition components.hpp:206
auto dfs_tree(const NodeID &start) const
Materializes the depth-first-search tree rooted at start.
Definition traversal.hpp:662
bool has_edge(const NodeID &u, const NodeID &v) const
Returns whether at least one edge exists between two endpoints.
Definition graph.hpp:779
auto shortest_path(const NodeID &source_id, const NodeID &target_id) const
Computes an unweighted shortest path between two nodes.
Definition shortest_paths.hpp:345
auto kruskal_minimum_spanning_tree() const
Returns the edges selected by Kruskal's minimum-spanning-tree algorithm.
Definition spanning_tree.hpp:78
std::vector< NodeID > successors(const NodeID &u) const
Alias for neighbors(), mainly to mirror directed-graph terminology.
Definition graph.hpp:1134
auto connected_components() const
Returns a node-to-component-label map for an undirected graph.
Definition components.hpp:155
auto floyd_warshall_all_pairs_shortest_paths_map() const
Returns all-pairs shortest-path distances keyed by node IDs.
Definition shortest_paths.hpp:907
std::vector< std::pair< NodeID, NodeID > > edges() const
Returns the public edge list.
Definition graph.hpp:1298
auto push_relabel_maximum_flow_result(const NodeID &source_id, const NodeID &target_id, const std::string &capacity_attr="capacity") const
Computes a maximum flow using push-relabel and returns edge assignments.
Definition flow.hpp:517
auto floyd_warshall_all_pairs_shortest_paths() const
Returns all-pairs shortest-path distances as a dense matrix.
Definition shortest_paths.hpp:898
Graph subgraph(const NodeRange &selected_nodes) const
Returns a materialized node-induced subgraph.
Definition graph.hpp:979
NodeAttrBaseProxy node(const NodeID &u)
Returns the proxy used for G.node(u)[key] node-attribute syntax.
Definition graph.hpp:1535
NodeProxy operator[](const NodeID &u)
Returns the proxy used for G[u][v] edge-access syntax.
Definition graph.hpp:1510
auto strongly_connected_component_groups() const
Groups each strongly connected component as a vector of node IDs.
Definition components.hpp:171
double shortest_path_length(const NodeID &source_id, const NodeID &target_id) const
Returns the length of an unweighted shortest path.
Definition shortest_paths.hpp:418
ConstNodeProxy operator[](const NodeID &u) const
Returns a non-mutating proxy for G[u][v] on const graphs.
Definition graph.hpp:1523
auto strongly_connected_components() const
Alias for strongly_connected_component_groups().
Definition components.hpp:227
const Value & operator[](const Key &key) const
Reads an existing value; this wrapper never inserts through operator[].
Definition graph.hpp:207
indexed_lookup_map()=default
Default-constructs an empty ordered lookup map.
const Value & operator[](const Key &key) const
Reads an existing value in const contexts; throws like at() if missing.
Definition graph.hpp:134
Minimal visitor interface for wrapper-level traversal callbacks.
Definition traversal.hpp:225
auto num_vertices(const GraphWrapper &G)
Deprecated free-function alias for num_vertices().
Definition graph.hpp:2196
auto num_edges(const GraphWrapper &G)
Deprecated free-function alias for num_edges().
Definition graph.hpp:2203
WeightMode
Explicit source-target shortest-path weighting mode.
Definition graph.hpp:117
Definition graph.hpp:1428
Definition graph.hpp:1350
EdgeAttrProxy & operator=(const T &val)
Sets attribute key on edge (u,v), creating the edge if it does not exist.
Definition graph.hpp:1361
Definition graph.hpp:1406
NodeAttrProxy & operator=(const T &val)
Sets attribute key on node u, creating the node if it does not exist.
Definition graph.hpp:1416