NuriKit v0.1.0b2
Loading...
Searching...
No Matches
subgraph.h
Go to the documentation of this file.
1//
2// Project NuriKit - Copyright 2025 SNU Compbio Lab.
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#ifndef NURI_CORE_GRAPH_SUBGRAPH_H_
7#define NURI_CORE_GRAPH_SUBGRAPH_H_
8
10#include <cstddef>
11#include <iterator>
12#include <stack>
13#include <type_traits>
14#include <utility>
15#include <vector>
16
17#include <boost/iterator/iterator_facade.hpp>
18#include <Eigen/Dense>
20
21#include "nuri/eigen_config.h"
25#include "nuri/iterator.h"
26#include "nuri/meta.h"
27
28namespace nuri {
29namespace internal {
30 template <class SGT, bool is_const>
31 class SubNodeWrapper {
32 public:
33 using DT = typename SGT::node_data_type;
34
35 using parent_type = const_if_t<is_const, SGT>;
36 using value_type = const_if_t<is_const, DT>;
37
38 using adjacency_iterator =
39 std::conditional_t<is_const, typename SGT::const_adjacency_iterator,
40 typename SGT::adjacency_iterator>;
41
42 template <bool other_const>
43 using Other = SubNodeWrapper<SGT, other_const>;
44
45 static_assert(!GraphTraits<SGT>::is_const || is_const,
46 "Cannot create non-const SubNodeWrapper from const "
47 "Subgraph");
48
49 constexpr SubNodeWrapper(int idx, parent_type &subgraph) noexcept
50 : idx_(idx), subgraph_(&subgraph) { }
51
52 template <bool other_const,
53 std::enable_if_t<is_const && !other_const, int> = 0>
54 constexpr SubNodeWrapper(const Other<other_const> &other) noexcept
55 : idx_(other.idx_), subgraph_(other.subgraph_) { }
56
57 constexpr int id() const noexcept { return idx_; }
58
59 constexpr value_type &data() const noexcept {
60 return subgraph_->node_data(idx_);
61 }
62
63 constexpr int degree() const noexcept { return subgraph_->degree(idx_); }
64
65 adjacency_iterator begin() const noexcept {
66 return subgraph_->adj_begin(idx_);
67 }
68
69 adjacency_iterator end() const noexcept { return subgraph_->adj_end(idx_); }
70
71 adjacency_iterator
72 find_adjacent(SubNodeWrapper<SGT, true> node) const noexcept {
73 return subgraph_->find_adjacent(*this, node);
74 }
75
76 constexpr Other<true> as_const() const noexcept { return *this; }
77
78 NodeWrapper<typename SGT::graph_type, is_const> as_parent() const noexcept {
79 return subgraph_->parent_node(idx_);
80 }
81
82 private:
83 template <class, bool>
84 friend class SubNodeWrapper;
85
86 int idx_;
87 parent_type *subgraph_;
88 };
89
90 template <class SGT, bool is_const>
91 class SubNodeIterator
92 : public DataIteratorBase<SubNodeIterator<SGT, is_const>, SGT,
93 SubNodeWrapper<SGT, is_const>, is_const> {
94 using Base = typename SubNodeIterator::Parent;
95
96 public:
97 using typename Base::difference_type;
98 using typename Base::iterator_category;
99 using typename Base::pointer;
100 using typename Base::reference;
101 using typename Base::value_type;
102
103 static_assert(!GraphTraits<SGT>::is_const || is_const,
104 "Cannot create non-const SubNodeIterator from const "
105 "Subgraph");
106
107 using Base::Base;
108
109 // Might look strange, but this is to provide all comparisons between
110 // all types of iterators (due to boost implementation). However, they
111 // could not be really constructed, so we static_assert to prevent misuse.
112
113 template <
114 class SGU, bool other_const,
115 std::enable_if_t<
116 !std::is_same_v<SGT, SGU> || (is_const && !other_const), int> = 0>
117 constexpr SubNodeIterator(
118 const SubNodeIterator<SGU, other_const> &other) noexcept
119 : Base(other) {
120 static_assert(std::is_same_v<SGT, SGU>,
121 "Cannot copy-construct SubNodeIterator from different "
122 "Subgraphs");
123 }
124
125 template <
126 class SGU, bool other_const,
127 std::enable_if_t<
128 !std::is_same_v<SGT, SGU> || (is_const && !other_const), int> = 0>
129 constexpr SubNodeIterator &
130 operator=(const SubNodeIterator<SGU, other_const> &other) noexcept {
131 static_assert(std::is_same_v<SGT, SGU>,
132 "Cannot copy-assign SubNodeIterator from different "
133 "Subgraphs");
134
135 Base::operator=(other);
136 return *this;
137 }
138
139 private:
140 friend Base;
141
142 friend class boost::iterator_core_access;
143
144 template <class, bool>
145 friend class SubNodeIterator;
146
147 constexpr reference dereference() const noexcept {
148 return this->graph().node(this->index());
149 }
150
151 template <class SGU, bool other_const,
152 std::enable_if_t<std::is_same_v<typename SGT::graph_type,
153 typename SGU::graph_type>,
154 int> = 0>
155 constexpr bool
156 equal(const SubNodeIterator<SGU, other_const> &other) const noexcept {
157 return this->index() == other.index();
158 }
159
160 template <class SGU, bool other_const,
161 std::enable_if_t<std::is_same_v<typename SGT::graph_type,
162 typename SGU::graph_type>,
163 int> = 0>
164 constexpr difference_type
165 distance_to(const SubNodeIterator<SGU, other_const> &other) const noexcept {
166 return other.index() - this->index();
167 }
168 };
169
170 template <class SGT, bool is_const>
171 class SubAdjWrapper {
172 public:
173 using edge_value_type = const_if_t<is_const, typename SGT::edge_data_type>;
174 using parent_type = const_if_t<is_const, SGT>;
175
176 template <bool other_const>
177 using Other = SubAdjWrapper<SGT, other_const>;
178
179 constexpr SubAdjWrapper(parent_type &graph, int src, int dst,
180 int eid) noexcept
181 : src_(src), dst_(dst), eid_(eid), graph_(&graph) { }
182
183 template <bool other_const,
184 std::enable_if_t<is_const && !other_const, int> = 0>
185 constexpr SubAdjWrapper(const Other<other_const> &other) noexcept
186 : src_(other.src_), dst_(other.dst_), eid_(other.eid_),
187 graph_(other.graph_) { }
188
189 constexpr auto src() const noexcept { return graph_->node(src_); }
190 constexpr auto dst() const noexcept { return graph_->node(dst_); }
191
192 constexpr int eid() const noexcept { return eid_; }
193 constexpr edge_value_type &edge_data() const noexcept {
194 return graph_->edge_data(eid_);
195 }
196
197 constexpr Other<true> as_const() const noexcept { return *this; }
198
199 constexpr auto as_parent() const noexcept {
200 return internal::AdjWrapper<typename SGT::graph_type, is_const>(
201 graph_->parent(), graph_->parent_node(src_).id(),
202 graph_->parent_node(dst_).id(), graph_->parent_edge(eid_).id());
203 }
204
205 private:
206 template <class, bool>
207 friend class SubAdjWrapper;
208
209 template <class, bool>
210 friend class SubAdjIterator;
211
212 friend SGT;
213
214 int src_;
215 int dst_;
216 int eid_;
217 parent_type *graph_;
218 };
219
220 template <class SGT, bool is_const>
221 class SubAdjIterator
222 : public ProxyIterator<SubAdjIterator<SGT, is_const>,
223 SubAdjWrapper<SGT, is_const>,
224 std::bidirectional_iterator_tag, int> {
225 using parent_nonconst_adjacency_iterator =
226 typename SGT::graph_type::adjacency_iterator;
227 using parent_const_adjacency_iterator =
228 typename SGT::graph_type::const_adjacency_iterator;
229
230 using parent_adjacency_iterator =
231 std::conditional_t<is_const, parent_const_adjacency_iterator,
232 parent_nonconst_adjacency_iterator>;
233
234 using Traits =
235 std::iterator_traits<typename SubAdjIterator::iterator_facade_>;
236
237 public:
238 using parent_type = const_if_t<is_const, SGT>;
239
240 using iterator_category = typename Traits::iterator_category;
241 using value_type = typename Traits::value_type;
242 using difference_type = typename Traits::difference_type;
243 using pointer = typename Traits::pointer;
244 using reference = typename Traits::reference;
245
246 static_assert(!GraphTraits<SGT>::is_const || is_const,
247 "Cannot create non-const SubAdjIterator from const "
248 "Subgraph");
249
250 constexpr SubAdjIterator() = default;
251
252 constexpr SubAdjIterator(parent_type &subgraph, int src,
253 int parent_idx) noexcept
254 : subgraph_(&subgraph), src_(src), parent_idx_(parent_idx) {
255 find_next();
256 }
257
258 // Might look strange, but this is to provide all comparisons between
259 // all types of iterators (due to boost implementation). However, they
260 // could not be really constructed, so we static_assert to prevent misuse.
261
262 template <
263 class SGU, bool other_const,
264 std::enable_if_t<
265 !std::is_same_v<SGT, SGU> || (is_const && !other_const), int> = 0>
266 constexpr SubAdjIterator(
267 const SubAdjIterator<SGU, other_const> &other) noexcept
268 : subgraph_(other.subgraph_), src_(other.src_), dst_(other.dst_),
269 eid_(other.eid_), parent_idx_(other.parent_idx_) {
270 static_assert(std::is_same_v<SGT, SGU>,
271 "Cannot copy-construct SubAdjIterator from different "
272 "Subgraphs");
273 }
274
275 template <
276 class SGU, bool other_const,
277 std::enable_if_t<
278 !std::is_same_v<SGT, SGU> || (is_const && !other_const), int> = 0>
279 constexpr SubAdjIterator &
280 operator=(const SubAdjIterator<SGU, other_const> &other) noexcept {
281 static_assert(std::is_same_v<SGT, SGU>,
282 "Cannot copy-assign SubAdjIterator from different "
283 "Subgraphs");
284
285 subgraph_ = other.subgraph_;
286 src_ = other.src_;
287 dst_ = other.dst_;
288 eid_ = other.eid_;
289 parent_idx_ = other.parent_idx_;
290 return *this;
291 }
292
293 bool begin() const noexcept { return parent_idx_ <= 0; }
294
295 bool end() const noexcept {
296 return parent_idx_ >= subgraph_->parent_node(src_).degree();
297 }
298
299 private:
300 friend SGT;
301
302 template <class, bool>
303 friend class SubAdjIterator;
304
305 friend class boost::iterator_core_access;
306
307 constexpr SubAdjIterator(parent_type &subgraph, int src, int dst, int eid,
308 int parent_idx) noexcept
309 : subgraph_(&subgraph), src_(src), dst_(dst), eid_(eid),
310 parent_idx_(parent_idx) { }
311
312 auto parent_iter() const {
313 return subgraph_->parent_node(src_).begin() + parent_idx_;
314 }
315
316 // NOT an iterator_facade interface; see constructor for why we need this
317 // as a separate function.
318 void find_next() {
319 for (auto ait = parent_iter(); !ait.end(); ++ait, ++parent_idx_) {
320 auto nit = subgraph_->find_node(ait->dst());
321 auto eit = subgraph_->find_edge(ait->eid());
322 if (nit != subgraph_->node_end() && eit != subgraph_->edge_end()) {
323 dst_ = nit->id();
324 eid_ = eit->id();
325 return;
326 }
327 }
328 }
329
330 reference dereference() const noexcept {
331 return { *subgraph_, src_, dst_, eid_ };
332 }
333
334 template <class SGU, bool other_const>
335 bool equal(const SubAdjIterator<SGU, other_const> &other) const noexcept {
336 return parent_idx_ == other.parent_idx_;
337 }
338
339 void increment() {
340 ++parent_idx_;
341 find_next();
342 }
343
344 void decrement() {
345 --parent_idx_;
346 for (auto ait = parent_iter(); parent_idx_ >= 0; --ait, --parent_idx_) {
347 auto nit = subgraph_->find_node(ait->dst());
348 auto eit = subgraph_->find_edge(ait->eid());
349 if (nit != subgraph_->node_end() && eit != subgraph_->edge_end()) {
350 dst_ = nit->id();
351 eid_ = eit->id();
352 return;
353 }
354 }
355 }
356
357 parent_type *subgraph_;
358 int src_;
359 int dst_;
360 int eid_;
361 int parent_idx_;
362 };
363
364 template <class SGT, bool is_const>
365 class SubEdgeWrapper {
366 public:
367 using DT = typename SGT::edge_data_type;
368
369 using parent_type = const_if_t<is_const, SGT>;
370 using value_type = const_if_t<is_const, DT>;
371
372 template <bool other_const>
373 using Other = SubEdgeWrapper<SGT, other_const>;
374
375 static_assert(!GraphTraits<SGT>::is_const || is_const,
376 "Cannot create non-const SubEdgeWrapper from const "
377 "Subgraph");
378
379 constexpr SubEdgeWrapper(int src, int dst, int eid,
380 parent_type &subgraph) noexcept
381 : src_(src), dst_(dst), eid_(eid), subgraph_(&subgraph) { }
382
383 template <bool other_const,
384 std::enable_if_t<is_const && !other_const, int> = 0>
385 constexpr SubEdgeWrapper(const Other<other_const> &other) noexcept
386 : src_(other.src_), dst_(other.dst_), eid_(other.eid_),
387 subgraph_(other.subgraph_) { }
388
389 constexpr auto id() const noexcept { return eid_; }
390
391 constexpr auto src() const noexcept { return subgraph_->node(src_); }
392 constexpr auto dst() const noexcept { return subgraph_->node(dst_); }
393
394 constexpr value_type &data() const noexcept {
395 return subgraph_->edge_data(eid_);
396 }
397
398 constexpr Other<true> as_const() const noexcept { return *this; }
399
400 EdgeWrapper<typename SGT::graph_type, is_const> as_parent() const noexcept {
401 return subgraph_->parent_edge(eid_);
402 }
403
404 private:
405 template <class, bool>
406 friend class SubEdgeWrapper;
407
408 template <class, bool>
409 friend class SubEdgeIterator;
410
411 int src_;
412 int dst_;
413 int eid_;
414 parent_type *subgraph_;
415 };
416
417 template <class SGT, bool is_const>
418 class SubEdgeIterator
419 : public DataIteratorBase<SubEdgeIterator<SGT, is_const>, SGT,
420 SubEdgeWrapper<SGT, is_const>, is_const> {
421 using Base = typename SubEdgeIterator::Parent;
422
423 public:
424 using typename Base::difference_type;
425 using typename Base::iterator_category;
426 using typename Base::pointer;
427 using typename Base::reference;
428 using typename Base::value_type;
429
430 static_assert(!GraphTraits<SGT>::is_const || is_const,
431 "Cannot create non-const SubEdgeIterator from const "
432 "Subgraph");
433
434 using Base::Base;
435
436 // Might look strange, but this is to provide all comparisons between
437 // all types of iterators (due to boost implementation). However, they
438 // could not be really constructed, so we static_assert to prevent misuse.
439
440 template <
441 class SGU, bool other_const,
442 std::enable_if_t<
443 !std::is_same_v<SGT, SGU> || (is_const && !other_const), int> = 0>
444 constexpr SubEdgeIterator(
445 const SubEdgeIterator<SGU, other_const> &other) noexcept
446 : Base(other) {
447 static_assert(std::is_same_v<SGT, SGU>,
448 "Cannot copy-construct SubEdgeIterator from different "
449 "Subgraph");
450 }
451
452 template <
453 class SGU, bool other_const,
454 std::enable_if_t<
455 !std::is_same_v<SGT, SGU> || (is_const && !other_const), int> = 0>
456 constexpr SubEdgeIterator &
457 operator=(const SubEdgeIterator<SGU, other_const> &other) noexcept {
458 static_assert(std::is_same_v<SGT, SGU>,
459 "Cannot copy-assign SubEdgeIterator from different "
460 "Subgraph");
461
462 Base::operator=(other);
463 return *this;
464 }
465
466 private:
467 friend Base;
468
469 friend class boost::iterator_core_access;
470
471 template <class, bool>
472 friend class SubEdgeIterator;
473
474 template <class SGU, bool other_const,
475 std::enable_if_t<std::is_same_v<typename SGT::graph_type,
476 typename SGU::graph_type>,
477 int> = 0>
478 constexpr bool
479 equal(const SubEdgeIterator<SGU, other_const> &other) const noexcept {
480 return this->index() == other.index();
481 }
482
483 template <class SGU, bool other_const,
484 std::enable_if_t<std::is_same_v<typename SGT::graph_type,
485 typename SGU::graph_type>,
486 int> = 0>
487 constexpr difference_type
488 distance_to(const SubEdgeIterator<SGU, other_const> &other) const noexcept {
489 return other.index() - this->index();
490 }
491
492 reference dereference() const noexcept {
493 return this->graph().edge(this->index());
494 }
495 };
496
497 template <class GT>
498 IndexSet find_nodes(GT &parent, const IndexSet &edges) {
499 std::vector<int> nodes;
500 nodes.reserve(static_cast<size_t>(edges.size()) * 2);
501
502 for (auto i: edges) {
503 nodes.push_back(parent.edge(i).src().id());
504 nodes.push_back(parent.edge(i).dst().id());
505 }
506
507 return IndexSet(std::move(nodes));
508 }
509
510 template <class GT>
511 IndexSet find_edges(GT &parent, const IndexSet &nodes) {
512 std::vector<int> edges;
513 std::stack<int, std::vector<int>> stack;
514 ArrayXb visited = ArrayXb::Zero(static_cast<int>(nodes.size()));
515
516 for (int i = 0; i < nodes.size(); ++i) {
517 if (visited[i])
518 continue;
519
520 visited[i] = true;
521 stack.push(i);
522
523 do {
524 int u = nodes[stack.top()];
525 stack.pop();
526
527 for (auto nei: parent[u]) {
528 int v = nei.dst().id();
529 int j = nodes.find_index(v);
530 if (j >= nodes.size())
531 continue;
532
533 if (u < v)
534 edges.push_back(nei.eid());
535
536 if (!visited[j]) {
537 visited[j] = true;
538 stack.push(j);
539 }
540 }
541 } while (!stack.empty());
542 }
543
544 return IndexSet(std::move(edges));
545 }
546} // namespace internal
547
574template <class NT, class ET, bool is_const = false>
575class Subgraph {
576public:
578 using parent_type = internal::const_if_t<is_const, graph_type>;
579
580 using node_data_type = NT;
581 using edge_data_type = ET;
582
583 using iterator = internal::SubNodeIterator<Subgraph, is_const>;
585 using const_iterator = internal::SubNodeIterator<Subgraph, true>;
587 using NodeRef = internal::SubNodeWrapper<Subgraph, is_const>;
588 using ConstNodeRef = internal::SubNodeWrapper<Subgraph, true>;
589
590 using edge_iterator = internal::SubEdgeIterator<Subgraph, is_const>;
591 using const_edge_iterator = internal::SubEdgeIterator<Subgraph, true>;
592 using EdgeRef = internal::SubEdgeWrapper<Subgraph, is_const>;
593 using ConstEdgeRef = internal::SubEdgeWrapper<Subgraph, true>;
594 using EdgesWrapper = internal::EdgesWrapper<Subgraph, is_const>;
595 using ConstEdgesWrapper = internal::EdgesWrapper<Subgraph, true>;
596
597 using adjacency_iterator = internal::SubAdjIterator<Subgraph, is_const>;
598 using const_adjacency_iterator = internal::SubAdjIterator<Subgraph, true>;
599 using AdjRef = internal::SubAdjWrapper<Subgraph, is_const>;
600 using ConstAdjRef = internal::SubAdjWrapper<Subgraph, true>;
601
602 static_assert(std::is_same_v<typename iterator::reference, NodeRef>);
603 static_assert(
604 std::is_same_v<typename const_iterator::reference, ConstNodeRef>);
605 static_assert(std::is_same_v<typename edge_iterator::reference, EdgeRef>);
606 static_assert(
607 std::is_same_v<typename const_edge_iterator::reference, ConstEdgeRef>);
608 static_assert(std::is_same_v<typename adjacency_iterator::reference, AdjRef>);
609 static_assert(
610 std::is_same_v<typename const_adjacency_iterator::reference, ConstAdjRef>);
611
612 template <bool other_const>
614
615 Subgraph(graph_type &&graph) = delete;
616
622 Subgraph(parent_type &graph): parent_(&graph) { }
623
639 static Subgraph from_indices(parent_type &graph, internal::IndexSet &&nodes,
640 internal::IndexSet &&edges) {
641 Subgraph subgraph(graph, std::move(nodes), {});
642 subgraph.add_edges(edges);
643 return subgraph;
644 }
645
659 static Subgraph from_nodes(parent_type &graph, internal::IndexSet &&nodes) {
660 internal::IndexSet edges = internal::find_edges(graph, nodes);
661 Subgraph subgraph(graph, std::move(nodes), std::move(edges));
662 return subgraph;
663 }
664
675 static Subgraph from_edges(parent_type &graph, internal::IndexSet &&edges) {
676 internal::IndexSet nodes = internal::find_nodes(graph, edges);
677 Subgraph subgraph(graph, std::move(nodes), std::move(edges));
678 return subgraph;
679 }
680
687 template <bool other_const,
688 std::enable_if_t<is_const && !other_const, int> = 0>
690 : parent_(other.parent_), nodes_(other.nodes_), edges_(other.edges_) { }
691
698 template <bool other_const,
699 std::enable_if_t<is_const && !other_const, int> = 0>
700 Subgraph(Other<other_const> &&other) noexcept
701 : parent_(other.parent_), nodes_(std::move(other.nodes_)),
702 edges_(std::move(other.edges_)) { }
703
710 template <bool other_const,
711 std::enable_if_t<is_const && !other_const, int> = 0>
713 parent_ = other.parent_;
714 nodes_ = other.nodes_;
715 edges_ = other.edges_;
716 return *this;
717 }
718
725 template <bool other_const,
726 std::enable_if_t<is_const && !other_const, int> = 0>
728 parent_ = other.parent_;
729 nodes_ = std::move(other.nodes_);
730 edges_ = std::move(other.edges_);
731 return *this;
732 }
733
739 bool empty() const { return nodes_.empty(); }
740
746 int size() const { return num_nodes(); }
747
753 int num_nodes() const { return static_cast<int>(nodes_.size()); }
754
760 int num_edges() const { return static_cast<int>(edges_.size()); }
761
773 void update(internal::IndexSet &&nodes, internal::IndexSet &&edges) {
774 nodes_ = std::move(nodes);
775
776 edges_.clear();
778 }
779
788 void update_nodes(internal::IndexSet &&nodes) noexcept {
789 nodes_ = std::move(nodes);
790 edges_ = internal::find_edges(*parent_, nodes_);
791 }
792
802 void update_edges(internal::IndexSet &&edges) noexcept {
803 edges_ = std::move(edges);
804 nodes_ = internal::find_nodes(*parent_, edges_);
805 }
806
815 void refresh_edges() { edges_ = internal::find_edges(*parent_, nodes_); }
816
824 void clear() noexcept {
825 nodes_.clear();
826 edges_.clear();
827 }
828
834 void clear_edges() noexcept { edges_.clear(); }
835
841 void reserve_nodes(int num_nodes) { nodes_.reserve(num_nodes); }
842
848 void reserve_edges(int num_edges) { edges_.reserve(num_edges); }
849
859 void add_node(int id) { nodes_.insert(id); }
860
870 void add_edge(int id) {
871 auto [_, added] = edges_.insert(id);
872 if (added) {
873 auto edge = parent_->edge(id);
874 nodes_.insert(edge.src().id());
875 nodes_.insert(edge.dst().id());
876 }
877 }
878
886 void add_nodes(const internal::IndexSet &nodes) { nodes_.union_with(nodes); }
887
896 void add_edges(const internal::IndexSet &edges) {
897 edges_.union_with(edges);
898
899 auto new_nodes = internal::find_nodes(*parent_, edges);
900 nodes_.union_with(new_nodes);
901 }
902
910 void add_nodes_with_edges(const internal::IndexSet &nodes) {
911 add_nodes(nodes);
912 auto new_edges = internal::find_edges(*parent_, nodes);
913 edges_.union_with(new_edges);
914 }
915
923 bool contains_node(int id) const { return nodes_.contains(id); }
924
934 return contains_node(node.id());
935 }
936
944 bool contains_edge(int id) const { return edges_.contains(id); }
945
955 return contains_edge(edge.id());
956 }
957
964 NodeRef operator[](int idx) { return node(idx); }
965
972 ConstNodeRef operator[](int idx) const { return node(idx); }
973
980 NodeRef node(int idx) { return { idx, *this }; }
981
988 ConstNodeRef node(int idx) const { return { idx, *this }; }
989
998 EdgeRef edge(int idx) {
999 auto pedge = parent_edge(idx);
1000 int src = nodes_.find_index(pedge.src().id()),
1001 dst = nodes_.find_index(pedge.dst().id());
1002 return { src, dst, idx, *this };
1003 }
1004
1013 ConstEdgeRef edge(int idx) const {
1014 auto pedge = parent_edge(idx);
1015 int src = nodes_.find_index(pedge.src().id()),
1016 dst = nodes_.find_index(pedge.dst().id());
1017 return { src, dst, idx, *this };
1018 }
1019
1026 internal::const_if_t<is_const, NT> &node_data(int idx) {
1027 return parent_->node_data(nodes_[idx]);
1028 }
1029
1036 const NT &node_data(int idx) const { return parent_->node_data(nodes_[idx]); }
1037
1044 internal::const_if_t<is_const, ET> &edge_data(int idx) {
1045 return parent_->edge_data(edges_[idx]);
1046 }
1047
1054 const ET &edge_data(int idx) const { return parent_->edge_data(edges_[idx]); }
1055
1062 std::conditional_t<is_const, typename parent_type::ConstNodeRef,
1063 typename parent_type::NodeRef>
1064 parent_node(int idx) {
1065 return parent_->node(nodes_[idx]);
1066 }
1067
1074 typename parent_type::ConstNodeRef parent_node(int idx) const {
1075 return parent_->node(nodes_[idx]);
1076 }
1077
1084 std::conditional_t<is_const, typename parent_type::ConstEdgeRef,
1085 typename parent_type::EdgeRef>
1086 parent_edge(int idx) {
1087 return parent_->edge(edges_[idx]);
1088 }
1089
1096 typename parent_type::ConstEdgeRef parent_edge(int idx) const {
1097 return parent_->edge(edges_[idx]);
1098 }
1099
1107 iterator find_node(int id) { return begin() + nodes_.find_index(id); }
1108
1118 return find_node(node.id());
1119 }
1120
1129 return begin() + nodes_.find_index(id);
1130 }
1131
1141 return find_node(node.id());
1142 }
1143
1152 return edge_begin() + edges_.find_index(id);
1153 }
1154
1166
1175 return edge_begin() + edges_.find_index(id);
1176 }
1177
1187 return find_edge(edge.id());
1188 }
1189
1198 void erase_node(int idx) {
1199 std::vector<int> erased_edges;
1200 for (auto nei: node(idx))
1201 erased_edges.push_back(nei.as_parent().eid());
1202 nodes_.erase(nodes_.begin() + idx);
1203 edges_.difference(internal::IndexSet(std::move(erased_edges)));
1204 }
1205
1214
1222 void erase_edge(int idx) { edges_.erase(edges_.begin() + idx); }
1223
1232
1243 std::vector<int> erased_edges;
1244 for (auto it = begin; it != end; ++it)
1245 for (auto nei: *it)
1246 erased_edges.push_back(nei.as_parent().eid());
1247
1248 nodes_.erase(begin - this->begin() + nodes_.begin(),
1249 end - this->begin() + nodes_.begin());
1250 edges_.difference(internal::IndexSet(std::move(erased_edges)));
1251 }
1252
1261 edges_.erase(begin - this->edge_begin() + edges_.begin(),
1262 end - this->edge_begin() + edges_.begin());
1263 }
1264
1273 void erase_node_of(int id) {
1274 int idx = nodes_.find_index(id);
1275 if (idx < num_nodes())
1276 erase_node(idx);
1277 }
1278
1288 erase_node_of(node.id());
1289 }
1290
1298 void erase_edge_of(int id) { edges_.erase(id); }
1299
1308 erase_edge_of(edge.id());
1309 }
1310
1319 template <class UnaryPred>
1320 void erase_nodes_if(UnaryPred pred) {
1321 std::vector<int> erased_nodes, erased_edges;
1322
1323 for (int i = 0; i < num_nodes(); ++i) {
1324 if (!pred(nodes_[i]))
1325 continue;
1326
1327 erased_nodes.push_back(nodes_[i]);
1328 for (auto nei: node(i))
1329 erased_edges.push_back(nei.as_parent().eid());
1330 }
1331
1332 nodes_.difference(internal::IndexSet(std::move(erased_nodes)));
1333 edges_.difference(internal::IndexSet(std::move(erased_edges)));
1334 }
1335
1343 template <class UnaryPred>
1344 void erase_edges_if(UnaryPred &&pred) {
1345 edges_.erase_if(std::forward<UnaryPred>(pred));
1346 }
1347
1359 void remap(const std::vector<int> &node_map,
1360 const std::vector<int> &edge_map) {
1361 nodes_.remap(node_map);
1362 edges_.remap(edge_map);
1363 }
1364
1376 void remap_nodes(const std::vector<int> &node_map) { nodes_.remap(node_map); }
1377
1386 void remap_edges(const std::vector<int> &old_to_new) {
1387 edges_.remap(old_to_new);
1388 }
1389
1390 iterator begin() { return { *this, 0 }; }
1391 iterator end() { return { *this, num_nodes() }; }
1392
1393 const_iterator begin() const { return cbegin(); }
1394 const_iterator end() const { return cend(); }
1395
1396 const_iterator cbegin() const { return { *this, 0 }; }
1397 const_iterator cend() const { return { *this, num_nodes() }; }
1398
1399 node_iterator node_begin() { return { *this, 0 }; }
1400 node_iterator node_end() { return { *this, num_nodes() }; }
1401
1404
1405 const_node_iterator node_cbegin() const { return { *this, 0 }; }
1406 const_node_iterator node_cend() const { return { *this, num_nodes() }; }
1407
1408 EdgesWrapper edges() { return { *this }; }
1409
1410 ConstEdgesWrapper edges() const { return { *this }; }
1411
1412 edge_iterator edge_begin() { return { *this, 0 }; }
1413 edge_iterator edge_end() { return { *this, num_edges() }; }
1414
1417
1418 const_edge_iterator edge_cbegin() const { return { *this, 0 }; }
1419 const_edge_iterator edge_cend() const { return { *this, num_edges() }; }
1420
1426 const std::vector<int> &node_ids() const { return nodes_.sequence(); }
1427
1433 const std::vector<int> &edge_ids() const { return edges_.sequence(); }
1434
1443 int degree(int idx) const {
1444 return std::distance(adj_cbegin(idx), adj_cend(idx));
1445 }
1446
1457 return find_edge(src.id(), dst.id());
1458 }
1459
1470 return find_edge(src.id(), dst.id());
1471 }
1472
1484 typename graph_type::ConstNodeRef dst) {
1485 auto sit = find_node(src), dit = find_node(dst);
1486 if (sit == end() || dit == end())
1487 return edge_end();
1488
1489 return find_edge(*sit, *dit);
1490 }
1491
1503 typename graph_type::ConstNodeRef dst) const {
1504 auto sit = find_node(src), dit = find_node(dst);
1505 if (sit == end() || dit == end())
1506 return edge_end();
1507
1508 return find_edge(*sit, *dit);
1509 }
1510
1521 return find_adjacent(src.id(), dst.id());
1522 }
1523
1535 ConstNodeRef dst) const {
1536 return find_adjacent(src.id(), dst.id());
1537 }
1538
1539 adjacency_iterator adj_begin(int idx) { return { *this, idx, 0 }; }
1541 return { *this, idx, parent_node(idx).degree() };
1542 }
1543
1544 const_adjacency_iterator adj_begin(int idx) const { return adj_cbegin(idx); }
1545 const_adjacency_iterator adj_end(int idx) const { return adj_cend(idx); }
1546
1548 return { *this, idx, 0 };
1549 }
1551 return { *this, idx, parent_node(idx).degree() };
1552 }
1553
1562 void rebind(parent_type &parent) { parent_ = &parent; }
1563
1564private:
1565 friend class Subgraph<NT, ET, true>;
1566
1567 template <class, bool>
1568 friend class internal::SubAdjWrapper;
1569 template <class, bool>
1570 friend class internal::SubEdgeWrapper;
1571
1572 Subgraph(parent_type &graph, internal::IndexSet &&nodes,
1573 internal::IndexSet &&edges) noexcept
1574 : parent_(&graph), nodes_(std::move(nodes)), edges_(std::move(edges)) { }
1575
1581 parent_type &parent() { return *parent_; }
1582
1588 const graph_type &parent() const { return *parent_; }
1589
1590 edge_iterator find_edge(int src, int dst) {
1591 return find_edge_helper(*this, src, dst);
1592 }
1593
1594 const_edge_iterator find_edge(int src, int dst) const {
1595 return find_edge_helper(*this, src, dst);
1596 }
1597
1598 adjacency_iterator find_adjacent(int src, int dst) {
1599 return find_adj_helper<adjacency_iterator>(*this, src, dst);
1600 }
1601
1602 const_adjacency_iterator find_adjacent(int src, int dst) const {
1603 return find_adj_helper<const_adjacency_iterator>(*this, src, dst);
1604 }
1605
1606 template <class SGT>
1607 static auto find_edge_helper(SGT &graph, int src, int dst) {
1608 if (graph.parent_node(src).degree() > graph.parent_node(dst).degree())
1609 std::swap(src, dst);
1610
1611 auto ait = graph.find_adjacent(src, dst);
1612 if (ait.end())
1613 return graph.edge_end();
1614
1615 return graph.edge_begin() + ait->eid();
1616 }
1617
1618 template <class AIT, class SGT>
1619 static AIT find_adj_helper(SGT &graph, int src, int dst) {
1620 auto pait = graph.parent_node(src).find_adjacent(graph.parent_node(dst));
1621 if (pait.end())
1622 return graph.adj_end(src);
1623
1624 auto eit = graph.find_edge(pait->eid());
1625 if (eit == graph.edge_end())
1626 return graph.adj_end(src);
1627
1628 return { graph, src, dst, eit->id(),
1629 pait - graph.parent_node(src).begin() };
1630 }
1631
1632 parent_type *parent_;
1633 internal::IndexSet nodes_;
1634 internal::IndexSet edges_;
1635};
1636
1637/* Deduction guides */
1638
1639template <class NT, class ET>
1641
1642template <class NT, class ET>
1643Subgraph(Graph<NT, ET> &graph, const std::vector<int> &nodes)
1645
1646template <class NT, class ET>
1647Subgraph(Graph<NT, ET> &graph, std::vector<int> &&nodes) noexcept
1649
1650template <class NT, class ET>
1652
1653template <class NT, class ET>
1654Subgraph(const Graph<NT, ET> &graph, const std::vector<int> &nodes)
1656
1657template <class NT, class ET>
1658Subgraph(const Graph<NT, ET> &graph, std::vector<int> &&nodes) noexcept
1660
1661namespace internal {
1662 /* Helper templates */
1663
1664 template <class T>
1665 struct SubgraphTypeHelper;
1666
1667 template <class T>
1668 struct SubgraphTypeHelper<T &&> { };
1669
1670 template <class T>
1671 struct SubgraphTypeHelper<T &> {
1672 using type = typename SubgraphTypeHelper<T>::type;
1673 };
1674
1675 template <template <class, class> class GT, class NT, class ET>
1676 struct SubgraphTypeHelper<GT<NT, ET>> {
1677 using type = Subgraph<NT, ET, false>;
1678 };
1679
1680 template <template <class, class> class GT, class NT, class ET>
1681 struct SubgraphTypeHelper<const GT<NT, ET>> {
1682 using type = Subgraph<NT, ET, true>;
1683 };
1684} // namespace internal
1685
1686template <class GT>
1687using SubgraphOf = typename internal::SubgraphTypeHelper<GT>::type;
1688
1695template <class GT>
1697 return { std::forward<GT>(graph) };
1698}
1699
1712template <class GT>
1713SubgraphOf<GT> make_subgraph(GT &&graph, internal::IndexSet &&nodes,
1714 internal::IndexSet &&edges) {
1715 return SubgraphOf<GT>::from_indices(std::forward<GT>(graph), std::move(nodes),
1716 std::move(edges));
1717}
1718
1729template <class GT>
1730SubgraphOf<GT> subgraph_from_nodes(GT &&graph, internal::IndexSet &&nodes) {
1731 return SubgraphOf<GT>::from_nodes(std::forward<GT>(graph), std::move(nodes));
1732}
1733
1744template <class GT>
1745SubgraphOf<GT> subgraph_from_edges(GT &&graph, internal::IndexSet &&edges) {
1746 return SubgraphOf<GT>::from_edges(std::forward<GT>(graph), std::move(edges));
1747}
1748
1749namespace internal {
1750 // NOLINTBEGIN(readability-identifier-naming)
1751 template <class NT, class ET, bool subg_const>
1752 struct GraphTraits<Subgraph<NT, ET, subg_const>> {
1753 constexpr static bool is_const = subg_const;
1754 constexpr static bool is_degree_constant_time = false;
1755 };
1756 // NOLINTEND(readability-identifier-naming)
1757} // namespace internal
1758} // namespace nuri
1759
1760#endif /* NURI_CORE_GRAPH_SUBGRAPH_H_ */
Class for very sparse graphs, especially designed for the molecular graphs.
Definition graph.h:475
internal::NodeWrapper< Graph, true > ConstNodeRef
Definition graph.h:497
internal::EdgeWrapper< Graph, true > ConstEdgeRef
Definition graph.h:502
A subgraph of a graph.
Definition subgraph.h:575
const_adjacency_iterator adj_cbegin(int idx) const
Definition subgraph.h:1547
internal::SubEdgeWrapper< Subgraph, is_const > EdgeRef
Definition subgraph.h:592
const_edge_iterator edge_begin() const
Definition subgraph.h:1415
internal::SubNodeIterator< Subgraph, is_const > iterator
Definition subgraph.h:583
int size() const
Count number of nodes in the subgraph.
Definition subgraph.h:746
ConstNodeRef operator[](int idx) const
Get a node in the subgraph.
Definition subgraph.h:972
void add_node(int id)
Add a node to the subgraph.
Definition subgraph.h:859
Subgraph & operator=(Other< other_const > &&other) noexcept
Converting assignment operator to allow implicit conversion from a non-const subgraph to a const subg...
Definition subgraph.h:727
ConstNodeRef node(int idx) const
Get a node in the subgraph.
Definition subgraph.h:988
void erase_node_of(typename graph_type::ConstNodeRef node)
Erase a node with given id from the subgraph. Corresponding edges will also be removed.
Definition subgraph.h:1287
const_adjacency_iterator adj_cend(int idx) const
Definition subgraph.h:1550
internal::EdgesWrapper< Subgraph, true > ConstEdgesWrapper
Definition subgraph.h:595
int degree(int idx) const
Count in-subgraph neighbors of a node.
Definition subgraph.h:1443
const ET & edge_data(int idx) const
Get data of an edge in the subgraph.
Definition subgraph.h:1054
void erase_edge_of(typename graph_type::ConstEdgeRef edge)
Erase an edge with given id from the subgraph.
Definition subgraph.h:1307
internal::SubEdgeIterator< Subgraph, is_const > edge_iterator
Definition subgraph.h:590
NodeRef operator[](int idx)
Get a node in the subgraph.
Definition subgraph.h:964
void add_edge(int id)
Add an edge to the subgraph. Also adds the incident nodes.
Definition subgraph.h:870
parent_type::ConstNodeRef parent_node(int idx) const
Get a parent node of a node in the subgraph.
Definition subgraph.h:1074
const std::vector< int > & node_ids() const
Get all node ids in the subgraph.
Definition subgraph.h:1426
ET edge_data_type
Definition subgraph.h:581
const_adjacency_iterator find_adjacent(ConstNodeRef src, ConstNodeRef dst) const
Find adjacent node of a node.
Definition subgraph.h:1534
void clear() noexcept
Clear the subgraph.
Definition subgraph.h:824
internal::SubNodeWrapper< Subgraph, true > ConstNodeRef
Definition subgraph.h:588
bool contains_node(int id) const
Check if a node is in the subgraph.
Definition subgraph.h:923
const_edge_iterator edge_end() const
Definition subgraph.h:1416
std::conditional_t< is_const, typename parent_type::ConstNodeRef, typename parent_type::NodeRef > parent_node(int idx)
Get a parent node of a node in the subgraph.
Definition subgraph.h:1064
bool empty() const
Whether the subgraph is empty.
Definition subgraph.h:739
void remap(const std::vector< int > &node_map, const std::vector< int > &edge_map)
Re-map node/edge ids.
Definition subgraph.h:1359
internal::const_if_t< is_const, graph_type > parent_type
Definition subgraph.h:578
const_adjacency_iterator adj_end(int idx) const
Definition subgraph.h:1545
parent_type::ConstEdgeRef parent_edge(int idx) const
Get a parent edge of an edge in the subgraph.
Definition subgraph.h:1096
bool contains_node(typename graph_type::ConstNodeRef node) const
Check if a node is in the subgraph.
Definition subgraph.h:933
internal::SubAdjIterator< Subgraph, true > const_adjacency_iterator
Definition subgraph.h:598
Subgraph(graph_type &&graph)=delete
const_edge_iterator edge_cbegin() const
Definition subgraph.h:1418
internal::EdgesWrapper< Subgraph, is_const > EdgesWrapper
Definition subgraph.h:594
edge_iterator edge_end()
Definition subgraph.h:1413
void erase_nodes_if(UnaryPred pred)
Erase matching nodes from the subgraph. Corresponding edges will also be removed.
Definition subgraph.h:1320
iterator find_node(typename graph_type::ConstNodeRef node)
Find a node with the given id.
Definition subgraph.h:1117
const_iterator const_node_iterator
Definition subgraph.h:586
const_node_iterator node_begin() const
Definition subgraph.h:1402
ConstEdgeRef edge(int idx) const
Get an edge in the subgraph.
Definition subgraph.h:1013
internal::SubEdgeIterator< Subgraph, true > const_edge_iterator
Definition subgraph.h:591
const_node_iterator node_end() const
Definition subgraph.h:1403
const_iterator cend() const
Definition subgraph.h:1397
void update_edges(internal::IndexSet &&edges) noexcept
Change the set of edges in the subgraph.
Definition subgraph.h:802
edge_iterator find_edge(int id)
Find an edge with the given id.
Definition subgraph.h:1151
NodeRef node(int idx)
Definition subgraph.h:980
internal::SubNodeWrapper< Subgraph, is_const > NodeRef
Definition subgraph.h:587
iterator node_iterator
Definition subgraph.h:584
const_node_iterator node_cbegin() const
Definition subgraph.h:1405
const NT & node_data(int idx) const
Get data of a node in the subgraph.
Definition subgraph.h:1036
internal::SubEdgeWrapper< Subgraph, true > ConstEdgeRef
Definition subgraph.h:593
node_iterator node_end()
Definition subgraph.h:1400
const_iterator begin() const
Definition subgraph.h:1393
Graph< NT, ET > graph_type
Definition subgraph.h:577
Subgraph & operator=(const Other< other_const > &other)
Converting assignment operator to allow implicit conversion from a non-const subgraph to a const subg...
Definition subgraph.h:712
edge_iterator edge_begin()
Definition subgraph.h:1412
iterator end()
Definition subgraph.h:1391
void add_edges(const internal::IndexSet &edges)
Add edges to the subgraph. Also adds the incident nodes.
Definition subgraph.h:896
std::conditional_t< is_const, typename parent_type::ConstEdgeRef, typename parent_type::EdgeRef > parent_edge(int idx)
Get a parent edge of an edge in the subgraph.
Definition subgraph.h:1086
int num_nodes() const
Count number of nodes in the subgraph.
Definition subgraph.h:753
const_iterator find_node(int id) const
Find a node with the given id.
Definition subgraph.h:1128
const_adjacency_iterator adj_begin(int idx) const
Definition subgraph.h:1544
NT node_data_type
Definition subgraph.h:580
Subgraph< NT, ET, other_const > Other
Definition subgraph.h:613
iterator find_node(int id)
Find a node with the given id.
Definition subgraph.h:1107
const_edge_iterator edge_cend() const
Definition subgraph.h:1419
void erase_node(ConstNodeRef node)
Erase a node from the subgraph.
Definition subgraph.h:1213
adjacency_iterator find_adjacent(ConstNodeRef src, ConstNodeRef dst)
Find adjacent node of a node.
Definition subgraph.h:1520
const_iterator end() const
Definition subgraph.h:1394
internal::SubAdjIterator< Subgraph, is_const > adjacency_iterator
Definition subgraph.h:597
internal::SubNodeIterator< Subgraph, true > const_iterator
Definition subgraph.h:585
iterator begin()
Definition subgraph.h:1390
edge_iterator find_edge(ConstNodeRef src, ConstNodeRef dst)
Find edge between two nodes.
Definition subgraph.h:1456
void reserve_edges(int num_edges)
Reserve space for a number of edges.
Definition subgraph.h:848
void reserve_nodes(int num_nodes)
Reserve space for a number of nodes.
Definition subgraph.h:841
void erase_edges_if(UnaryPred &&pred)
Erase matching edges from the subgraph.
Definition subgraph.h:1344
Subgraph(parent_type &graph)
Construct an empty subgraph.
Definition subgraph.h:622
internal::const_if_t< is_const, ET > & edge_data(int idx)
Get data of an edge in the subgraph.
Definition subgraph.h:1044
void erase_edges(const_edge_iterator begin, const_edge_iterator end)
Erase range of edges from the subgraph.
Definition subgraph.h:1260
void remap_nodes(const std::vector< int > &node_map)
Re-map node ids.
Definition subgraph.h:1376
node_iterator node_begin()
Definition subgraph.h:1399
adjacency_iterator adj_begin(int idx)
Definition subgraph.h:1539
void erase_edge(int idx)
Erase an edge from the subgraph.
Definition subgraph.h:1222
bool contains_edge(int id) const
Check if an edge is in the subgraph.
Definition subgraph.h:944
void erase_node(int idx)
Erase a node from the subgraph. Corresponding edges will also be removed.
Definition subgraph.h:1198
bool contains_edge(typename graph_type::ConstEdgeRef edge) const
Check if an edge is in the subgraph.
Definition subgraph.h:954
const std::vector< int > & edge_ids() const
Get all edge ids in the subgraph.
Definition subgraph.h:1433
void erase_edge_of(int id)
Erase an edge with given id from the subgraph.
Definition subgraph.h:1298
EdgeRef edge(int idx)
Definition subgraph.h:998
edge_iterator find_edge(typename graph_type::ConstEdgeRef edge)
Find an edge with the given id.
Definition subgraph.h:1163
internal::SubAdjWrapper< Subgraph, true > ConstAdjRef
Definition subgraph.h:600
void update(internal::IndexSet &&nodes, internal::IndexSet &&edges)
Change the set of nodes and edges in the subgraph.
Definition subgraph.h:773
const_iterator cbegin() const
Definition subgraph.h:1396
EdgesWrapper edges()
Definition subgraph.h:1408
const_node_iterator node_cend() const
Definition subgraph.h:1406
void erase_edge(ConstEdgeRef edge)
Erase an edge from the subgraph.
Definition subgraph.h:1231
ConstEdgesWrapper edges() const
Definition subgraph.h:1410
void erase_node_of(int id)
Erase a node with given id from the subgraph. Corresponding edges will also be removed.
Definition subgraph.h:1273
void update_nodes(internal::IndexSet &&nodes) noexcept
Change the set of nodes in the subgraph.
Definition subgraph.h:788
void erase_nodes(const_iterator begin, const_iterator end)
Erase range of nodes from the subgraph. Corresponding edges will also be removed.
Definition subgraph.h:1242
int num_edges() const
Count number of edges in the subgraph.
Definition subgraph.h:760
Subgraph(Other< other_const > &&other) noexcept
Converting constructor to allow implicit conversion from a non-const subgraph to a const subgraph.
Definition subgraph.h:700
void rebind(parent_type &parent)
Re-bind the subgraph to a new parent graph.
Definition subgraph.h:1562
void add_nodes_with_edges(const internal::IndexSet &nodes)
Add nodes to the subgraph, and update the edges.
Definition subgraph.h:910
const_iterator find_node(typename graph_type::ConstNodeRef node) const
Find a node with the given id.
Definition subgraph.h:1140
internal::SubAdjWrapper< Subgraph, is_const > AdjRef
Definition subgraph.h:599
internal::const_if_t< is_const, NT > & node_data(int idx)
Get data of a node in the subgraph.
Definition subgraph.h:1026
static Subgraph from_edges(parent_type &graph, internal::IndexSet &&edges)
Construct a subgraph with the given edges and all nodes connected to the edges.
Definition subgraph.h:675
static Subgraph from_nodes(parent_type &graph, internal::IndexSet &&nodes)
Construct a subgraph with the given nodes and all edges connecting the nodes.
Definition subgraph.h:659
void refresh_edges()
Make this graph an induced subgraph of the parent graph.
Definition subgraph.h:815
const_edge_iterator find_edge(int id) const
Find an edge with the given id.
Definition subgraph.h:1174
const_edge_iterator find_edge(ConstNodeRef src, ConstNodeRef dst) const
Find edge between two nodes.
Definition subgraph.h:1469
edge_iterator find_edge(typename graph_type::ConstNodeRef src, typename graph_type::ConstNodeRef dst)
Find edge between two nodes.
Definition subgraph.h:1483
static Subgraph from_indices(parent_type &graph, internal::IndexSet &&nodes, internal::IndexSet &&edges)
Construct a subgraph with the given nodes and edges.
Definition subgraph.h:639
const_edge_iterator find_edge(typename graph_type::ConstNodeRef src, typename graph_type::ConstNodeRef dst) const
Find edge between two nodes.
Definition subgraph.h:1502
void add_nodes(const internal::IndexSet &nodes)
Add nodes to the subgraph.
Definition subgraph.h:886
Subgraph(const Other< other_const > &other)
Converting constructor to allow implicit conversion from a non-const subgraph to a const subgraph.
Definition subgraph.h:689
void clear_edges() noexcept
Clear the edges.
Definition subgraph.h:834
void remap_edges(const std::vector< int > &old_to_new)
Re-map edge ids.
Definition subgraph.h:1386
const_edge_iterator find_edge(typename graph_type::ConstEdgeRef edge) const
Find an edge with the given id.
Definition subgraph.h:1186
adjacency_iterator adj_end(int idx)
Definition subgraph.h:1540
Definition crdgen.h:16
SubgraphOf< GT > subgraph_from_nodes(GT &&graph, internal::IndexSet &&nodes)
Make a subgraph from list of nodes.
Definition subgraph.h:1730
SubgraphOf< GT > make_subgraph(GT &&graph)
Make an empty subgraph from a graph.
Definition subgraph.h:1696
auto edges(const Graph< NT, ET > &g)
Definition adaptor.h:273
SubgraphOf< GT > subgraph_from_edges(GT &&graph, internal::IndexSet &&edges)
Make a subgraph from list of edges.
Definition subgraph.h:1745
Subgraph(Graph< NT, ET > &graph) -> Subgraph< NT, ET, false >
typename internal::SubgraphTypeHelper< GT >::type SubgraphOf
Definition subgraph.h:1687