6#ifndef NURI_CORE_GRAPH_GRAPH_H_
7#define NURI_CORE_GRAPH_GRAPH_H_
11#include <initializer_list>
18#include <absl/algorithm/container.h>
19#include <absl/base/attributes.h>
20#include <absl/base/optimization.h>
21#include <absl/container/flat_hash_set.h>
22#include <absl/log/absl_check.h>
23#include <absl/log/absl_log.h>
24#include <boost/iterator/iterator_facade.hpp>
35 template <
class Derived,
class GT,
class DT,
bool is_const>
36 class DataIteratorBase
37 :
public ProxyIterator<Derived, DT, std::random_access_iterator_tag, int> {
39 std::iterator_traits<typename DataIteratorBase::iterator_facade_>;
42 using parent_type = const_if_t<is_const, GT>;
44 using iterator_category =
typename Traits::iterator_category;
45 using value_type =
typename Traits::value_type;
46 using difference_type =
typename Traits::difference_type;
47 using pointer =
typename Traits::pointer;
48 using reference =
typename Traits::reference;
50 constexpr DataIteratorBase() noexcept = default;
52 constexpr DataIteratorBase(parent_type &graph,
53 difference_type index) noexcept
54 : graph_(&graph), index_(index) { }
57 using Parent = DataIteratorBase;
59 template <
class Other,
60 std::enable_if_t<!std::is_same_v<Derived, Other>,
int> = 0>
61 constexpr DataIteratorBase(
const Other &other) noexcept
62 : graph_(other.graph_), index_(other.index_) { }
64 template <
class Other,
65 std::enable_if_t<!std::is_same_v<Derived, Other>,
int> = 0>
66 constexpr DataIteratorBase &operator=(
const Other &other)
noexcept {
67 graph_ = other.graph_;
68 index_ = other.index_;
72 constexpr parent_type &graph() const noexcept {
return *graph_; }
74 constexpr difference_type index() const noexcept {
return index_; }
76 template <
class Other,
77 std::enable_if_t<std::is_convertible_v<Other, Derived>,
int> = 0>
78 constexpr bool equal(
const Other &other)
const noexcept {
79 return index_ == other.index_;
82 template <
class Other,
83 std::enable_if_t<std::is_convertible_v<Other, Derived>,
int> = 0>
84 constexpr difference_type distance_to(
const Other &other)
const noexcept {
85 return other.index_ - index_;
88 void increment() noexcept { ++index_; }
89 void decrement() noexcept { --index_; }
90 void advance(difference_type n)
noexcept { index_ += n; }
93 template <
class,
class,
class,
bool>
94 friend class DataIteratorBase;
96 friend class boost::iterator_core_access;
99 difference_type index_;
102 template <
class GT,
bool is_const>
105 template <
class GT,
bool is_const>
108 using edge_value_type = const_if_t<is_const, typename GT::edge_data_type>;
109 using parent_type = const_if_t<is_const, GT>;
111 template <
bool other_const>
112 using Other = AdjWrapper<GT, other_const>;
114 constexpr AdjWrapper(parent_type &graph,
int src,
int dst,
int eid) noexcept
115 : src_(src), dst_(dst), eid_(eid), graph_(&graph) { }
117 template <
bool other_const,
118 std::enable_if_t<is_const && !other_const, int> = 0>
119 constexpr AdjWrapper(
const Other<other_const> &other) noexcept
120 : src_(other.src_), dst_(other.dst_), eid_(other.eid_),
121 graph_(other.graph_) { }
123 constexpr auto src() const noexcept {
return graph_->node(src_); }
124 constexpr auto dst() const noexcept {
return graph_->node(dst_); }
126 constexpr int eid() const noexcept {
return eid_; }
127 constexpr edge_value_type &edge_data() const noexcept {
128 return graph_->edge_data(eid_);
131 constexpr Other<true> as_const() const noexcept {
return *
this; }
134 template <
class,
bool>
135 friend class AdjWrapper;
145 template <
class GT,
bool is_const>
147 :
public DataIteratorBase<AdjIterator<GT, is_const>, GT,
148 AdjWrapper<GT, is_const>, is_const> {
149 using Base =
typename AdjIterator::Parent;
152 using typename Base::difference_type;
153 using typename Base::iterator_category;
154 using typename Base::pointer;
155 using typename Base::reference;
156 using typename Base::value_type;
158 using typename Base::parent_type;
160 template <
bool other_const>
161 using Other = AdjIterator<GT, other_const>;
163 constexpr AdjIterator() noexcept = default;
165 constexpr AdjIterator(parent_type &graph, difference_type idx,
166 difference_type nid) noexcept
167 : Base(graph, idx), nid_(nid) { }
169 template <
bool other_const,
170 std::enable_if_t<is_const && !other_const, int> = 0>
171 constexpr AdjIterator(
const Other<other_const> &other) noexcept
172 : Base(other), nid_(other.nid_) { }
174 template <
bool other_const,
175 std::enable_if_t<is_const && !other_const, int> = 0>
176 constexpr AdjIterator &operator=(
const Other<other_const> &other)
noexcept {
177 Base::operator=(other);
182 constexpr bool begin() const noexcept {
183 return Base::equal(this->graph().adj_begin(nid_));
186 constexpr bool end() const noexcept {
187 return Base::equal(this->graph().adj_end(nid_));
193 friend class boost::iterator_core_access;
195 template <
class,
bool>
196 friend class AdjIterator;
200 std::enable_if_t<std::is_convertible_v<Other, AdjIterator>,
int> = 0>
201 constexpr bool equal(
const Other &other)
const noexcept {
202 return nid_ == other.nid_ && Base::equal(other);
205 constexpr reference dereference() const noexcept {
206 return this->graph().adjacent(nid_, this->index());
212 template <
class GT,
bool is_const>
215 using DT =
typename GT::node_data_type;
217 using parent_type = const_if_t<is_const, GT>;
218 using value_type = const_if_t<is_const, DT>;
220 using adjacency_iterator =
221 std::conditional_t<is_const,
typename GT::const_adjacency_iterator,
222 typename GT::adjacency_iterator>;
224 template <
bool other_const>
225 using Other = NodeWrapper<GT, other_const>;
227 constexpr NodeWrapper(
int nid, parent_type &graph) noexcept
228 : nid_(nid), graph_(&graph) { }
230 template <
bool other_const,
231 std::enable_if_t<is_const && !other_const, int> = 0>
232 constexpr NodeWrapper(
const Other<other_const> &other) noexcept
233 : nid_(other.nid_), graph_(other.graph_) { }
235 constexpr int id() const noexcept {
return nid_; }
237 constexpr value_type &data() const noexcept {
238 return graph_->node_data(nid_);
241 constexpr int degree() const noexcept {
return graph_->degree(nid_); }
243 adjacency_iterator begin() const noexcept {
244 return graph_->adj_begin(nid_);
247 adjacency_iterator end() const noexcept {
return graph_->adj_end(nid_); }
249 AdjWrapper<GT, is_const> neighbor(
int idx)
const noexcept {
250 return graph_->adjacent(nid_, idx);
253 AdjWrapper<GT, is_const> operator[](
int idx)
const noexcept {
254 return neighbor(idx);
257 adjacency_iterator find_adjacent(
int aid)
const noexcept {
258 return graph_->find_adjacent(nid_, aid);
262 find_adjacent(NodeWrapper<GT, true> node)
const noexcept {
263 return find_adjacent(node.id());
266 constexpr Other<true> as_const() const noexcept {
return *
this; }
269 template <
class,
bool>
270 friend class NodeWrapper;
276 template <
class GT,
bool is_const>
278 :
public DataIteratorBase<NodeIterator<GT, is_const>, GT,
279 NodeWrapper<GT, is_const>, is_const> {
280 using Base =
typename NodeIterator::Parent;
283 using typename Base::difference_type;
284 using typename Base::iterator_category;
285 using typename Base::pointer;
286 using typename Base::reference;
287 using typename Base::value_type;
291 template <
bool other_const,
292 std::enable_if_t<is_const && !other_const, int> = 0>
293 constexpr NodeIterator(
const NodeIterator<GT, other_const> &other) noexcept
296 template <
bool other_const,
297 std::enable_if_t<is_const && !other_const, int> = 0>
298 constexpr NodeIterator &
299 operator=(
const NodeIterator<GT, other_const> &other)
noexcept {
300 Base::operator=(other);
307 friend class boost::iterator_core_access;
309 template <
class,
bool other_const>
310 friend class NodeIterator;
312 constexpr reference dereference() const noexcept {
313 return this->graph().node(this->index());
317 template <
class GT,
bool is_const>
320 using DT =
typename GT::edge_data_type;
322 using parent_type = const_if_t<is_const, GT>;
323 using value_type = const_if_t<is_const, DT>;
325 template <
bool other_const>
326 using Other = EdgeWrapper<GT, other_const>;
328 constexpr EdgeWrapper(
int eid, parent_type &graph) noexcept
329 : eid_(eid), graph_(&graph) { }
331 template <
bool other_const,
332 std::enable_if_t<is_const && !other_const, int> = 0>
333 constexpr EdgeWrapper(
const Other<other_const> &other) noexcept
334 : eid_(other.eid_), graph_(other.graph_) { }
336 constexpr int id() const noexcept {
return eid_; }
338 constexpr NodeWrapper<GT, is_const> src() const noexcept {
339 return graph_->edge_src(eid_);
342 constexpr NodeWrapper<GT, is_const> dst() const noexcept {
343 return graph_->edge_dst(eid_);
346 constexpr value_type &data() const noexcept {
347 return graph_->edge_data(eid_);
350 constexpr Other<true> as_const() const noexcept {
return *
this; }
353 template <
class,
bool>
354 friend class EdgeWrapper;
360 template <
class GT,
bool is_const>
362 :
public DataIteratorBase<EdgeIterator<GT, is_const>, GT,
363 EdgeWrapper<GT, is_const>, is_const> {
364 using Base =
typename EdgeIterator::Parent;
367 using typename Base::difference_type;
368 using typename Base::iterator_category;
369 using typename Base::pointer;
370 using typename Base::reference;
371 using typename Base::value_type;
375 template <
bool other_const,
376 std::enable_if_t<is_const && !other_const, int> = 0>
377 constexpr EdgeIterator(
const EdgeIterator<GT, other_const> &other) noexcept
380 template <
bool other_const,
381 std::enable_if_t<is_const && !other_const, int> = 0>
382 constexpr EdgeIterator &
383 operator=(
const EdgeIterator<GT, other_const> &other)
noexcept {
384 Base::operator=(other);
391 friend class boost::iterator_core_access;
393 template <
class,
bool other_const>
394 friend class EdgeIterator;
396 constexpr reference dereference() const noexcept {
397 return this->graph().edge(this->index());
401 template <
class GT,
bool is_const>
404 template <
class GU = GT,
405 std::enable_if_t<std::is_same_v<GU, GT> && !is_const,
int> = 0>
406 EdgesWrapper(GT &graph): graph_(&graph) { }
408 EdgesWrapper(
const GT &graph): graph_(&graph) { }
410 template <
bool other_const>
411 using Other = EdgesWrapper<GT, other_const>;
413 template <
bool other_const,
414 std::enable_if_t<is_const && !other_const, int> = 0>
415 EdgesWrapper(
const Other<other_const> &other) noexcept
416 : graph_(other.graph_) { }
418 template <
bool other_const,
419 std::enable_if_t<is_const && !other_const, int> = 0>
420 EdgesWrapper &operator=(
const Other<other_const> &other)
noexcept {
421 graph_ = other.graph_;
425 auto operator[](
int id)
const {
return graph_->edge(
id); }
427 auto begin()
const {
return graph_->edge_begin(); }
428 auto end()
const {
return graph_->edge_end(); }
430 auto cbegin()
const {
return graph_->edge_cbegin(); }
431 auto cend()
const {
return graph_->edge_cend(); }
433 EdgesWrapper<GT, true> as_const()
const {
return *
this; }
435 int size()
const {
return graph_->num_edges(); }
438 const_if_t<is_const, GT> *graph_;
441 template <
class,
bool>
442 class SubEdgeWrapper;
445 struct OffsetForwarder {
447 T operator()(
const U &edge)
const {
448 return T { edge.src().id() + offset, edge.dst().id() + offset,
457 std::pair<int, std::vector<int>>>;
459template <
class NT,
class ET,
bool is_const>
474template <
class NT,
class ET>
492 using iterator = internal::NodeIterator<Graph, false>;
496 using NodeRef = internal::NodeWrapper<Graph, false>;
501 using EdgeRef = internal::EdgeWrapper<Graph, false>;
506 using AdjRef = internal::AdjWrapper<Graph, false>;
509 static_assert(std::is_same_v<typename iterator::reference, NodeRef>);
511 std::is_same_v<typename const_iterator::reference, ConstNodeRef>);
512 static_assert(std::is_same_v<typename edge_iterator::reference, EdgeRef>);
514 std::is_same_v<typename const_edge_iterator::reference, ConstEdgeRef>);
515 static_assert(std::is_same_v<typename adjacency_iterator::reference, AdjRef>);
517 std::is_same_v<typename const_adjacency_iterator::reference, ConstAdjRef>);
545 <<
"The graph is empty (num_nodes() == 0) but num_edges() == "
551 int num_nodes()
const {
return static_cast<int>(nodes_.size()); }
556 <<
"The graph is empty (num_nodes() == 0) but num_edges() == "
561 int num_edges()
const {
return static_cast<int>(edges_.size()); }
563 int degree(
int id)
const {
return offsets_[
id + 1] - offsets_[id]; }
583 nodes_.push_back(data);
584 offsets_.push_back(offsets_[
id]);
596 nodes_.push_back(std::move(data));
597 offsets_.push_back(offsets_[
id]);
611 template <
class Iterator,
612 internal::enable_if_compatible_iter_t<Iterator, NT> = 0>
615 nodes_.insert(nodes_.end(),
begin,
end);
616 offsets_.resize(
num_nodes() + 1, offsets_.back());
634 ABSL_DEPRECATED(
"Slow, due to CSR recompilation.")
636 ABSL_DCHECK_NE(src, dst) <<
"self-loop is not allowed";
639 edges_.push_back({ src, dst, data });
640 publish_edges_from(eid);
655 ABSL_DEPRECATED(
"Slow, due to CSR recompilation.")
656 int
add_edge(
int src,
int dst, ET &&data) noexcept {
657 ABSL_DCHECK_NE(src, dst) <<
"self-loop is not allowed";
660 edges_.push_back({ src, dst, std::move(data) });
661 publish_edges_from(eid);
679 template <
class Iterator,
680 internal::enable_if_compatible_iter_t<Iterator, StoredEdge> = 0>
683 edges_.insert(edges_.end(),
begin,
end);
684 publish_edges_from(first);
695 const NT &
node_data(
int id)
const {
return nodes_[id]; }
750 template <
class UnaryPred>
774 template <
class Iterator,
775 class = internal::enable_if_compatible_iter_t<Iterator, int>>
795 const ET &
edge_data(
int id)
const {
return edges_[id].data; }
806 return find_edge_helper(*
this, src, dst);
818 return find_edge_helper(*
this, src, dst);
854 absl::c_fill(offsets_, 0);
866 const StoredEdge &
edge = edges_[id];
867 auto srcit = find_adjacency_entry(
edge.src,
edge.dst),
868 dstit = find_adjacency_entry(
edge.dst,
edge.src);
869 erase_adjacency_entry(
edge.src, srcit,
edge.dst, dstit);
871 erase_edge_common(
id);
946 template <
class UnaryPred>
971 template <
class Iterator,
972 class = internal::enable_if_compatible_iter_t<Iterator, int>>
975 internal::EdgesWrapper<Graph, false>
edges() {
return { *
this }; }
976 internal::EdgesWrapper<Graph, true>
edges()
const {
return { *
this }; }
977 internal::EdgesWrapper<Graph, true>
cedges()
const {
return { *
this }; }
996 return find_adj_helper(*
this, src, dst);
1009 return find_adj_helper(*
this, src, dst);
1046 return { *
this, 0, nid };
1049 return { *
this,
degree(nid), nid };
1061 template <
class GraphLike>
1063 const int offset =
size();
1064 reserve(offset + other.size());
1066 for (
auto node: other)
1069 auto edges = other.edges();
1072 internal::OffsetForwarder<StoredEdge> as_stored_edge { offset };
1073 add_edges(internal::make_transform_iterator(
edges.begin(), as_stored_edge),
1074 internal::make_transform_iterator(
edges.end(), as_stored_edge));
1078 template <
class,
bool>
1079 friend class internal::NodeWrapper;
1081 template <
class,
bool>
1082 friend class internal::EdgeIterator;
1084 template <
class,
bool>
1085 friend class internal::AdjIterator;
1087 friend class Subgraph<NT, ET, false>;
1088 friend class Subgraph<NT, ET, true>;
1091 static internal::AdjIterator<Graph, std::is_const_v<GT>>
1092 find_adj_helper(GT &graph,
int src,
int dst) {
1095 for (; !ret.end(); ++ret)
1096 if (ret->dst().id() == dst)
1103 static internal::EdgeIterator<Graph, std::is_const_v<GT>>
1104 find_edge_helper(GT &graph,
int src,
int dst) {
1105 if (graph.degree(src) > graph.degree(dst))
1106 return find_edge_helper(graph, dst, src);
1108 auto ait = find_adj_helper(graph, src, dst);
1110 return graph.edge_end();
1112 return { graph, ait->eid_ };
1115 std::pair<int, std::vector<int>>
1116 erase_nodes_common(std::vector<int> &node_keep,
int first_erased_id,
1117 bool erase_trailing);
1119 void erase_edge_common(
int id);
1121 void erase_edges_common(std::vector<int> &edge_keep,
int first_erased_id,
1122 bool erase_trailing);
1140 void publish_edges_from(
int first_eid);
1142 auto find_adjacency_entry(
int src,
int dst) {
1143 return std::find_if(adj_list_.begin() + offsets_[src],
1144 adj_list_.begin() + offsets_[src + 1],
1145 [dst](
const AdjEntry &adj) { return adj.dst == dst; });
1148 void erase_adjacency_entry(
int src,
1149 typename std::vector<AdjEntry>::iterator srcit,
1151 typename std::vector<AdjEntry>::iterator dstit) {
1153 erase_adjacency_entry(dst, dstit, src, srcit);
1159 std::move(srcit + 1, dstit, srcit);
1160 std::move(dstit + 1, adj_list_.end(), dstit - 1);
1161 adj_list_.resize(adj_list_.size() - 2);
1165 for (
int v = src + 1; v <= dst; ++v)
1167 for (
int v = dst + 1, n =
static_cast<int>(offsets_.size()); v < n; ++v)
1171 AdjRef adjacent(
int nid,
int idx) {
1172 const AdjEntry &adj = adj_list_[offsets_[nid] + idx];
1173 return { *
this, nid, adj.dst, adj.eid };
1177 const AdjEntry &adj = adj_list_[offsets_[nid] + idx];
1178 return { *
this, nid, adj.dst, adj.eid };
1181 std::vector<int> offsets_ = { 0 };
1182 std::vector<AdjEntry> adj_list_;
1184 std::vector<NT> nodes_;
1185 std::vector<StoredEdge> edges_;
1190template <
class NT,
class ET>
1191template <
class Iterator,
class>
1203 std::vector<int> node_keep(
num_nodes(), 1);
1205 for (
auto it =
begin; it !=
end; ++it) {
1208 first_erased_id = std::min(first_erased_id, nid);
1211 bool erase_trailing =
true;
1212 for (
int i =
num_nodes() - 1; i >= first_erased_id; --i) {
1213 if (node_keep[i] == 1) {
1214 erase_trailing =
false;
1220 erase_nodes_common(node_keep, first_erased_id, erase_trailing);
1222 { erase_trailing ? first_erased_id : -1, std::move(node_keep) },
1223 std::move(edge_info),
1227template <
class NT,
class ET>
1228template <
class UnaryPred>
1244 std::vector<int> node_keep(
num_nodes(), 1);
1245 int first_erased_id = -1;
1246 bool erase_trailing =
end == this->end();
1247 for (
auto it =
begin; it !=
end; ++it) {
1252 ABSL_ASSUME(nid >= 0);
1255 if (first_erased_id < 0)
1256 first_erased_id = nid;
1259 }
else if (first_erased_id >= 0) {
1260 erase_trailing =
false;
1265 erase_nodes_common(node_keep, first_erased_id, erase_trailing);
1267 { erase_trailing ? first_erased_id : -1, std::move(node_keep) },
1268 std::move(edge_info),
1272template <
class NT,
class ET>
1273std::pair<int, std::vector<int>>
1274Graph<NT, ET>::erase_nodes_common(std::vector<int> &node_keep,
1275 const int first_erased_id,
1276 const bool erase_trailing) {
1278 if (first_erased_id < 0 || first_erased_id >= num_nodes())
1282 auto ret = erase_edges(edge_begin(), edge_end(), [&](ConstEdgeRef edge) {
1283 return node_keep[edge.src().id()] == 0 || node_keep[edge.dst().id()] == 0;
1287 if (erase_trailing) {
1290 ABSL_DLOG(INFO) <<
"resizing offset table & node list";
1292 nodes_.resize(first_erased_id);
1293 offsets_.resize(first_erased_id + 1);
1300 [&](
const NT & ) {
return node_keep[i++] == 0; });
1303 mask_to_map(node_keep);
1305 for (
int v = 0; v < static_cast<int>(node_keep.size()); ++v) {
1306 int w = node_keep[v];
1309 offsets_[w + 1] = offsets_[v + 1];
1311 offsets_.resize(nodes_.size() + 1);
1313 for (AdjEntry &adj: adj_list_)
1314 adj.dst = node_keep[adj.dst];
1316 for (StoredEdge &edge: edges_) {
1317 edge.src = node_keep[edge.src];
1318 edge.dst = node_keep[edge.dst];
1324template <
class NT,
class ET>
1325void Graph<NT, ET>::publish_edges_from(
const int first_eid) {
1327 if (first_eid == total_edges)
1330 const int n = num_nodes();
1333 std::vector<int> delta(n, 0);
1334 for (
int eid = first_eid; eid < total_edges; ++eid) {
1335 const StoredEdge &e = edges_[eid];
1339 const int v_min =
static_cast<int>(
1340 absl::c_find_if(delta, [](
int d) {
return d > 0; }) - delta.begin());
1343 const int added = 2 * (total_edges - first_eid);
1344 adj_list_.resize(adj_list_.size() + added);
1352 for (
int i = n - 1; i > v_min; --i) {
1353 const int old_end = offsets_[i + 1], old_start = offsets_[i],
1354 old_deg = old_end - old_start;
1356 offsets_[i + 1] = old_end + shift;
1358 const int new_start = old_start + shift;
1359 std::move_backward(adj_list_.begin() + old_start,
1360 adj_list_.begin() + old_end,
1361 adj_list_.begin() + new_start + old_deg);
1363 offsets_[v_min + 1] += shift;
1366 ABSL_DCHECK_EQ(shift, delta[v_min])
1367 <<
"shift mismatch: " << shift <<
" vs " << delta[v_min];
1371 for (
int eid = first_eid; eid < total_edges; ++eid) {
1372 const StoredEdge &e = edges_[eid];
1373 int sd = delta[e.src]--, dd = delta[e.dst]--;
1374 adj_list_[offsets_[e.src + 1] - sd] = { e.dst, eid };
1375 adj_list_[offsets_[e.dst + 1] - dd] = { e.src, eid };
1379template <
class NT,
class ET>
1384 auto srcit = find_adjacency_entry(src, dst);
1385 if (srcit == adj_list_.begin() + offsets_[src + 1])
1388 int eid = srcit->eid;
1390 auto dstit = find_adjacency_entry(dst, src);
1391 erase_adjacency_entry(src, srcit, dst, dstit);
1393 erase_edge_common(eid);
1398template <
class NT,
class ET>
1399void Graph<NT, ET>::erase_edge_common(
int id) {
1401 edges_.erase(edges_.begin() +
id);
1403 if (
id == orig_edges - 1)
1406 for (AdjEntry &adj: adj_list_) {
1412template <
class NT,
class ET>
1413template <
class UnaryPred>
1414std::pair<int, std::vector<int>>
1422 std::vector<int> edge_keep(
num_edges(), 1);
1423 int first_erased_id = -1;
1425 for (
auto it =
begin; it !=
end; ++it) {
1429 ABSL_ASSUME(eid >= 0);
1431 if (first_erased_id < 0)
1432 first_erased_id = eid;
1435 }
else if (first_erased_id >= 0) {
1436 erase_trailing =
false;
1440 erase_edges_common(edge_keep, first_erased_id, erase_trailing);
1441 return { erase_trailing ? first_erased_id : -1, std::move(edge_keep) };
1444template <
class NT,
class ET>
1445template <
class Iterator,
class>
1452 std::vector<int> edge_keep(
num_edges(), 1);
1454 for (
auto it =
begin; it !=
end; ++it) {
1457 first_erased_id = std::min(first_erased_id, eid);
1460 bool erase_trailing =
true;
1461 for (
int i =
num_edges() - 1; i >= first_erased_id; --i) {
1462 if (edge_keep[i] == 1) {
1463 erase_trailing =
false;
1468 erase_edges_common(edge_keep, first_erased_id, erase_trailing);
1469 return { erase_trailing ? first_erased_id : -1, std::move(edge_keep) };
1472template <
class NT,
class ET>
1473void Graph<NT, ET>::erase_edges_common(std::vector<int> &edge_keep,
1474 int first_erased_id,
1475 bool erase_trailing) {
1477 if (first_erased_id < 0 || first_erased_id >=
num_edges())
1481 const int n = num_nodes();
1482 int p = 0, old_end = 0;
1483 for (
int i = 0; i < n; ++i) {
1484 const int old_start = old_end;
1485 old_end = offsets_[i + 1];
1486 for (
int q = old_start; q < old_end; ++q) {
1487 if (edge_keep[adj_list_[q].eid] != 0)
1488 adj_list_[p++] = adj_list_[q];
1490 offsets_[i + 1] = p;
1492 adj_list_.resize(p);
1496 if (erase_trailing) {
1497 ABSL_DLOG(INFO) <<
"resizing edge list";
1499 edges_.resize(first_erased_id);
1505 erase_if(edges_, [&](
const StoredEdge & ) {
1506 return edge_keep[i++] == 0;
1510 mask_to_map(edge_keep);
1512 for (AdjEntry &adj: adj_list_)
1513 adj.eid = edge_keep[adj.eid];
1518 template <
class NT,
class ET>
1519 struct GraphTraits<Graph<NT, ET>> {
1520 constexpr static bool is_degree_constant_time =
true;
1524 template <
class GT,
bool is_const>
1525 class EigenNeighborIndexer {
1527 EigenNeighborIndexer(NodeWrapper<GT, is_const> node): node_(node) { }
1529 int size()
const {
return node_.degree(); }
1531 int operator[](
int i)
const {
return node_[i].dst().id(); }
1534 NodeWrapper<GT, is_const> node_;
1538template <
class GT,
bool is_const>
1539internal::EigenNeighborIndexer<GT, is_const>
1545 template <
class NT,
class ET>
1546 void connected_components_impl(
const Graph<NT, ET> &g,
1547 absl::flat_hash_set<int> &visited,
1548 std::queue<int> &q) {
1549 while (!q.empty()) {
1550 int atom = q.front();
1553 auto [_, inserted] = visited.insert(atom);
1557 for (
auto ait = g.adj_begin(atom); !ait.end(); ++ait) {
1558 int dst = ait->dst().id();
1577template <
class NT,
class ET>
1580 absl::flat_hash_set<int> visited;
1581 std::queue<int> q { { begin } };
1583 internal::connected_components_impl(g, visited, q);
1605template <
class NT,
class ET>
1608 absl::flat_hash_set<int> visited { begin };
1611 for (
auto ait = g.
adj_begin(begin); !ait.end(); ++ait) {
1612 int dst = ait->dst().id();
1617 internal::connected_components_impl(g, visited, q);
1619 if (visited.contains(exclude))
Class for very sparse graphs, especially designed for the molecular graphs.
Definition graph.h:475
const ET & edge_data(int id) const
Definition graph.h:795
internal::EdgesWrapper< Graph, true > cedges() const
Definition graph.h:977
int add_node(const NT &data)
Add a node to the graph.
Definition graph.h:581
int degree(int id) const
Definition graph.h:563
void reserve(int num_nodes)
Definition graph.h:565
void erase_edge(int id)
Erase an edge from the graph.
Definition graph.h:865
ConstNodeRef node(int id) const
Definition graph.h:692
int size() const
Definition graph.h:550
bool empty() const
Definition graph.h:542
int add_node(NT &&data) noexcept
Add a node to the graph.
Definition graph.h:594
const NT & node_data(int id) const
Definition graph.h:695
internal::NodeWrapper< Graph, true > ConstNodeRef
Definition graph.h:497
NT & node_data(int id)
Definition graph.h:694
void clear()
Definition graph.h:697
int add_edges(Iterator begin, Iterator end)
Add multiple edges to the graph.
Definition graph.h:681
const_edge_iterator edge_cend() const
Definition graph.h:984
const_iterator begin() const
Definition graph.h:780
void reserve_edges(int num_edges)
Definition graph.h:570
edge_iterator find_edge(ConstNodeRef src, ConstNodeRef dst)
Find an edge between two nodes.
Definition graph.h:830
adjacency_iterator adj_begin(int nid)
Definition graph.h:1041
NodesErased erase_nodes(const_iterator begin, const_iterator end, UnaryPred pred)
Erase matching nodes and all its associated edge(s) from the graph.
Definition graph.h:1229
std::pair< int, std::vector< int > > erase_edges(Iterator begin, Iterator end)
Erase edges from the graph.
Definition graph.h:1446
NodeRef node(int id)
Definition graph.h:691
adjacency_iterator find_adjacent(int src, int dst)
Find an adjacency entry between two nodes.
Definition graph.h:995
ConstEdgeRef edge(int id) const
Definition graph.h:786
void clear_edges()
Remove all edges from the graph.
Definition graph.h:851
ConstNodeRef edge_dst(int id) const
Definition graph.h:792
NodeRef edge_src(int id)
Definition graph.h:788
const_adjacency_iterator adj_end(int nid) const
Definition graph.h:1044
bool erase_edge_between(int src, int dst)
Erase an edge from the graph between two nodes.
Definition graph.h:1380
const_adjacency_iterator find_adjacent(int src, int dst) const
Find an adjacency entry between two nodes.
Definition graph.h:1008
NodesErased erase_nodes(Iterator begin, Iterator end)
Erase nodes and all its associated edge(s) from the graph.
Definition graph.h:1192
internal::EdgeIterator< Graph, false > edge_iterator
Definition graph.h:499
adjacency_iterator adj_end(int nid)
Definition graph.h:1042
ET & edge_data(int id)
Definition graph.h:794
int num_nodes() const
Definition graph.h:551
std::pair< int, std::vector< int > > erase_edges(const_edge_iterator begin, const_edge_iterator end, UnaryPred pred)
Erase matching edges from the graph.
Definition graph.h:1415
void merge(const GraphLike &other)
Merge another graph-like object into this graph.
Definition graph.h:1062
iterator begin()
Definition graph.h:778
NodeRef operator[](int id)
Definition graph.h:688
const_adjacency_iterator find_adjacent(ConstNodeRef src, ConstNodeRef dst) const
Find an adjacency entry between two nodes.
Definition graph.h:1036
const_iterator end() const
Definition graph.h:781
internal::NodeIterator< Graph, true > const_iterator
Definition graph.h:494
int add_nodes(Iterator begin, Iterator end)
Add multiple nodes to the graph.
Definition graph.h:613
NT node_data_type
Definition graph.h:489
const_edge_iterator find_edge(int src, int dst) const
Find an edge between two nodes.
Definition graph.h:817
internal::AdjWrapper< Graph, true > ConstAdjRef
Definition graph.h:507
internal::EdgeIterator< Graph, true > const_edge_iterator
Definition graph.h:500
internal::NodeWrapper< Graph, false > NodeRef
Definition graph.h:496
edge_iterator edge_end()
Definition graph.h:980
Graph(const Graph &)=default
internal::EdgeWrapper< Graph, false > EdgeRef
Definition graph.h:501
iterator end()
Definition graph.h:779
edge_iterator find_edge(int src, int dst)
Find an edge between two nodes.
Definition graph.h:805
int add_edge(int src, int dst, const BondData &data)
Definition graph.h:635
const_edge_iterator find_edge(ConstNodeRef src, ConstNodeRef dst) const
Find an edge between two nodes.
Definition graph.h:843
bool edge_empty() const
Definition graph.h:553
const_edge_iterator edge_cbegin() const
Definition graph.h:983
int num_edges() const
Definition graph.h:561
internal::AdjIterator< Graph, false > adjacency_iterator
Definition graph.h:504
ET edge_data_type
Definition graph.h:490
iterator node_iterator
Definition graph.h:493
internal::EdgesWrapper< Graph, false > edges()
Definition graph.h:975
Graph(int num_nodes, const NT &data)
Create a graph with num_nodes nodes, each initialized with data.
Definition graph.h:539
EdgeRef edge(int id)
Definition graph.h:785
std::pair< int, std::vector< int > > erase_edges(const_edge_iterator begin, const_edge_iterator end)
Erase edges from the graph.
Definition graph.h:919
NodeRef edge_dst(int id)
Definition graph.h:791
bool erase_edge_between(ConstNodeRef src, ConstNodeRef dst)
Erase an edge from the graph between two nodes.
Definition graph.h:897
const_adjacency_iterator adj_cend(int nid) const
Definition graph.h:1048
edge_iterator edge_begin()
Definition graph.h:979
const_adjacency_iterator adj_cbegin(int nid) const
Definition graph.h:1045
const_edge_iterator edge_end() const
Definition graph.h:982
const_adjacency_iterator adj_begin(int nid) const
Definition graph.h:1043
const_edge_iterator edge_begin() const
Definition graph.h:981
internal::EdgeWrapper< Graph, true > ConstEdgeRef
Definition graph.h:502
internal::EdgesWrapper< Graph, true > edges() const
Definition graph.h:976
const_iterator cend() const
Definition graph.h:783
Graph(Graph &&) noexcept=default
internal::AdjWrapper< Graph, false > AdjRef
Definition graph.h:506
NodesErased erase_nodes(const_iterator begin, const_iterator end)
Erase nodes and all its associated edge(s) from the graph.
Definition graph.h:724
ConstNodeRef operator[](int id) const
Definition graph.h:689
ConstNodeRef edge_src(int id) const
Definition graph.h:789
internal::AdjIterator< Graph, true > const_adjacency_iterator
Definition graph.h:505
const_iterator const_node_iterator
Definition graph.h:495
internal::NodeIterator< Graph, false > iterator
Definition graph.h:492
adjacency_iterator find_adjacent(ConstNodeRef src, ConstNodeRef dst)
Find an adjacency entry between two nodes.
Definition graph.h:1022
const_iterator cbegin() const
Definition graph.h:782
A subgraph of a graph.
Definition subgraph.h:575
adjacency_iterator adj_begin(int idx)
Definition subgraph.h:1539
std::vector< T, Alloc >::size_type erase_if(std::vector< T, Alloc > &c, Pred &&pred)
Definition container_ext.h:55
auto degree(typename boost::graph_traits< Graph< NT, ET > >::vertex_descriptor v, const Graph< NT, ET > &g)
Definition adaptor.h:242
absl::flat_hash_set< int > connected_components(const Graph< NT, ET > &g, int begin)
Find connected components of a graph starting from a node.
Definition graph.h:1578
internal::EigenNeighborIndexer< GT, is_const > as_index(internal::NodeWrapper< GT, is_const > node)
Definition graph.h:1540
std::pair< std::pair< int, std::vector< int > >, std::pair< int, std::vector< int > > > NodesErased
Definition graph.h:456
auto num_edges(const Graph< NT, ET > &g)
Definition adaptor.h:279
ET data
Definition graph.h:486
int dst
Definition graph.h:485
int src
Definition graph.h:484