Commit 3a95582f authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Implement `return_maps` option in motifs()

This returns an optional list of locations of the motifs found in the
main graph.
parent 1e2702b4
......@@ -56,8 +56,8 @@ using namespace boost::python;
void extended_clustering(GraphInterface& g, python::list props);
void get_motifs(GraphInterface& g, size_t k, python::list subgraph_list,
python::list hist, python::list p, bool comp_iso,
bool fill_list, rng_t& rng);
python::list hist, python::list pvmaps, bool collect_vmaps,
python::list p, bool comp_iso, bool fill_list, rng_t& rng);
BOOST_PYTHON_MODULE(libgraph_tool_clustering)
{
......
......@@ -22,6 +22,8 @@
#include "graph_properties.hh"
#include "graph_util.hh"
#include "graph_python_interface.hh"
#include "graph_motifs.hh"
#include <boost/python.hpp>
......@@ -66,8 +68,8 @@ struct retrieve_from_list
};
void get_motifs(GraphInterface& g, size_t k, python::list subgraph_list,
python::list hist, python::list p, bool comp_iso,
bool fill_list, rng_t& rng)
python::list hist, python::list pvmaps, bool collect_vmaps,
python::list p, bool comp_iso, bool fill_list, rng_t& rng)
{
boost::any list;
if (g.GetDirected())
......@@ -105,15 +107,29 @@ void get_motifs(GraphInterface& g, size_t k, python::list subgraph_list,
else
sampler = sample_some(plist, rng);
typedef property_map_type
::apply<int32_t, GraphInterface::vertex_index_map_t>::type
vmap_t;
vector<vector<vmap_t> > vmaps;
run_action<>()
(g, boost::bind<void>(get_all_motifs(), _1, k, boost::ref(list),
boost::ref(phist), _2,
plist[0], comp_iso, fill_list, boost::ref(rng)),
(g, boost::bind<void>(get_all_motifs(collect_vmaps, plist[0], comp_iso,
fill_list, rng),
_1, k, boost::ref(list), boost::ref(phist),
boost::ref(vmaps),_2),
mpl::vector<sample_all,sample_some>())(sampler);
for (size_t i = 0; i < phist.size(); ++i)
hist.append(phist[i]);
for (size_t i = 0; i < vmaps.size(); ++i)
{
python::list vlist;
for (size_t j = 0; j < vmaps[i].size(); ++j)
vlist.append(PythonPropertyMap<vmap_t>(vmaps[i][j]));
pvmaps.append(vlist);
}
if (fill_list)
{
for (int i = 0; i < python::len(subgraph_list); ++i)
......
......@@ -288,10 +288,20 @@ void get_sig(Graph& g, vector<size_t>& sig)
// gets (or samples) all the subgraphs in graph g
struct get_all_motifs
{
template <class Graph, class Sampler>
get_all_motifs(bool collect_vmaps, double p, bool comp_iso, bool fill_list,
rng_t& rng)
: collect_vmaps(collect_vmaps), p(p),
comp_iso(comp_iso), fill_list(fill_list), rng(rng) {}
bool collect_vmaps;
double p;
bool comp_iso;
bool fill_list;
rng_t& rng;
template <class Graph, class Sampler, class VMap>
void operator()(Graph& g, size_t k, boost::any& list,
vector<size_t>& hist, Sampler sampler, double p,
bool comp_iso, bool fill_list, rng_t& rng) const
vector<size_t>& hist, vector<vector<VMap> >& vmaps,
Sampler sampler) const
{
typedef typename mpl::if_<typename is_directed::apply<Graph>::type,
d_graph_t,
......@@ -377,6 +387,7 @@ struct get_all_motifs
}
bool found = false;
size_t pos;
typeof(sub_list.begin()) sl = sub_list.find(sig);
if (sl != sub_list.end())
{
......@@ -397,7 +408,8 @@ struct get_all_motifs
}
if (found)
{
hist[sl->second[l].first]++;
pos = sl->second[l].first;
hist[pos]++;
break;
}
}
......@@ -409,6 +421,17 @@ struct get_all_motifs
sub_list[sig].push_back(make_pair(subgraph_list.size() - 1,
sub));
hist.push_back(1);
pos = hist.size() - 1;
found = true;
}
if (found && collect_vmaps)
{
if (pos >= vmaps.size())
vmaps.resize(pos + 1);
vmaps[pos].push_back(VMap(get(boost::vertex_index,sub)));
for (size_t vi = 0; vi < num_vertices(sub); ++vi)
vmaps[pos].back()[vertex(vi, sub)] = subgraphs[j][vi];
}
}
}
......
......@@ -46,7 +46,7 @@ from __future__ import division, absolute_import, print_function
from .. dl_import import dl_import
dl_import("from . import libgraph_tool_clustering as _gt")
from .. import _degree, _prop, Graph, GraphView, _get_rng
from .. import _degree, _prop, Graph, GraphView, PropertyMap, _get_rng
from .. topology import isomorphism
from .. generation import random_rewire
from .. stats import vertex_hist
......@@ -284,7 +284,7 @@ def extended_clustering(g, props=None, max_depth=3, undirected=False):
return props
def motifs(g, k, p=1.0, motif_list=None):
def motifs(g, k, p=1.0, motif_list=None, return_maps=False):
r"""
Count the occurrence of k-size subgraphs (motifs). A tuple with two lists is
returned: the list of motifs found, and the list with their respective
......@@ -296,7 +296,7 @@ def motifs(g, k, p=1.0, motif_list=None):
Graph to be used.
k : int
number of vertices of the motifs
p : float or float list (optional, default: 1.0)
p : float or float list (optional, default: `1.0`)
uniform fraction of the motifs to be sampled. If a float list is
provided, it will be used as the fraction at each depth
:math:`[1,\dots,k]` in the algorithm. See [wernicke-efficient-2006]_ for
......@@ -304,6 +304,10 @@ def motifs(g, k, p=1.0, motif_list=None):
motif_list : list of :class:`~graph_tool.Graph` objects, optional
If supplied, the algorithms will only search for the motifs in this list
(or isomorphisms).
return_maps : bool (optional, default `False`)
If true, a list will be returned, which provide for each motif graph a
list of vertex property maps which map the motif to its location in the
main graph.
Returns
-------
......@@ -314,6 +318,9 @@ def motifs(g, k, p=1.0, motif_list=None):
out-degree-sequence, and number of edges (in this order).
counts : list of ints
The number of times the respective motif in the motifs list was counted
vertex_maps : list of lists of :class:`~graph_tool.PropertyMap` objects
List for each motif graph containing the locations in the main
graph. This is only returned if `return_maps == True`.
See Also
--------
......@@ -375,9 +382,10 @@ def motifs(g, k, p=1.0, motif_list=None):
pd = [float(x) for x in p]
hist = []
vertex_maps = []
was_directed = g.is_directed()
_gt.get_motifs(g._Graph__graph, k, sub_list, hist, pd,
True, len(sub_list) == 0,
_gt.get_motifs(g._Graph__graph, k, sub_list, hist, vertex_maps,
return_maps, pd, True, len(sub_list) == 0,
_get_rng())
# assemble graphs
......@@ -402,6 +410,11 @@ def motifs(g, k, p=1.0, motif_list=None):
sub_list = [x[0] for x in list_hist]
hist = [x[1] for x in list_hist]
if return_maps:
for i, vlist in enumerate(vertex_maps):
sub = sub_list[i]
vertex_maps[i] = [PropertyMap(vm, sub, "v") for vm in vlist]
return sub_list, hist, vertex_maps
return sub_list, hist
......
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