Commit 4d69fce0 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Assorted docstring inclusions/modifications

Mostly in the flow and spectral modules.
parent effd22b7
......@@ -14,6 +14,7 @@ Available subpackages
generation
topology
flow
run_action
spectral
stats
run_action
util
\ No newline at end of file
......@@ -458,12 +458,12 @@ def motif_significance(g, k, n_shuffles=100, p=1.0, motif_list=None,
Examples
--------
>>> g = gt.random_graph(100, lambda: 3, seed=10)
>>> g = gt.random_graph(100, lambda: (3,3), seed=10)
>>> motifs, zscores = gt.motif_significance(g, 3)
>>> print len(motifs)
11
12
>>> print zscores
[0.99252511282153089, 0.99338956784734667, 1.4783772887933557, 1.3527251395635047, -1.3544301877234366, -1.3559964630331622, -1.1963658331614413, -0.20999999999999999, -0.16, -0.37, -0.13]
[1.6197267471265697, 1.6271265351937325, 0.99350347553112339, -1.4729502635694927, -1.1004922497513825, -1.1181853811005562, 0.92339606894139736, -0.11, -0.10000000000000001, -0.28999999999999998, -0.22, -0.01]
"""
s_ms, counts = motifs(g, k, p, motif_list, undirected, seed)
......
......@@ -59,7 +59,7 @@ def graph_draw(g, pos=None, size=(15, 15), pin=False, layout= "neato",
----------
g : Graph
Graph to be used.
pos : tuple of PropertyMaps (optional, default: None)
pos : PropertyMap or tuple of PropertyMaps (optional, default: None)
Vertex property maps containing the x and y coordinates of the vertices.
size : tuple of scalars (optional, default: (15,15))
Size (in centimeters) of the canvas.
......@@ -188,17 +188,15 @@ def graph_draw(g, pos=None, size=(15, 15), pin=False, layout= "neato",
Returns
-------
pos_x : PropertyMap
Vertex property map with the x-coordinates of the vertices.
pos_y : PropertyMap
Vertex property map with the y-coordinates of the vertices.
pos : PropertyMap
Vector vertex property map with the x and y coordinates of the vertices.
gv : gv.digraph or gv.graph (optional, only if returngv == True)
Internally used graphviz graph.
Notes
-----
This function is a wrapper for the graphviz_ python
This function is a wrapper for the [graphviz] python
routines. Extensive additional documentation for the graph, vertex and edge
properties is available at: http://www.graphviz.org/doc/info/attrs.html.
......@@ -235,8 +233,7 @@ def graph_draw(g, pos=None, size=(15, 15), pin=False, layout= "neato",
References
----------
.. _graphviz: http://www.graphviz.org
.. [graphviz] http://www.graphviz.org
"""
......@@ -454,6 +451,30 @@ def graph_draw(g, pos=None, size=(15, 15), pin=False, layout= "neato",
return pos
def random_layout(g, shape=None, pos=None, dim=2):
r"""Performs a random layout of the graph.
Parameters
----------
g : Graph
Graph to be used.
shape : tuple (optional, default: None)
Rectangular shape of the bounding area. If None, a square of linear size
:math:`\sqrt{N}` is used.
pos : PropertyMap (optional, default: None)
Vector vertex property maps where the coordinates should be stored.
dim : int (optional, default: 2)
Number of coordinates per vertex.
Returns
-------
pos : A vector vertex property map
Vertex property map with the coordinates of the vertices.
Notes
-----
This algorithm has complexity :math:`O(V)`.
"""
if pos == None:
pos = [g.new_vertex_property("double") for i in xrange(dim)]
......@@ -461,7 +482,7 @@ def random_layout(g, shape=None, pos=None, dim=2):
pos = ungroup_vector_property(pos)
if shape == None:
shape = (sqrt(g.num_vertices()), sqrt(g.num_vertices()))
shape = [sqrt(g.num_vertices())]*dim
for i in xrange(dim):
_check_prop_scalar(pos[i], name="pos[%d]" % i)
......@@ -474,6 +495,65 @@ def random_layout(g, shape=None, pos=None, dim=2):
def arf_layout(g, weight=None, d=0.1, a=10, dt=0.001, epsilon=1e-6,
max_iter=1000, pos=None, dim=2):
r"""Calculate the ARF spring-block layout of the graph.
Parameters
----------
g : Graph
Graph to be used.
weight : PropertyMap (optional, default: None)
An edge property map with the respective weights.
d : float (optional, default: 0.1)
Opposing force between vertices.
a : float (optional, default: 10)
Attracting force between adjacent vertices.
dt : float (optional, default: 0.001)
Iteration step size.
epsilon : float (optional, default: 1e-6)
Convergence criterion.
max_iter : int (optional, default: 1000)
Maximum number of iterations. If this value is 0, it runs until
convergence.
pos : PropertyMap (optional, default: None)
Vector vertex property maps where the coordinates should be stored.
dim : int (optional, default: 2)
Number of coordinates per vertex.
Returns
-------
pos : A vector vertex property map
Vertex property map with the coordinates of the vertices.
Notes
-----
This algorithm is defined in [geipel_self-organization_2007]_, and has
complexity :math:`O(V^2)`.
Examples
--------
>>> from numpy.random import seed, zipf
>>> seed(42)
>>> g = gt.random_graph(100, lambda: 3, directed=False)
>>> t = gt.min_spanning_tree(g)
>>> g.set_edge_filter(t)
>>> pos = gt.graph_draw(g, output=None) # initial configuration
>>> pos = gt.arf_layout(g, pos=pos, max_iter=0)
>>> gt.graph_draw(g, pos=pos, pin=True, output="graph-draw-arf.png")
<...>
.. figure:: graph-draw-arf.png
:align: center
ARF layout of a minimum spanning tree of a random graph.
References
----------
.. [geipel_self-organization_2007] Markus M. Geipel, "Self-Organization
applied to Dynamic Network Layout" , International Journal of Modern
Physics C vol. 18, no. 10 (2007), pp. 1537-1549, arXiv:0704.1748v5
.. _arf: http://www.sg.ethz.ch/research/graphlayout
"""
if pos == None:
pos = random_layout(g, dim=dim)
_check_prop_vector(pos, name="pos", floating=True)
......
......@@ -29,6 +29,97 @@ __all__ = ["edmonds_karp_max_flow", "push_relabel_max_flow",
"kolmogorov_max_flow", "max_cardinality_matching"]
def edmonds_karp_max_flow(g, source, target, capacity, residual=None):
r"""Calculate maximum flow on the graph with Edmonds-Karp algorithm.
Parameters
----------
g : Graph
Graph to be used.
source : Vertex
The source vertex.
target : Vertex
The target (or "sink") vertex.
capacity : PropertyMap
Edge property map with the edge capacities.
residual : PropertyMap (optional, default: none)
Edge property map where the residuals should be stored.
Returns
-------
residual : PropertyMap
Edge property map with the residual capacities (capacity - flow).
Notes
-----
The algorithm is due to [edmonds_theoretical_1972]_, though we are using the
variation called the ``labeling algorithm'' described in
[ravindra_network_1993]_.
This algorithm provides a very simple and easy to implement solution to the
maximum flow problem. However, there are several reasons why this algorithm
is not as good as the push_relabel_max_flow() or the kolmogorov_max_flow()
algorithm.
- In the non-integer capacity case, the time complexity is :math:`O(V E^2)`
which is worse than the time complexity of the push-relabel algorithm
:math:`O(V^2E^{1/2})` for all but the sparsest of graphs.
- In the integer capacity case, if the capacity bound U is very large then
the algorithm will take a long time.
Examples
--------
>>> from numpy.random import seed, random
>>> seed(42)
>>> g = gt.random_graph(100, lambda: (2,2))
>>> c = g.new_edge_property("double")
>>> c.a = random(len(c.a))
>>> res = gt.edmonds_karp_max_flow(g, g.vertex(0), g.vertex(1), c)
>>> res.a = c.a - res.a # the actual flow
>>> print res.a[0:g.num_edges()]
[ 0.39416408 0.72865707 0. 0. 0.02419415 0.05808361
0. 0. 0.70807258 0.02058449 0.02058449 0.
0.21233911 0.18182497 0.01658783 0. 0. 0. 0.
0. 0. 0.11572935 0. 0.1483536 0.5083988
0.19967378 0.02058449 0. 0. 0. 0.11572935
0. 0. 0.47060682 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0.3571333 0. 0.
0. 0. 0.11118128 0.0884925 0. 0. 0.
0. 0. 0. 0. 0.14837338 0. 0.
0.0884925 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0.20875992 0.46564427 0. 0.02058449 0. 0. 0.
0. 0. 0. 0. 0. 0. 0.
0.01658783 0. 0. 0. 0. 0. 0.
0. 0.20875992 0. 0.09303057 0. 0.
0.09303057 0.22879817 0. 0. 0. 0. 0.
0. 0.05808361 0. 0.18657006 0. 0.11118128
0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0.11572935 0. 0. 0.
0. 0. 0. 0. 0. 0. 0.
0.12776911 0. 0. 0. 0. 0. 0.
0. 0.02058449 0. 0.11572935 0. 0.32182874
0.18657006 0. 0. 0. 0. 0.31729067
0. 0.14837338 0. 0.11572935 0.09028977 0. 0.
0. 0. 0. 0. 0.01658783 0.08227776
0. 0. 0. 0. 0. 0.14837338
0. 0.20875992 0.11347352 0.09886559 0.65221433 0. 0.
0. 0. 0. 0. 0. 0. 0.
0.05808361 0. 0. 0. 0. 0. 0.
0. ]
References
----------
.. [boost_edmonds_karp] http://www.boost.org/libs/graph/doc/edmonds_karp_max_flow.html
.. [edmonds_theoretical_1972] Jack Edmonds and Richard M. Karp, "Theoretical
improvements in the algorithmic efficiency for network flow problems.
Journal of the ACM", 1972 19:248-264
.. [ravindra_network_1993] Ravindra K. Ahuja and Thomas L. Magnanti and
James B. Orlin,"Network Flows: Theory, Algorithms, and Applications".
Prentice Hall, 1993.
"""
_check_prop_scalar(capacity, "capacity")
if residual == None:
residual = g.new_edge_property(capacity.value_type())
......@@ -42,6 +133,82 @@ def edmonds_karp_max_flow(g, source, target, capacity, residual=None):
return residual
def push_relabel_max_flow(g, source, target, capacity, residual=None):
r"""Calculate maximum flow on the graph with push-relabel algorithm.
Parameters
----------
g : Graph
Graph to be used.
source : Vertex
The source vertex.
target : Vertex
The target (or "sink") vertex.
capacity : PropertyMap
Edge property map with the edge capacities.
residual : PropertyMap (optional, default: none)
Edge property map where the residuals should be stored.
Returns
-------
residual : PropertyMap
Edge property map with the residual capacities (capacity - flow).
Notes
-----
The algorithm is defined in [goldberg_new_1985]_. The complexity is
:math:`O(V^3)`.
Examples
--------
>>> from numpy.random import seed, random
>>> seed(42)
>>> g = gt.random_graph(100, lambda: (2,2))
>>> c = g.new_edge_property("double")
>>> c.a = random(len(c.a))
>>> res = gt.push_relabel_max_flow(g, g.vertex(0), g.vertex(1), c)
>>> res.a = c.a - res.a # the actual flow
>>> print res.a[0:g.num_edges()]
[ 0.39416408 0.72865707 0. 0. 0.10582673 0. 0.
0. 0.70807258 0.02058449 0.02058449 0. 0.21233911
0.18182497 0.04005893 0. 0. 0.02354897 0.03688695
0. 0.04645041 0.01722617 0.08333736 0.02058449 0.64459363
0.06347894 0.05747144 0. 0.04645041 0. 0.01722617
0.06505159 0. 0.56093603 0. 0.06245346 0.04645041
0. 0. 0.07377389 0.06505159 0. 0.03142919
0. 0.06505159 0.0234711 0.07377389 0. 0.04645041
0.44746251 0.02816465 0.03688695 0.03688695 0. 0.
0.06347894 0.04645041 0.04522729 0. 0.04005893 0. 0.0234711
0. 0.1561659 0.03688695 0.03688695 0.1259324 0.
0.03688695 0. 0.04645041 0. 0.04645041 0. 0.
0. 0.06505159 0. 0. 0.29129661 0.37531506
0. 0.05747144 0.03688695 0.01722617 0. 0.03142919
0.00862975 0.04645041 0. 0.00862975 0.01722617 0.04005893
0. 0. 0.02816465 0. 0. 0.
0.03142919 0.03688695 0.25440966 0.0885227 0.23718349 0. 0.
0.26065459 0.22879817 0. 0. 0. 0.
0.04645041 0. 0.05508016 0. 0.18657006 0.
0.04645041 0. 0.13245284 0. 0.0234711 0.
0.03142919 0. 0. 0. 0.13245284 0.08227776
0.02585591 0.0234711 0. 0. 0. 0.
0.06245346 0. 0. 0.06245346 0.04645041 0. 0.
0.04069727 0.03688695 0.06505159 0.03142919 0. 0.02058449
0.03688695 0.08227776 0. 0.48945276 0.18657006 0.06505159
0. 0. 0.01722617 0.35473057 0. 0.20261631
0. 0.2147306 0.0729211 0.04069727 0.02354897 0.0916777
0.04077514 0.04077514 0. 0.01658783 0.08227776 0. 0.
0. 0. 0. 0.12800126 0. 0.25440966
0.11347352 0.09886559 0.56188512 0. 0.0234711 0.
0.03688695 0. 0.06505159 0. 0. 0.03688695
0.04645041 0. 0. 0.03688695 0. 0.03688695
0.04645041 0.03688695]
References
----------
.. [boost_push_relabel] http://www.boost.org/libs/graph/doc/push_relabel_max_flow.html
.. [goldberg_new_1985] A. V. Goldberg, "A New Max-Flow Algorithm", MIT
Tehnical report MIT/LCS/TM-291, 1985.
"""
_check_prop_scalar(capacity, "capacity")
if residual == None:
residual = g.new_edge_property(capacity.value_type())
......@@ -55,6 +222,91 @@ def push_relabel_max_flow(g, source, target, capacity, residual=None):
return residual
def kolmogorov_max_flow(g, source, target, capacity, residual=None):
r"""Calculate maximum flow on the graph with Kolmogorov algorithm.
Parameters
----------
g : Graph
Graph to be used.
source : Vertex
The source vertex.
target : Vertex
The target (or "sink") vertex.
capacity : PropertyMap
Edge property map with the edge capacities.
residual : PropertyMap (optional, default: none)
Edge property map where the residuals should be stored.
Returns
-------
residual : PropertyMap
Edge property map with the residual capacities (capacity - flow).
Notes
-----
The algorithm is defined in [kolmogorov_graph_2003]_ and
[boykov_experimental_2004]_. The worst case complexity is
:math:`O(EV^2|C|)`, where :math:`|C|` is the minimum cut (but typically
perfomrs much better).
For a more detailed description, see [boost_kolmogorov]_.
Examples
--------
>>> from numpy.random import seed, random
>>> seed(42)
>>> g = gt.random_graph(100, lambda: (2,2))
>>> c = g.new_edge_property("double")
>>> c.a = random(len(c.a))
>>> res = gt.push_relabel_max_flow(g, g.vertex(0), g.vertex(1), c)
>>> res.a = c.a - res.a # the actual flow
>>> print res.a[0:g.num_edges()]
[ 0.39416408 0.72865707 0. 0. 0.10582673 0. 0.
0. 0.70807258 0.02058449 0.02058449 0. 0.21233911
0.18182497 0.04005893 0. 0. 0.02354897 0.03688695
0. 0.04645041 0.01722617 0.08333736 0.02058449 0.64459363
0.06347894 0.05747144 0. 0.04645041 0. 0.01722617
0.06505159 0. 0.56093603 0. 0.06245346 0.04645041
0. 0. 0.07377389 0.06505159 0. 0.03142919
0. 0.06505159 0.0234711 0.07377389 0. 0.04645041
0.44746251 0.02816465 0.03688695 0.03688695 0. 0.
0.06347894 0.04645041 0.04522729 0. 0.04005893 0. 0.0234711
0. 0.1561659 0.03688695 0.03688695 0.1259324 0.
0.03688695 0. 0.04645041 0. 0.04645041 0. 0.
0. 0.06505159 0. 0. 0.29129661 0.37531506
0. 0.05747144 0.03688695 0.01722617 0. 0.03142919
0.00862975 0.04645041 0. 0.00862975 0.01722617 0.04005893
0. 0. 0.02816465 0. 0. 0.
0.03142919 0.03688695 0.25440966 0.0885227 0.23718349 0. 0.
0.26065459 0.22879817 0. 0. 0. 0.
0.04645041 0. 0.05508016 0. 0.18657006 0.
0.04645041 0. 0.13245284 0. 0.0234711 0.
0.03142919 0. 0. 0. 0.13245284 0.08227776
0.02585591 0.0234711 0. 0. 0. 0.
0.06245346 0. 0. 0.06245346 0.04645041 0. 0.
0.04069727 0.03688695 0.06505159 0.03142919 0. 0.02058449
0.03688695 0.08227776 0. 0.48945276 0.18657006 0.06505159
0. 0. 0.01722617 0.35473057 0. 0.20261631
0. 0.2147306 0.0729211 0.04069727 0.02354897 0.0916777
0.04077514 0.04077514 0. 0.01658783 0.08227776 0. 0.
0. 0. 0. 0.12800126 0. 0.25440966
0.11347352 0.09886559 0.56188512 0. 0.0234711 0.
0.03688695 0. 0.06505159 0. 0. 0.03688695
0.04645041 0. 0. 0.03688695 0. 0.03688695
0.04645041 0.03688695]
References
----------
.. [boost_kolmogorov] http://www.boost.org/libs/graph/doc/kolmogorov_max_flow.html
.. [kolmogorov_graph_2003] Vladimir Kolmogorov, "Graph Based Algorithms for
Scene Reconstruction from Two or More Views", PhD thesis, Cornell
University, September 2003.
.. [boykov_experimental_2004] Yuri Boykov and Vladimir Kolmogorov, "An
Experimental Comparison of Min-Cut/Max-Flow Algorithms for Energy
Minimization", Vision In IEEE Transactions on Pattern Analysis and
Machine Intelligence, vol. 26, no. 9, pp. 1124-1137, Sept. 2004.
"""
_check_prop_scalar(capacity, "capacity")
if residual == None:
residual = g.new_edge_property(capacity.value_type())
......@@ -68,6 +320,50 @@ def kolmogorov_max_flow(g, source, target, capacity, residual=None):
return residual
def max_cardinality_matching(g, match=None):
r"""Find the maximum cardinality matching in the graph.
Parameters
----------
g : Graph
Graph to be used.
match : PropertyMap (optional, default: none)
Edge property map where the matching will be specified.
Returns
-------
match : PropertyMap
Boolean edge property map where the matching is specified.
is_maximal : bool
True if the matching is indeed maximal, or False otherwise.
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(42)
>>> 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.png")
<...>
.. figure:: max_card_match.png
:align: center
Edges belonging to the matching are in red.
References
----------
.. [boost_max_matching] http://www.boost.org/libs/graph/doc/maximum_matching.html
"""
if match == None:
match = g.new_edge_property("bool")
_check_prop_scalar(match, "match")
......
......@@ -29,6 +29,57 @@ import scipy.sparse
__all__ = ["adjacency", "laplacian", "incidence"]
def adjacency(g, sparse=True, weight=None):
r"""Return the adjacency matrix of the graph.
Parameters
----------
g : Graph
Graph to be used.
sparse : bool (optional, default: True)
Build a :mod:`~scipy.sparse` matrix.
weight : PropertyMap (optional, default: True)
Edge property map with the edge weights.
Returns
-------
a : matrix
The adjacency matrix.
Notes
-----
The adjacency matrix is defined as
.. math::
a_{i,j} =
\begin{cases}
1 & \text{if } v_i \text{ is adjacent to } v_j, \\
0 & \text{otherwise}
\end{cases}
In the case of weighted edges, the value 1 is replaced the weight of the
respective edge.
Examples
--------
>>> from numpy.random import seed, random
>>> seed(42)
>>> g = gt.random_graph(100, lambda: (10,10))
>>> m = gt.adjacency(g)
>>> print m.todense()
[[ 0. 0. 0. ..., 1. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]
[ 1. 0. 0. ..., 0. 0. 0.]
...,
[ 0. 0. 0. ..., 0. 1. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]]
References
----------
.. [wikipedia_adjacency] http://en.wikipedia.org/wiki/Adjacency_matrix
"""
if g.get_vertex_filter()[0] != None:
index = g.new_vertex_property("int64_t")
for i,v in enumerate(g.vertices()):
......@@ -67,6 +118,74 @@ def _get_deg(v, deg, weight):
@_limit_args({"deg":["total", "in", "out"]})
def laplacian(g, deg="total", normalized=True, sparse=True, weight=None):
r"""Return the Laplacian matrix of the graph.
Parameters
----------
g : Graph
Graph to be used.
deg : str (optional, default: "total")
Degree to be used, in case of a directed graph.
normalized : bool (optional, default: True)
Whether to compute the normalized Laplacian.
sparse : bool (optional, default: True)
Build a :mod:`~scipy.sparse` matrix.
weight : PropertyMap (optional, default: True)
Edge property map with the edge weights.
Returns
-------
l : matrix
The Laplacian matrix.
Notes
-----
The Laplacian matrix is defined as
.. math::
\ell_{i,j} =
\begin{cases}
\Gamma(v_i) & \text{if } i = j \\
-1 & \text{if } i \neq j \text{ and } v_i \text{ is adjacent to } v_j \\
0 & \text{otherwise}.
\end{cases}
Where :math:`\Gamma(v_i)` is the degree of vertex :math:`v_i`. The
normalized version is
.. math::
\ell_{i,j} =
\begin{cases}
1 & \text{ if } i = j \text{ and } \Gamma(v_i) \neq 0 \\
-\frac{1}{\sqrt{\Gamma(v_i)\Gamma(v_j)}} & \text{ if } i \neq j \text{ and } v_i \text{ is adjacent to } v_j \\
0 & \text{otherwise}.
\end{cases}
In the case of weighted edges, the value 1 is replaced the weight of the
respective edge.
Examples
--------
>>> from numpy.random import seed, random
>>> seed(42)
>>> g = gt.random_graph(100, lambda: (10,10))
>>> m = gt.laplacian(g)
>>> print m.todense()
[[ 1. 0. 0. ..., 0.05 0. 0. ]
[ 0. 1. 0. ..., 0. 0. 0. ]
[ 0.05 0. 1. ..., 0. 0. 0. ]
...,
[ 0. 0. 0. ..., 1. 0.05 0. ]
[ 0. 0. 0. ..., 0. 1. 0. ]
[ 0. 0. 0. ..., 0. 0. 1. ]]
References
----------
.. [wikipedia_laplacian] http://en.wikipedia.org/wiki/Laplacian_matrix
"""
if g.get_vertex_filter()[0] != None:
index = g.new_vertex_property("int64_t")
for i,v in enumerate(g.vertices()):
......@@ -96,6 +215,63 @@ def laplacian(g, deg="total", normalized=True, sparse=True, weight=None):
return m
def incidence(g, sparse=True):
r"""Return the incidence matrix of the graph.
Parameters
----------