How to use the O(1) remove_edge(typename Config::out_edge_iterator iter)
I looked at runtime statements here: https://www.boost.org/doc/libs/1_85_0/libs/graph/doc/using_adjacency_list.ht... Fore remove_edge() there is no O(1) option listed. On the other hand in Boost graph code I see this O(1) remove_edge() in boost/graph/detail/adjacency_list.hpp: template < class Config > struct directed_edges_helper { ... // O(1) inline void remove_edge(typename Config::out_edge_iterator iter) { std::cerr << "foobar" << std::endl; typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(*this); typename Config::edge_descriptor e = *iter; typename Config::OutEdgeList& el = g.out_edge_list(source(e, g)); el.erase(iter.base()); } }; So my questions is for which graph and how I can make use of that O(1) function to remove an edge. It seems to be for directed graph only. While I need it for undirected graph, being able to use that O(1) function for directed graph would be a first step. Regards, Hermann Stamm-Wilbrandt.
On 2024-08-05 22:37, Hermann Stamm-Wilbrandt via Boost wrote:
Fore remove_edge() there is no O(1) option listed.
On the other hand in Boost graph code I see this O(1) remove_edge() in boost/graph/detail/adjacency_list.hpp:
template < class Config > struct directed_edges_helper { ... // O(1) inline void remove_edge(typename Config::out_edge_iterator iter) { std::cerr << "foobar" << std::endl; typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(*this); typename Config::edge_descriptor e = *iter; typename Config::OutEdgeList& el = g.out_edge_list(source(e, g)); el.erase(iter.base()); } };
So my questions is for which graph and how I can make use of that O(1) function to remove an edge. It seems to be for directed graph only. While I need it for undirected graph, being able to use that O(1) function for directed graph would be a first step.
I went a step further, transferred the directed O(1) concept to undirected graph. Given an out_edge_iterator it can be removed in O(1), and that is true for undirected graph as well. This small demo code piece: ... out_edge_iterator it = out_edges(v1, g).first; g.remove_edge(it); ... between two print_graph() statements shows that the concept works. The (only) edge gets removed from out edge list of v1 only: pi@raspberrypi5:~ $ g++ ug_demo.cpp pi@raspberrypi5:~ $ ./a.out 0 <--> 1 <--> 2 2 <--> 1 foobar foobar2 0 <--> 1 <--> 2 <--> 1 pi@raspberrypi5:~ $ I had to add "void remove_edge(out_edge_iterator i)" to graph/undirected_graph.h ... void remove_edge(edge_iterator i) { remove_edge(*i); } + void remove_edge(out_edge_iterator i) { + std::cerr << "foobar" << std::endl; + boost::remove_edge(i, m_graph); + } + void remove_edge(edge_descriptor e) ... and modify (only for proof of concept) in graph/detail/adjacency_list.hpp: // O(E/V) inline void remove_edge(typename Config::out_edge_iterator iter) { - this->remove_edge(*iter); + std::cerr << "foobar2" << std::endl; + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast< graph_type& >(*this); + typename Config::edge_descriptor e = *iter; + auto el = g.out_edge_list(source(e, g)); + el.erase(iter.base()); + +// this->remove_edge(*iter); } }; An undirected edge needs to know its out_edge_iterators for both of its vertices. I plan to use an edge map of std::pair of out_edge_iterators and initialize for each edge correctly. Then I will be able to do a sequence of edge removals taking O(1) time for each edge removal ... Regards, Hermann.
On 2024-08-07 17:42, Hermann Stamm-Wilbrandt via Boost wrote:
I had to add "void remove_edge(out_edge_iterator i)" to graph/undirected_graph.h ...
void remove_edge(edge_iterator i) { remove_edge(*i); }
+ void remove_edge(out_edge_iterator i) { + std::cerr << "foobar" << std::endl; + boost::remove_edge(i, m_graph); + } + void remove_edge(edge_descriptor e)
... and modify (only for proof of concept) in graph/detail/adjacency_list.hpp:
// O(E/V) inline void remove_edge(typename Config::out_edge_iterator iter) { - this->remove_edge(*iter); + std::cerr << "foobar2" << std::endl; + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast< graph_type& >(*this); + typename Config::edge_descriptor e = *iter; + auto el = g.out_edge_list(source(e, g)); + el.erase(iter.base()); + +// this->remove_edge(*iter); } };
I just comitted
https://github.com/Hermann-SW/graph/commit/fca0056ea64a1637d7602aaddbb7cad4c...
implementation of O(1) "remove_edge(out_edge_iterator,
out_edge_iterator)".
I followed the steps needed seen for "remove_edge(edge_descriptor e)"
implementation in undirected_graph.hpp, up to and including the
dispatcher stuff in detail/adjacency_list.hpp.
Short demo and description can be found here:
https://github.com/Hermann-SW/graph?tab=readme-ov-file#fork-mission-statemen...
Later I added assertions guaranteeing being correctly called:
typename Config::edge_descriptor e = *iter1;
typename Config::edge_descriptor f = *iter2;
BOOST_ASSERT(source(e, g) == target(f, g));
BOOST_ASSERT(source(f, g) == target(e, g));
Next steps:
- create edge_map with std::pair
participants (1)
-
hermann@stamm-wilbrandt.de