Commit f52e0fa9 authored by Tiago Peixoto's avatar Tiago Peixoto

Add "compact" optional parameter to hashimoto()

parent 1c478957
......@@ -49,6 +49,9 @@ void transition(GraphInterface& g, boost::any index, boost::any weight,
void nonbacktracking(GraphInterface& gi, boost::any index,
std::vector<int64_t>& i, std::vector<int64_t>& j);
void compact_nonbacktracking(GraphInterface& gi, std::vector<int64_t>& i,
std::vector<int64_t>& j, std::vector<double>& x);
BOOST_PYTHON_MODULE(libgraph_tool_spectral)
{
using namespace boost::python;
......@@ -59,4 +62,5 @@ BOOST_PYTHON_MODULE(libgraph_tool_spectral)
def("incidence", &incidence);
def("transition", &transition);
def("nonbacktracking", &nonbacktracking);
def("compact_nonbacktracking", &compact_nonbacktracking);
}
......@@ -41,3 +41,11 @@ void nonbacktracking(GraphInterface& gi, boost::any index,
edge_scalar_properties())(index);
}
void compact_nonbacktracking(GraphInterface& gi, std::vector<int64_t>& i,
std::vector<int64_t>& j, std::vector<double>& x)
{
run_action<>()
(gi, [&](auto& g){ get_compact_nonbacktracking(g, i, j, x);})();
}
......@@ -54,6 +54,42 @@ void get_nonbacktracking(Graph& g, Index index,
}
}
template <class Graph>
void get_compact_nonbacktracking(Graph& g,
std::vector<int64_t>& i,
std::vector<int64_t>& j,
std::vector<double>& x)
{
for (auto e : edges_range(g))
{
auto u = source(e, g);
auto v = target(e, g);
i.push_back(u);
j.push_back(v);
x.push_back(1);
i.push_back(v);
j.push_back(u);
x.push_back(1);
}
auto N = num_vertices(g);
for (auto u : vertices_range(g))
{
int32_t k = out_degree(u, g);
auto idx = u + N;
i.push_back(u);
j.push_back(idx);
x.push_back(-1);
i.push_back(idx);
j.push_back(u);
x.push_back(k-1);
}
}
} // namespace graph_tool
#endif // GRAPH_NONBACKTRACKING_MATRIX_HH
......@@ -41,7 +41,8 @@ Contents
from __future__ import division, absolute_import, print_function
from .. import _degree, _prop, Graph, GraphView, _limit_args, Vector_int64_t
from .. import _degree, _prop, Graph, GraphView, _limit_args, Vector_int64_t, \
Vector_double
from .. stats import label_self_loops
import numpy
import scipy.sparse
......@@ -619,7 +620,7 @@ def modularity_matrix(g, weight=None, index=None):
return B
def hashimoto(g, weight=None, index=None):
def hashimoto(g, index=None, compact=False):
r"""Return the Hashimoto (or non-backtracking) matrix of a graph.
Parameters
......@@ -651,6 +652,21 @@ def hashimoto(g, weight=None, index=None):
asymmetric square matrix (or :math:`|E|\times |E|` for directed graphs),
indexed over edge directions.
If the option ``compact=True`` is passed, the matrix returned has shape
:math:`2|V|\times 2|V|`, where :math:`|V|` is the number of vertices, and is
given by
.. math::
\boldsymbol h =
\left(\begin{array}{c|c}
\boldsymbol A & -\boldsymbol 1 \\ \hline
\boldsymbol D-\boldsymbol 1 & \boldsymbol 0
\end{array}\right)
where :math:`\boldsymbol A` is the adjacency matrix, and :math:`\boldsymbol
D` is the diagonal matrix with the node degrees.
Examples
--------
.. testsetup::
......@@ -687,28 +703,42 @@ def hashimoto(g, weight=None, index=None):
.. [hashimoto] Hashimoto, Ki-ichiro. "Zeta functions of finite graphs and
representations of p-adic groups." Automorphic forms and geometry of
arithmetic varieties. 1989. 211-280. :DOI:`10.1016/B978-0-12-330580-0.50015-X`
.. [krzakala_spectral] Florent Krzakala, Cristopher Moore, Elchanan Mossel,
Joe Neeman, Allan Sly, Lenka Zdeborová, and Pan Zhang, "Spectral redemption
in clustering sparse networks", PNAS 110 (52) 20935-20940, 2013.
:doi:`10.1073/pnas.1312486110`, :arxiv:`1306.5550`
"""
if index is None:
if g.get_edge_filter()[0] is not None:
index = g.new_edge_property("int64_t")
index.fa = numpy.arange(g.num_edges())
E = index.fa.max() + 1
else:
index = g.edge_index
E = g.edge_index_range
if not g.is_directed():
E *= 2
i = Vector_int64_t()
j = Vector_int64_t()
if compact:
i = Vector_int64_t()
j = Vector_int64_t()
x = Vector_double()
libgraph_tool_spectral.nonbacktracking(g._Graph__graph, _prop("e", g, index),
i, j)
libgraph_tool_spectral.compact_nonbacktracking(g._Graph__graph,
i, j, x)
data = numpy.ones(i.a.shape)
m = scipy.sparse.coo_matrix((data, (i.a,j.a)), shape=(E, E))
N = g.num_vertices(ignore_filter=True)
m = scipy.sparse.coo_matrix((x, (i.a,j.a)), shape=(2 * N, 2 * N))
else:
if index is None:
if g.get_edge_filter()[0] is not None:
index = g.new_edge_property("int64_t")
index.fa = numpy.arange(g.num_edges())
E = index.fa.max() + 1
else:
index = g.edge_index
E = g.edge_index_range
if not g.is_directed():
E *= 2
i = Vector_int64_t()
j = Vector_int64_t()
libgraph_tool_spectral.nonbacktracking(g._Graph__graph, _prop("e", g, index),
i, j)
data = numpy.ones(i.a.shape)
m = scipy.sparse.coo_matrix((data, (i.a,j.a)), shape=(E, E))
m = m.tocsr()
return m
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