Commit 2a21ab19 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Implement k-core decomposition

parent 072781c0
......@@ -22,6 +22,7 @@ libgraph_tool_topology_la_SOURCES = \
graph_diameter.cc \
graph_dominator_tree.cc \
graph_isomorphism.cc \
graph_kcore.cc \
graph_maximal_planar.cc \
graph_maximal_vertex_set.cc \
graph_minimum_spanning_tree.cc \
......@@ -40,5 +41,6 @@ libgraph_tool_topology_la_SOURCES = \
libgraph_tool_topology_la_include_HEADERS = \
graph_components.hh \
graph_kcore.hh \
graph_similarity.hh \
graph_subgraph_isomorphism.hh
\ No newline at end of file
// Copyright (C) 2006-2013 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_kcore.hh"
#include <boost/python.hpp>
using namespace std;
using namespace boost;
using namespace graph_tool;
void do_kcore_decomposition(GraphInterface& gi, boost::any prop,
GraphInterface::deg_t deg)
{
run_action<>()(gi, bind<void>(kcore_decomposition(), _1,
gi.GetVertexIndex(), _2, _3),
writable_vertex_scalar_properties(),
degree_selectors())(prop, degree_selector(deg));
}
void export_kcore()
{
python::def("kcore_decomposition", &do_kcore_decomposition);
};
// Copyright (C) 2006-2013 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/>.
#ifndef GRAPH_KCORE_HH
#define GRAPH_KCORE_HH
namespace graph_tool
{
using namespace std;
using namespace boost;
struct kcore_decomposition
{
template <class Graph, class VertexIndex, class CoreMap, class DegSelector>
void operator()(Graph& g, VertexIndex vertex_index, CoreMap core_map,
DegSelector degS) const
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
unchecked_vector_property_map<size_t, VertexIndex> deg(vertex_index,
num_vertices(g));
unchecked_vector_property_map<size_t, VertexIndex> pos(vertex_index,
num_vertices(g));
vector<vector<vertex_t> > bins;
typename graph_traits<Graph>::vertex_iterator vi, vi_end;
for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
{
size_t k = degS(*vi, g);
deg[*vi] = k;
if (k >= bins.size())
bins.resize(k + 1);
bins[k].push_back(*vi);
pos[*vi] = bins[k].size() - 1;
}
for (size_t k = 0; k < bins.size(); ++k)
{
while (!bins[k].empty())
{
vertex_t v = bins[k].back();
bins[k].pop_back();
core_map[v] = k;
typename graph_traits<Graph>::out_edge_iterator e, e_end;
for (tie(e, e_end) = out_edges(v, g); e != e_end; ++e)
{
vertex_t u = target(*e, g);
if (deg[u] > deg[v])
{
size_t ku = deg[u];
vertex_t w = bins[ku].back();
pos[w] = pos[u];
bins[ku][pos[w]] = w;
bins[ku].pop_back();
bins[ku - 1].push_back(u);
pos[u] = bins[ku - 1].size() - 1;
--deg[u];
}
}
}
}
}
};
} // graph_tool namespace
#endif // GRAPH_KCORE_HH
......@@ -49,6 +49,7 @@ void get_random_spanning_tree(GraphInterface& gi, size_t root,
vector<int32_t> get_tsp(GraphInterface& gi, size_t src, boost::any weight_map);
void export_components();
void export_kcore();
void export_similarity();
void export_dists();
void export_all_dists();
......@@ -74,6 +75,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_topology)
def("random_spanning_tree", &get_random_spanning_tree);
def("get_tsp", &get_tsp);
export_components();
export_kcore();
export_similarity();
export_dists();
export_all_dists();
......
......@@ -48,6 +48,7 @@ Summary
label_biconnected_components
label_largest_component
label_out_component
kcore_decomposition
is_bipartite
is_DAG
is_planar
......@@ -66,7 +67,7 @@ dl_import("from . import libgraph_tool_topology")
from .. import _prop, Vector_int32_t, _check_prop_writable, \
_check_prop_scalar, _check_prop_vector, Graph, PropertyMap, GraphView,\
libcore, _get_rng
libcore, _get_rng, _degree
import random, sys, numpy
__all__ = ["isomorphism", "subgraph_isomorphism", "mark_subgraph",
"max_cardinality_matching", "max_independent_vertex_set",
......@@ -74,9 +75,9 @@ __all__ = ["isomorphism", "subgraph_isomorphism", "mark_subgraph",
"topological_sort", "transitive_closure", "tsp_tour",
"sequential_vertex_coloring", "label_components",
"label_largest_component", "label_biconnected_components",
"label_out_component", "shortest_distance", "shortest_path",
"pseudo_diameter", "is_bipartite", "is_DAG", "is_planar",
"make_maximal_planar", "similarity", "edge_reciprocity"]
"label_out_component", "kcore_decomposition", "shortest_distance",
"shortest_path", "pseudo_diameter", "is_bipartite", "is_DAG",
"is_planar", "make_maximal_planar", "similarity", "edge_reciprocity"]
def similarity(g1, g2, label1=None, label2=None, norm=True):
......@@ -928,6 +929,82 @@ def label_biconnected_components(g, eprop=None, vprop=None):
_prop("v", g, vprop))
return eprop, vprop, hist
def kcore_decomposition(g, deg="out", vprop=None):
"""
Perform a k-core decomposition of the given graph.
Parameters
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
deg : string
Degree to be used for the decomposition. It can be either "in", "out" or
"total", for in-, out-, or total degree of the vertices.
vprop : :class:`~graph_tool.PropertyMap` (optional, default: ``None``)
Vertex property to store the decomposition. If ``None`` is supplied,
one is created.
Returns
-------
kval : :class:`~graph_tool.PropertyMap`
Vertex property map with the k-core decomposition, i.e. a given vertex v
belongs to the ``kval[v]``-core.
Notes
-----
The k-core is a maximal set of vertices such that its induced subgraph only
contains vertices with degree larger than or equal to k.
This algorithm is described in [batagelk-algorithm]_ and runs in :math:`O(V + E)`
time.
Examples
--------
>>> g = gt.collection.data["netscience"]
>>> g = gt.GraphView(g, vfilt=gt.label_largest_component(g))
>>> kcore = gt.kcore_decomposition(g)
>>> gt.graph_draw(g, pos=g.vp["pos"], vertex_fill_color=kcore, vertex_text=kcore, output="netsci-kcore.pdf")
<...>
.. testcode::
:hide:
gt.graph_draw(g, pos=g.vp["pos"], vertex_fill_color=kcore, vertex_text=kcore, output="netsci-kcore.png")
.. figure:: netsci-kcore.*
:align: center
K-core decomposition of a network of network scientists.
References
----------
.. [k-core] http://en.wikipedia.org/wiki/Degeneracy_%28graph_theory%29
.. [batagelk-algorithm] V. Batagelj, M. Zaversnik, "An O(m) Algorithm for
Cores Decomposition of Networks", 2003, :arxiv:`cs/0310049`
"""
if vprop is None:
vprop = g.new_vertex_property("int32_t")
_check_prop_writable(vprop, name="vprop")
_check_prop_scalar(vprop, name="vprop")
if deg not in ["in", "out", "total"]:
raise ValueError("invalid degree: " + str(deg))
if g.is_directed():
if deg == "out":
g = GraphView(g, reversed=True)
if deg == "total":
g = GraphView(g, directed=False)
libgraph_tool_topology.\
kcore_decomposition(g._Graph__graph, _prop("v", g, vprop),
_degree(g, deg))
return vprop
def shortest_distance(g, source=None, weights=None, max_dist=None,
directed=None, dense=False, dist_map=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