Commit 8783af44 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Implement all_circuits()

This fixes issue #191
parent da47282a
......@@ -15,6 +15,7 @@ libgraph_tool_topology_la_LIBADD = $(MOD_LIBADD)
libgraph_tool_topology_la_LDFLAGS = $(MOD_LDFLAGS)
libgraph_tool_topology_la_SOURCES = \
graph_all_circuits.cc \
graph_all_distances.cc \
graph_bipartite.cc \
graph_components.cc \
......
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2006-2016 Tiago de Paula Peixoto <tiago@skewed.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <boost/graph/hawick_circuits.hpp>
#include "graph_tool.hh"
#include "numpy_bind.hh"
#include "graph_python_interface.hh"
#ifdef HAVE_BOOST_COROUTINE
#include <boost/coroutine/all.hpp>
#endif // HAVE_BOOST_COROUTINE
using namespace std;
using namespace graph_tool;
template <class Yield>
struct CircuitVisitor
{
CircuitVisitor(Yield& yield)
: _yield(yield) {}
Yield& _yield;
template <class Vs, class Graph>
void cycle(const Vs& vs, Graph&)
{
auto c = wrap_vector_owned(vs);
_yield(c);
}
};
boost::python::object get_all_circuits(GraphInterface& gi, bool unique)
{
#ifdef HAVE_BOOST_COROUTINE
auto dispatch = [&](auto& yield)
{
run_action<>()
(gi,
[&](auto& g)
{
CircuitVisitor<decltype(yield)> visitor(yield);
if (unique)
hawick_unique_circuits(g, visitor);
else
hawick_circuits(g, visitor);
})();
};
return boost::python::object(CoroGenerator(dispatch));
#else
throw GraphException("This functionality is not available because boost::coroutine was not found at compile-time");
#endif // HAVE_BOOST_COROUTINE
}
void export_all_circuits()
{
boost::python::def("get_all_circuits", &get_all_circuits);
};
......@@ -18,6 +18,7 @@
#include <boost/python.hpp>
#include "graph.hh"
#include "random.hh"
#include "numpy_bind.hh"
using namespace boost;
using namespace boost::python;
......@@ -56,6 +57,7 @@ void export_kcore();
void export_similarity();
void export_dists();
void export_all_dists();
void export_all_circuits();
void export_diam();
void export_random_matching();
void export_maximal_vertex_set();
......@@ -83,6 +85,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_topology)
export_similarity();
export_dists();
export_all_dists();
export_all_circuits();
export_diam();
export_random_matching();
export_maximal_vertex_set();
......
......@@ -33,6 +33,7 @@ Summary
all_shortest_paths
all_predecessors
all_paths
all_circuits
pseudo_diameter
similarity
vertex_similarity
......@@ -83,7 +84,7 @@ __all__ = ["isomorphism", "subgraph_isomorphism", "mark_subgraph",
"label_largest_component", "label_biconnected_components",
"label_out_component", "kcore_decomposition", "shortest_distance",
"shortest_path", "all_shortest_paths", "all_predecessors",
"all_paths", "pseudo_diameter", "is_bipartite", "is_DAG",
"all_paths", "all_circuits", "pseudo_diameter", "is_bipartite", "is_DAG",
"is_planar", "make_maximal_planar", "similarity", "vertex_similarity",
"edge_reciprocity"]
......@@ -1731,6 +1732,59 @@ def all_paths(g, source, target, cutoff=None):
_prop("v", g, visited))
return path_iterator
def all_circuits(g, unique=False):
"""Return an iterator over all the cycles in a directed graph.
Parameters
----------
g : :class:`~graph_tool.Graph`
A directed graph to be used.
unique : ``bool`` (optional, default: None)
If ``True``, parallel edges and self-loops will be ignored.
Returns
-------
cycle_iterator : iterator over a sequence of integers
Iterator over sequences of vertices that form a circuit.
Notes
-----
This algorithm [hawick-enumerating-2008]_ runs in worse time
:math:`O[(V + E)(C + 1)]`, where :math:`C` is the number of circuits.
Examples
--------
.. testcode::
:hide:
gt.seed_rng(42)
>>> g = gt.random_graph(10, lambda: (1, 1))
>>> for c in gt.all_circuits(g):
... print(c)
[13 15 2]
[13 60 2]
[13 64 2]
[ 13 100 2]
[ 13 106 2]
[13 2]
References
----------
.. [hawick-enumerating-2008] K.A. Hawick and H.A. James, "Enumerating
Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs.",
In Proceedings of FCS. 2008, 14-20,
http://cssg.massey.ac.nz/cstn/013/cstn-013.html
.. [hawick-bgl] http://www.boost.org/doc/libs/graph/doc/hawick_circuits.html
"""
if not g.is_directed():
raise ValueError("The graph must be directed.")
circuits_iterator = libgraph_tool_topology.get_all_circuits(g._Graph__graph,
unique)
return circuits_iterator
def pseudo_diameter(g, source=None, weights=None):
"""
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment