~ubuntu-branches/ubuntu/utopic/python-networkx/utopic

« back to all changes in this revision

Viewing changes to networkx/algorithms/centrality/current_flow_betweenness_subset.py

  • Committer: Package Import Robot
  • Author(s): Sandro Tosi
  • Date: 2012-08-11 12:41:30 UTC
  • mfrom: (1.4.1) (5.1.13 sid)
  • Revision ID: package-import@ubuntu.com-20120811124130-whr6uso7fncyg8bi
Tags: 1.7-1
* New upstream release
* debian/patches/changeset_*
  - removed, included upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
"""
2
2
Current-flow betweenness centrality measures for subsets of nodes.
3
 
 
4
3
"""
5
 
#    Copyright (C) 2010 by 
 
4
#    Copyright (C) 2010-2011 by 
6
5
#    Aric Hagberg <hagberg@lanl.gov>
7
6
#    Dan Schult <dschult@colgate.edu>
8
7
#    Pieter Swart <swart@lanl.gov>
13
12
__all__ = ['current_flow_betweenness_centrality_subset',
14
13
           'edge_current_flow_betweenness_centrality_subset']
15
14
 
 
15
import itertools
16
16
import networkx as nx
 
17
from networkx.algorithms.centrality.flow_matrix import *
 
18
 
17
19
 
18
20
def current_flow_betweenness_centrality_subset(G,sources,targets,
19
 
                                               normalized=True):
20
 
    """Compute current-flow betweenness centrality for subsets nodes.
 
21
                                               normalized=True,
 
22
                                               weight='weight',
 
23
                                               dtype=float, solver='lu'):
 
24
    r"""Compute current-flow betweenness centrality for subsets of nodes.
21
25
 
22
26
    Current-flow betweenness centrality uses an electrical current
23
27
    model for information spreading in contrast to betweenness
29
33
    Parameters
30
34
    ----------
31
35
    G : graph
32
 
      A networkx graph 
 
36
      A NetworkX graph 
33
37
 
34
38
    sources: list of nodes
35
39
      Nodes to use as sources for current
37
41
    targets: list of nodes
38
42
      Nodes to use as sinks for current
39
43
 
40
 
    normalized : bool, optional
 
44
    normalized : bool, optional (default=True)
41
45
      If True the betweenness values are normalized by b=b/(n-1)(n-2) where
42
46
      n is the number of nodes in G.
43
47
 
 
48
    weight : string or None, optional (default='weight')
 
49
      Key for edge data used as the edge weight.
 
50
      If None, then use 1 as each edge weight.
 
51
 
 
52
    dtype: data type (float)
 
53
      Default data type for internal matrices.
 
54
      Set to np.float32 for lower memory consumption.
 
55
 
 
56
    solver: string (default='lu')
 
57
       Type of linear solver to use for computing the flow matrix.
 
58
       Options are "full" (uses most memory), "lu" (recommended), and 
 
59
       "cg" (uses least memory).
 
60
 
44
61
    Returns
45
62
    -------
46
63
    nodes : dictionary
48
65
        
49
66
    See Also
50
67
    --------
 
68
    approximate_current_flow_betweenness_centrality
51
69
    betweenness_centrality
52
70
    edge_betweenness_centrality
53
71
    edge_current_flow_betweenness_centrality
54
72
 
55
73
    Notes
56
74
    -----
57
 
    The algorithm is from Brandes [1]_.
 
75
    Current-flow betweenness can be computed in `O(I(n-1)+mn \log n)`
 
76
    time [1]_, where `I(n-1)` is the time needed to compute the 
 
77
    inverse Laplacian.  For a full matrix this is `O(n^3)` but using
 
78
    sparse methods you can achieve `O(nm{\sqrt k})` where `k` is the
 
79
    Laplacian matrix condition number.  
 
80
 
 
81
    The space required is `O(nw) where `w` is the width of the sparse
 
82
    Laplacian matrix.  Worse case is `w=n` for `O(n^2)`.
58
83
 
59
84
    If the edges have a 'weight' attribute they will be used as 
60
85
    weights in this algorithm.  Unspecified weights are set to 1.
70
95
    .. [2] A measure of betweenness centrality based on random walks,
71
96
       M. E. J. Newman, Social Networks 27, 39-54 (2005).
72
97
    """
 
98
    from networkx.utils import reverse_cuthill_mckee_ordering 
73
99
    try:
74
100
        import numpy as np
75
101
    except ImportError:
76
 
        raise ImportError(
77
 
            """current_flow_betweenness_centrality_subset() requires NumPy 
78
 
http://scipy.org/""")
79
 
 
 
102
        raise ImportError('current_flow_betweenness_centrality requires NumPy ',
 
103
                          'http://scipy.org/')
 
104
    try:
 
105
        import scipy 
 
106
    except ImportError:
 
107
        raise ImportError('current_flow_betweenness_centrality requires SciPy ',
 
108
                          'http://scipy.org/')
80
109
    if G.is_directed():
81
 
        raise nx.NetworkXError(\
82
 
            "current_flow_betweenness_centrality_subset() not defined for digraphs.")
 
110
        raise nx.NetworkXError('current_flow_betweenness_centrality() ',
 
111
                               'not defined for digraphs.')
83
112
    if not nx.is_connected(G):
84
113
        raise nx.NetworkXError("Graph not connected.")
85
 
    betweenness=dict.fromkeys(G,0.0) # b[v]=0 for v in G
86
 
    F=_compute_F(G) # Current-flow matrix
87
 
    m,n=F.shape # m edges and n nodes
88
 
    mapping=dict(zip(G,range(n)))  # map nodes to integers
89
 
    for (ei,e) in enumerate(G.edges_iter()): 
90
 
        u,v=e
91
 
        # ei is index of edge
92
 
        Fe=F[ei,:] # ei row of F
93
 
        for s in sources:
94
 
            i=mapping[s]
95
 
            for t in targets:
96
 
                j=mapping[t]
97
 
                betweenness[u]+=0.5*np.abs(Fe[i]-Fe[j]) 
98
 
                betweenness[v]+=0.5*np.abs(Fe[i]-Fe[j]) 
 
114
    n = G.number_of_nodes()
 
115
    ordering = list(reverse_cuthill_mckee_ordering(G))
 
116
    # make a copy with integer labels according to rcm ordering
 
117
    # this could be done without a copy if we really wanted to
 
118
    mapping=dict(zip(ordering,range(n)))
 
119
    H = nx.relabel_nodes(G,mapping)
 
120
    betweenness = dict.fromkeys(H,0.0) # b[v]=0 for v in H
 
121
    for row,(s,t) in flow_matrix_row(H, weight=weight, dtype=dtype, 
 
122
                                     solver=solver):
 
123
        for ss in sources:
 
124
            i=mapping[ss]
 
125
            for tt in targets:
 
126
                j=mapping[tt]
 
127
                betweenness[s]+=0.5*np.abs(row[i]-row[j]) 
 
128
                betweenness[t]+=0.5*np.abs(row[i]-row[j]) 
99
129
    if normalized:
100
130
        nb=(n-1.0)*(n-2.0) # normalization factor
101
131
    else:
102
132
        nb=2.0
103
 
    for v in G:
 
133
    for v in H:
104
134
        betweenness[v]=betweenness[v]/nb+1.0/(2-n)
105
 
    return betweenness            
106
 
 
107
 
 
108
 
def edge_current_flow_betweenness_centrality_subset(G,sources,targets,
109
 
                                                    normalized=True):
110
 
    """Compute edge current-flow betweenness centrality for subsets
 
135
    return dict((ordering[k],v) for k,v in betweenness.items())
 
136
 
 
137
 
 
138
def edge_current_flow_betweenness_centrality_subset(G, sources, targets,
 
139
                                                    normalized=True, 
 
140
                                                    weight='weight',
 
141
                                                    dtype=float, solver='lu'):
 
142
    """Compute current-flow betweenness centrality for edges using subsets 
111
143
    of nodes.
112
144
 
113
145
    Current-flow betweenness centrality uses an electrical current
120
152
    Parameters
121
153
    ----------
122
154
    G : graph
123
 
      A networkx graph 
 
155
      A NetworkX graph 
124
156
 
125
157
    sources: list of nodes
126
158
      Nodes to use as sources for current
128
160
    targets: list of nodes
129
161
      Nodes to use as sinks for current
130
162
 
131
 
    normalized : bool, optional
 
163
    normalized : bool, optional (default=True)
132
164
      If True the betweenness values are normalized by b=b/(n-1)(n-2) where
133
165
      n is the number of nodes in G.
134
166
 
 
167
    weight : string or None, optional (default='weight')
 
168
      Key for edge data used as the edge weight.
 
169
      If None, then use 1 as each edge weight.
 
170
 
 
171
    dtype: data type (float)
 
172
      Default data type for internal matrices.
 
173
      Set to np.float32 for lower memory consumption.
 
174
 
 
175
    solver: string (default='lu')
 
176
       Type of linear solver to use for computing the flow matrix.
 
177
       Options are "full" (uses most memory), "lu" (recommended), and 
 
178
       "cg" (uses least memory).
 
179
 
135
180
    Returns
136
181
    -------
137
182
    nodes : dictionary
145
190
 
146
191
    Notes
147
192
    -----
148
 
    The algorithm is from Brandes [1]_.
 
193
    Current-flow betweenness can be computed in `O(I(n-1)+mn \log n)`
 
194
    time [1]_, where `I(n-1)` is the time needed to compute the 
 
195
    inverse Laplacian.  For a full matrix this is `O(n^3)` but using
 
196
    sparse methods you can achieve `O(nm{\sqrt k})` where `k` is the
 
197
    Laplacian matrix condition number.  
 
198
 
 
199
    The space required is `O(nw) where `w` is the width of the sparse
 
200
    Laplacian matrix.  Worse case is `w=n` for `O(n^2)`.
149
201
 
150
202
    If the edges have a 'weight' attribute they will be used as 
151
203
    weights in this algorithm.  Unspecified weights are set to 1.
161
213
    .. [2] A measure of betweenness centrality based on random walks, 
162
214
       M. E. J. Newman, Social Networks 27, 39-54 (2005).
163
215
    """
 
216
    from networkx.utils import reverse_cuthill_mckee_ordering 
164
217
    try:
165
218
        import numpy as np
166
219
    except ImportError:
167
 
        raise ImportError(
168
 
            """current_flow_betweenness_centrality_subset() requires NumPy 
169
 
http://scipy.org/""")
170
 
 
 
220
        raise ImportError('current_flow_betweenness_centrality requires NumPy ',
 
221
                          'http://scipy.org/')
 
222
    try:
 
223
        import scipy 
 
224
    except ImportError:
 
225
        raise ImportError('current_flow_betweenness_centrality requires SciPy ',
 
226
                          'http://scipy.org/')
171
227
    if G.is_directed():
172
 
        raise nx.NetworkXError(\
173
 
            "edge_current_flow_closeness_centrality_subset() not defined for digraphs.")
 
228
        raise nx.NetworkXError('edge_current_flow_betweenness_centrality ',
 
229
                               'not defined for digraphs.')
174
230
    if not nx.is_connected(G):
175
231
        raise nx.NetworkXError("Graph not connected.")
176
 
    betweenness=(dict.fromkeys(G.edges(),0.0)) 
177
 
    F=_compute_F(G) # Current-flow matrix
178
 
    m,n=F.shape # m edges and n nodes
 
232
    n = G.number_of_nodes()
 
233
    ordering = list(reverse_cuthill_mckee_ordering(G))
 
234
    # make a copy with integer labels according to rcm ordering
 
235
    # this could be done without a copy if we really wanted to
 
236
    mapping=dict(zip(ordering,range(n)))
 
237
    H = nx.relabel_nodes(G,mapping)
 
238
    betweenness=(dict.fromkeys(H.edges(),0.0))
179
239
    if normalized:
180
240
        nb=(n-1.0)*(n-2.0) # normalization factor
181
241
    else:
182
242
        nb=2.0
183
 
    mapping=dict(zip(G,range(n)))  # map nodes to integers
184
 
    for (ei,e) in enumerate(G.edges_iter()): 
185
 
        # ei is index of edge
186
 
        Fe=F[ei,:] # ei row of F
187
 
        for s in sources:
188
 
            i=mapping[s]
189
 
            for t in targets:
190
 
                j=mapping[t]
191
 
                betweenness[e]+=0.5*np.abs(Fe[i]-Fe[j])
 
243
    for row,(e) in flow_matrix_row(H, weight=weight, dtype=dtype, 
 
244
                                   solver=solver):
 
245
        for ss in sources:
 
246
            i=mapping[ss]
 
247
            for tt in targets:
 
248
                j=mapping[tt]
 
249
                betweenness[e]+=0.5*np.abs(row[i]-row[j]) 
192
250
        betweenness[e]/=nb
193
 
    return betweenness            
194
 
 
195
 
 
196
 
 
197
 
def _compute_C(G):
198
 
    """Inverse of Laplacian."""
199
 
    try:
200
 
        import numpy as np
201
 
    except ImportError:
202
 
        raise ImportError(
203
 
            """current_flow_betweenness_centrality_subset() requires NumPy 
204
 
http://scipy.org/""")
205
 
 
206
 
    L=nx.laplacian(G) # use ordering of G.nodes() 
207
 
    # remove first row and column
208
 
    LR=L[1:,1:]
209
 
    LRinv=np.linalg.inv(LR)
210
 
    C=np.zeros(L.shape)
211
 
    C[1:,1:]=LRinv
212
 
    return C
213
 
 
214
 
def _compute_F(G):
215
 
    """Current flow matrix."""
216
 
    try:
217
 
        import numpy as np
218
 
    except ImportError:
219
 
        raise ImportError(
220
 
            """current_flow_betweenness_centrality_subset() requires NumPy 
221
 
http://scipy.org/""")
222
 
    C=np.asmatrix(_compute_C(G))
223
 
    n=G.number_of_nodes()
224
 
    m=G.number_of_edges()
225
 
    B=np.zeros((n,m))
226
 
    # use G.nodes() and G.edges() ordering of edges for B  
227
 
    mapping=dict(zip(G,range(n)))  # map nodes to integers
228
 
    for (ei,(v,w,d)) in enumerate(G.edges_iter(data=True)): 
229
 
        c=d.get('weight',1.0)
230
 
        vi=mapping[v]
231
 
        wi=mapping[w]
232
 
        B[vi,ei]=c
233
 
        B[wi,ei]=-c
234
 
    return np.asarray(B.T*C)
 
251
    return dict(((ordering[s],ordering[t]),v) 
 
252
                for (s,t),v in betweenness.items())
235
253
 
236
254
 
237
255
# fixture for nose tests
239
257
    from nose import SkipTest
240
258
    try:
241
259
        import numpy
 
260
        import scipy
242
261
    except:
243
262
        raise SkipTest("NumPy not available")
 
263