Skip to content

Commit

Permalink
Fix the O(n^3) performance issue in is_connected utility function.
Browse files Browse the repository at this point in the history
Adhere to the specification in comment:
// Is the undirected graph connected?
// Is the directed graph strongly connected?

Instead of checking if each vertex is reachable from each vertex (which is O(n^3)),
consider different approaches for directed and undirected graphs:

For an undirected graph check if each vertex was reachable with a single DFS walk.
This runs in O(N) (modulo back edges).

For a directed graph run Tarjan SCC algorithm and check if all vertices end up in
a single component. This runs in O(N+E).

The speed-up is considerable, e.g. for a 25x25 square connected graph it is about:

time: undirected, connected - prev implementation - elapsed 	16.458s
time: undirected, connected - new  implementation - elapsed 	6.1249e-05s
time: directed, connected - prev implementation - elapsed 	7.45684s
time: directed, connected - new  implementation - elapsed 	4.9894e-05s

For similar 80x80 graph it's about 0.000563113s, while it just takes forever
with the previous O(n^3) approach.
  • Loading branch information
Wavetrace committed Nov 11, 2024
1 parent f1e51a0 commit 80ae041
Showing 1 changed file with 43 additions and 14 deletions.
57 changes: 43 additions & 14 deletions include/boost/graph/graph_utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <assert.h>
#include <boost/config.hpp>
#include <boost/tuple/tuple.hpp>

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/strong_components.hpp>
#include <boost/pending/container_traits.hpp>
#include <boost/graph/depth_first_search.hpp>
// iota moved to detail/algorithm.hpp
Expand Down Expand Up @@ -339,27 +341,54 @@ inline bool is_reachable(
return get(color, y) != color_traits< ColorValue >::white();
}

// Is the undirected graph connected?
// Is the directed graph strongly connected?
template < typename VertexListGraph, typename VertexColorMap >
inline bool is_connected(const VertexListGraph& g, VertexColorMap color)
template < typename Graph, typename VertexColorMap >
inline bool is_connected_dispatch(const Graph& g, VertexColorMap color, undirected_tag)
{
// color map should start out white for each vertex
typedef typename property_traits< VertexColorMap >::value_type ColorValue;
typedef color_traits< ColorValue > Color;
typename graph_traits< VertexListGraph >::vertex_iterator ui, ui_end, vi,
vi_end, ci, ci_end;

default_dfs_visitor vis;
detail::depth_first_visit_impl(g, detail::get_default_starting_vertex(g),
vis, color, detail::nontruth2());

// If an undirected graph is connected, then each vertex is reachable in a
// single DFS visit. If any vertex was unreachable, grpah is not connected.
typename graph_traits< Graph >::vertex_iterator ui, ui_end;
for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui)
for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
if (*ui != *vi)
{
for (boost::tie(ci, ci_end) = vertices(g); ci != ci_end; ++ci)
put(color, *ci, Color::white());
if (!is_reachable(*ui, *vi, g, color))
return false;
}
if (get(color, *ui) == Color::white())
return false;
return true;

}

template < typename Graph, typename VertexColorMap >
inline bool is_connected_dispatch(const Graph& g, VertexColorMap, directed_tag)
{
// Run the Tarjan SCC algorithm
std::vector< size_t > comp_map(num_vertices(g));
strong_components(g,
make_iterator_property_map(comp_map.begin(), get(vertex_index, g)));

// If the directed graph is strongly connected, all vertices are in
// the same component 0
for (std::vector< size_t >::const_iterator i = comp_map.begin();
i != comp_map.end(); ++i)
if (*i > 0)
return false;
return true;
}


// Is the undirected graph connected?
// Is the directed graph strongly connected?
template < typename VertexListGraph, typename VertexColorMap >
inline bool is_connected(const VertexListGraph& g, VertexColorMap color)
{
typedef typename graph_traits< VertexListGraph >::directed_category Cat;
return is_connected_dispatch(g, color, Cat());
}

template < typename Graph >
bool is_self_loop(
typename graph_traits< Graph >::edge_descriptor e, const Graph& g)
Expand Down

0 comments on commit 80ae041

Please sign in to comment.