Commit 6749a383 authored by Tiago Peixoto's avatar Tiago Peixoto

Implement topology.max_independent_vertex_set()

parent 335cd9b8
......@@ -21,6 +21,7 @@ libgraph_tool_topology_la_SOURCES = \
graph_diameter.cc \
graph_dominator_tree.cc \
graph_isomorphism.cc \
graph_maximal_vertex_set.cc \
graph_minimum_spanning_tree.cc \
graph_planar.cc \
graph_random_matching.cc \
......
// Copyright (C) 2006-2011 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 "graph.hh"
#include "graph_filtering.hh"
#include "graph_properties.hh"
#include "graph_selectors.hh"
#include "graph_util.hh"
#include <boost/python.hpp>
#if (GCC_VERSION >= 40400)
# include <tr1/random>
#else
# include <boost/tr1/random.hpp>
#endif
using namespace std;
using namespace boost;
using namespace graph_tool;
typedef tr1::mt19937 rng_t;
struct do_maximal_vertex_set
{
template <class Graph, class VertexIndex, class VertexSet,
class RNG>
void operator()(const Graph& g, VertexIndex vertex_index, VertexSet mvs,
bool high_deg, RNG& rng) const
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
typedef typename property_traits<VertexSet>::value_type wval_t;
tr1::variate_generator<RNG&, tr1::uniform_real<> >
sample(rng, tr1::uniform_real<>(0, 1));
VertexSet marked(vertex_index, num_vertices(g));
vector<vertex_t> vlist;
double max_deg = 0, tmp_max_deg = 0;
typename graph_traits<Graph>::vertex_iterator v, v_end;
for (tie(v, v_end) = vertices(g); v != v_end; ++v)
{
vlist.push_back(*v);
mvs[*v] = marked[*v] = false;
max_deg = max(out_degree(*v, g), max_deg);
}
vector<vertex_t> selected, tmp;
tmp.reserve(vlist.size());
selected.reserve(vlist.size());
while (!vlist.empty())
{
selected.clear();
tmp.clear();
tmp_max_deg = 0;
int i, N = vlist.size();
#pragma omp parallel for default(shared) private(i)
for (i = 0; i < N; ++i)
{
typename graph_traits<Graph>::vertex_descriptor v =
vlist[i];
marked[v] = false;
bool include = true;
typename graph_traits<Graph>::adjacency_iterator a, a_end;
for(tie(a, a_end) = adjacent_vertices(v, g); a != a_end; ++a)
{
if (mvs[*a])
{
include = false;
break;
}
}
if (!include)
continue;
include = false;
if (out_degree(v, g) > 0)
{
double p, r;
if (high_deg)
p = out_degree(v, g) / max_deg;
else
p = 1. / (2 * out_degree(v, g));
{
#pragma omp critical
r = sample();
}
if (r < p)
include = true;
}
else
{
include = true;
}
if (include)
{
marked[v] = true;
{
#pragma omp critical
selected.push_back(v);
}
}
else
{
#pragma omp critical
tmp.push_back(v);
tmp_max_deg = max(tmp_max_deg, out_degree(v, g));
}
}
N = selected.size();
#pragma omp parallel for default(shared) private(i)
for (i = 0; i < N; ++i)
{
typename graph_traits<Graph>::vertex_descriptor v =
selected[i];
bool include = true;
typename graph_traits<Graph>::adjacency_iterator a, a_end;
for(tie(a, a_end) = adjacent_vertices(v, g); a != a_end; ++a)
{
if (*a == v) //skip self-loops
continue;
if (mvs[*a])
{
include = false;
break;
}
if (marked[*a])
{
bool inc = ((high_deg && (out_degree(v, g) >
out_degree(*a, g))) ||
(!high_deg && (out_degree(v, g) <
out_degree(*a, g))));
if (out_degree(v, g) == out_degree(*a, g))
inc = v < *a;
include = include && inc;
}
}
if (include)
{
mvs[v] = true;
}
else
{
#pragma omp critical
tmp.push_back(v);
tmp_max_deg = max(tmp_max_deg, out_degree(v, g));
}
marked[v] = false;
}
vlist = tmp;
max_deg = tmp_max_deg;
}
}
};
void maximal_vertex_set(GraphInterface& gi, boost::any mvs, bool high_deg,
size_t seed)
{
rng_t rng(static_cast<rng_t::result_type>(seed));
run_action<>()
(gi, bind<void>(do_maximal_vertex_set(), _1, gi.GetVertexIndex(),
_2, high_deg, ref(rng)),
writable_vertex_scalar_properties())(mvs);
}
void export_maximal_vertex_set()
{
python::def("maximal_vertex_set", &maximal_vertex_set);
}
......@@ -63,4 +63,5 @@ BOOST_PYTHON_MODULE(libgraph_tool_topology)
export_all_dists();
export_diam();
export_random_matching();
export_maximal_vertex_set();
}
......@@ -35,6 +35,8 @@ Summary
isomorphism
subgraph_isomorphism
mark_subgraph
max_cardinality_matching
max_independent_vertex_set
min_spanning_tree
dominator_tree
topological_sort
......@@ -60,8 +62,8 @@ __all__ = ["isomorphism", "subgraph_isomorphism", "mark_subgraph",
"max_cardinality_matching", "max_independent_vertex_set",
"min_spanning_tree", "dominator_tree", "topological_sort",
"transitive_closure", "label_components", "label_largest_component",
"label_biconnected_components", "shortest_distance",
"shortest_path", "pseudo_diameter", "is_planar", "similarity"]
"label_biconnected_components", "shortest_distance", "shortest_path",
"pseudo_diameter", "is_planar", "similarity"]
def similarity(g1, g2, label1=None, label2=None, norm=True):
......@@ -1174,3 +1176,70 @@ def max_cardinality_matching(g, heuristic=False, weight=None, minimize=True,
random_matching(u._Graph__graph, _prop("e", u, weight),
_prop("e", u, match), minimize, seed)
return match
def max_independent_vertex_set(g, high_deg=False, mivs=None):
r"""Find the maximum cardinality matching in the graph.
Parameters
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
high_deg : bool (optional, default: `False`)
If `True`, vertices with high degree will be included first in the set,
otherwise they will be included last.
mivs : :class:`~graph_tool.PropertyMap` (optional, default: `None`)
Vertex property map where the vertex set will be specified.
Returns
-------
match : :class:`~graph_tool.PropertyMap`
Boolean edge property map where the matching is specified.
is_maximal : bool
True if the matching is indeed maximal, or False otherwise. This is only
returned if ``heuristic == False``.
Notes
-----
A *matching* is a subset of the edges of a graph such that no two edges
share a common vertex. A *maximum cardinality matching* has maximum size
over all matchings in the graph.
For a more detailed description, see [boost-max-matching]_.
Examples
--------
>>> from numpy.random import seed, random
>>> seed(43)
>>> g = gt.random_graph(100, lambda: (2,2))
>>> res = gt.max_cardinality_matching(g)
>>> print res[1]
True
>>> gt.graph_draw(g, ecolor=res[0], output="max_card_match.pdf")
<...>
.. figure:: max_card_match.*
:align: center
Edges belonging to the matching are in red.
References
----------
.. [boost-max-matching] http://www.boost.org/libs/graph/doc/maximum_matching.html
.. [matching-heuristic] B. Hendrickson and R. Leland. "A Multilevel Algorithm
for Partitioning Graphs." In S. Karin, editor, Proc. Supercomputing ’95,
San Diego. ACM Press, New York, 1995, :doi:`10.1145/224170.224228`
"""
if mivs is None:
mivs = g.new_vertex_property("bool")
_check_prop_scalar(mivs, "mivs")
_check_prop_writable(mivs, "mivs")
seed = numpy.random.randint(0, sys.maxint)
u = GraphView(g, directed=False)
libgraph_tool_topology.\
maximal_vertex_set(u._Graph__graph, _prop("v", u, mivs), high_deg,
seed)
mivs = g.own_property(mivs)
return mivs
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