mirror of
https://github.com/boostorg/graph.git
synced 2025-05-09 23:14:00 +00:00
Optionally specify a maximum circuit length in Hawick circuits algorithm
This commit is contained in:
parent
c9f515347b
commit
3f75ea7aa3
@ -13,13 +13,13 @@
|
||||
<h1 id="hawick_circuits"><code>hawick_circuits</code></h1>
|
||||
|
||||
<pre><code>template <typename Graph, typename Visitor, typename VertexIndexMap>
|
||||
void hawick_circuits(Graph const& graph, Visitor visitor, VertexIndexMap const& vim = get(vertex_index, graph));
|
||||
void hawick_circuits(Graph const& graph, Visitor visitor, VertexIndexMap const& vim = get(vertex_index, graph), unsigned int const maxLength = 0);
|
||||
|
||||
template <typename Graph, typename Visitor, typename VertexIndexMap>
|
||||
void hawick_unique_circuits(Graph const& graph, Visitor visitor, VertexIndexMap const& vim = get(vertex_index, graph));
|
||||
void hawick_unique_circuits(Graph const& graph, Visitor visitor, VertexIndexMap const& vim = get(vertex_index, graph), unsigned int const maxLength = 0);
|
||||
</code></pre>
|
||||
|
||||
<p>Enumerate all the elementary circuits in a directed multigraph. Specifically,
|
||||
<p>Enumerate all the elementary circuits (of length ≤ <code>maxLength</code>, if nonzero) in a directed multigraph. Specifically,
|
||||
self-loops and redundant circuits caused by parallel edges are enumerated too.
|
||||
<code>hawick_unique_circuits</code> may be used if redundant circuits caused by parallel
|
||||
edges are not desired.</p>
|
||||
@ -59,6 +59,12 @@ edges are not desired.</p>
|
||||
the vertex index map provided by the <code>graph</code>.</p>
|
||||
</blockquote>
|
||||
|
||||
<p><strong>IN:</strong> <code>unsigned int const maxLength = 0</code></p>
|
||||
|
||||
<blockquote>
|
||||
<p>The maximum circuit length to consider. Beyond this it truncates the depth-first search, reducing the computation time by ignoring longer circuits. The default value of <code>maxLength = 0</code> implies no maximum.</p>
|
||||
</blockquote>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="footer">
|
||||
|
@ -78,7 +78,7 @@ int main(int argc, char const* argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
std::cout << "usage: " << argv[0] << " num_vertices < input\n";
|
||||
std::cout << "usage: " << argv[0] << " <num_vertices> <max_length (optional)>\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@ -88,7 +88,12 @@ int main(int argc, char const* argv[])
|
||||
build_graph(graph, num_vertices, first_vertex, last_vertex);
|
||||
|
||||
cycle_printer< std::ostream > visitor(std::cout);
|
||||
boost::hawick_circuits(graph, visitor);
|
||||
if (argc == 2) {
|
||||
boost::hawick_circuits(graph, visitor);
|
||||
} else {
|
||||
unsigned int max_length = boost::lexical_cast< unsigned int >(argv[2]);
|
||||
boost::hawick_circuits(graph, visitor, max_length);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -153,13 +153,14 @@ namespace hawick_circuits_detail
|
||||
public:
|
||||
hawick_circuits_from(Graph const& graph, Visitor& visitor,
|
||||
VertexIndexMap const& vim, Stack& stack, ClosedMatrix& closed,
|
||||
VerticesSize n_vertices)
|
||||
VerticesSize n_vertices, unsigned int const maxLength)
|
||||
: graph_(graph)
|
||||
, visitor_(visitor)
|
||||
, vim_(vim)
|
||||
, stack_(stack)
|
||||
, closed_(closed)
|
||||
, blocked_(n_vertices, vim_)
|
||||
, maxLength_(maxLength)
|
||||
{
|
||||
BOOST_ASSERT(blocked_map_starts_all_unblocked());
|
||||
|
||||
@ -224,6 +225,10 @@ namespace hawick_circuits_detail
|
||||
stack_.push_back(v);
|
||||
block(v);
|
||||
|
||||
// Truncate the search if any circuits would exceed maxLength_.
|
||||
bool const truncate_search =
|
||||
(maxLength_ > 0 && stack_.size() >= maxLength_);
|
||||
|
||||
// Cache some values that are used more than once in the function.
|
||||
VertexIndex const index_of_start = index_of(start);
|
||||
AdjacentVertices const adj_vertices
|
||||
@ -249,13 +254,19 @@ namespace hawick_circuits_detail
|
||||
found_circuit = true;
|
||||
}
|
||||
|
||||
// If required, truncate the search before the subsequent
|
||||
// recursive call to circuit().
|
||||
else if (truncate_search)
|
||||
continue;
|
||||
|
||||
// If `w` is not blocked, we continue searching further down the
|
||||
// same path for a cycle with `w` in it.
|
||||
else if (!is_blocked(w) && circuit(start, w))
|
||||
found_circuit = true;
|
||||
}
|
||||
|
||||
if (found_circuit)
|
||||
bool const finish_circuit = (found_circuit || truncate_search);
|
||||
if (finish_circuit)
|
||||
unblock(v);
|
||||
else
|
||||
for (AdjacencyIterator w_it = boost::begin(adj_vertices);
|
||||
@ -274,7 +285,7 @@ namespace hawick_circuits_detail
|
||||
|
||||
BOOST_ASSERT(v == stack_.back());
|
||||
stack_.pop_back();
|
||||
return found_circuit;
|
||||
return finish_circuit;
|
||||
}
|
||||
|
||||
public:
|
||||
@ -287,12 +298,14 @@ namespace hawick_circuits_detail
|
||||
Stack& stack_;
|
||||
ClosedMatrix& closed_;
|
||||
BlockedMap blocked_;
|
||||
unsigned int const maxLength_;
|
||||
};
|
||||
|
||||
template < typename GetAdjacentVertices, typename Graph, typename Visitor,
|
||||
typename VertexIndexMap >
|
||||
void call_hawick_circuits(Graph const& graph,
|
||||
Visitor /* by value */ visitor, VertexIndexMap const& vertex_index_map)
|
||||
Visitor /* by value */ visitor, VertexIndexMap const& vertex_index_map,
|
||||
unsigned int const maxLength)
|
||||
{
|
||||
typedef graph_traits< Graph > Traits;
|
||||
typedef typename Traits::vertex_descriptor Vertex;
|
||||
@ -322,7 +335,8 @@ namespace hawick_circuits_detail
|
||||
// construction. It would be strictly equivalent to have these as
|
||||
// member variables of the sub algorithm.
|
||||
SubAlgorithm sub_algo(
|
||||
graph, visitor, vertex_index_map, stack, closed, n_vertices);
|
||||
graph, visitor, vertex_index_map, stack, closed, n_vertices,
|
||||
maxLength);
|
||||
sub_algo(*start);
|
||||
stack.clear();
|
||||
typename ClosedMatrix::iterator row, last_row = closed.end();
|
||||
@ -333,30 +347,35 @@ namespace hawick_circuits_detail
|
||||
|
||||
template < typename GetAdjacentVertices, typename Graph, typename Visitor >
|
||||
void call_hawick_circuits(
|
||||
Graph const& graph, BOOST_FWD_REF(Visitor) visitor)
|
||||
Graph const& graph, BOOST_FWD_REF(Visitor) visitor,
|
||||
unsigned int const maxLength)
|
||||
{
|
||||
call_hawick_circuits< GetAdjacentVertices >(graph,
|
||||
boost::forward< Visitor >(visitor), get(vertex_index, graph));
|
||||
boost::forward< Visitor >(visitor), get(vertex_index, graph),
|
||||
maxLength);
|
||||
}
|
||||
} // end namespace hawick_circuits_detail
|
||||
|
||||
//! Enumerate all the elementary circuits in a directed multigraph.
|
||||
template < typename Graph, typename Visitor, typename VertexIndexMap >
|
||||
void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor,
|
||||
BOOST_FWD_REF(VertexIndexMap) vertex_index_map)
|
||||
BOOST_FWD_REF(VertexIndexMap) vertex_index_map,
|
||||
unsigned int const maxLength = 0)
|
||||
{
|
||||
hawick_circuits_detail::call_hawick_circuits<
|
||||
hawick_circuits_detail::get_all_adjacent_vertices >(
|
||||
boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
|
||||
boost::forward< VertexIndexMap >(vertex_index_map));
|
||||
boost::forward< VertexIndexMap >(vertex_index_map), maxLength);
|
||||
}
|
||||
|
||||
template < typename Graph, typename Visitor >
|
||||
void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor)
|
||||
void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor,
|
||||
unsigned int const maxLength = 0)
|
||||
{
|
||||
hawick_circuits_detail::call_hawick_circuits<
|
||||
hawick_circuits_detail::get_all_adjacent_vertices >(
|
||||
boost::forward< Graph >(graph), boost::forward< Visitor >(visitor));
|
||||
boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
|
||||
maxLength);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -366,21 +385,24 @@ void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor)
|
||||
template < typename Graph, typename Visitor, typename VertexIndexMap >
|
||||
void hawick_unique_circuits(BOOST_FWD_REF(Graph) graph,
|
||||
BOOST_FWD_REF(Visitor) visitor,
|
||||
BOOST_FWD_REF(VertexIndexMap) vertex_index_map)
|
||||
BOOST_FWD_REF(VertexIndexMap) vertex_index_map,
|
||||
unsigned int const maxLength = 0)
|
||||
{
|
||||
hawick_circuits_detail::call_hawick_circuits<
|
||||
hawick_circuits_detail::get_unique_adjacent_vertices >(
|
||||
boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
|
||||
boost::forward< VertexIndexMap >(vertex_index_map));
|
||||
boost::forward< VertexIndexMap >(vertex_index_map), maxLength);
|
||||
}
|
||||
|
||||
template < typename Graph, typename Visitor >
|
||||
void hawick_unique_circuits(
|
||||
BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor)
|
||||
BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor,
|
||||
unsigned int const maxLength = 0)
|
||||
{
|
||||
hawick_circuits_detail::call_hawick_circuits<
|
||||
hawick_circuits_detail::get_unique_adjacent_vertices >(
|
||||
boost::forward< Graph >(graph), boost::forward< Visitor >(visitor));
|
||||
boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
|
||||
maxLength);
|
||||
}
|
||||
} // end namespace boost
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user