1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
"""
=======================
Distance-regular graphs
=======================
"""
import networkx as nx
from networkx.utils import not_implemented_for
from .distance_measures import diameter
__all__ = [
"is_distance_regular",
"is_strongly_regular",
"intersection_array",
"global_parameters",
]
def is_distance_regular(G):
"""Returns True if the graph is distance regular, False otherwise.
A connected graph G is distance-regular if for any nodes x,y
and any integers i,j=0,1,...,d (where d is the graph
diameter), the number of vertices at distance i from x and
distance j from y depends only on i,j and the graph distance
between x and y, independently of the choice of x and y.
Parameters
----------
G: Networkx graph (undirected)
Returns
-------
bool
True if the graph is Distance Regular, False otherwise
Examples
--------
>>> G = nx.hypercube_graph(6)
>>> nx.is_distance_regular(G)
True
See Also
--------
intersection_array, global_parameters
Notes
-----
For undirected and simple graphs only
References
----------
.. [1] Brouwer, A. E.; Cohen, A. M.; and Neumaier, A.
Distance-Regular Graphs. New York: Springer-Verlag, 1989.
.. [2] Weisstein, Eric W. "Distance-Regular Graph."
http://mathworld.wolfram.com/Distance-RegularGraph.html
"""
try:
intersection_array(G)
return True
except nx.NetworkXError:
return False
def global_parameters(b, c):
"""Returns global parameters for a given intersection array.
Given a distance-regular graph G with integers b_i, c_i,i = 0,....,d
such that for any 2 vertices x,y in G at a distance i=d(x,y), there
are exactly c_i neighbors of y at a distance of i-1 from x and b_i
neighbors of y at a distance of i+1 from x.
Thus, a distance regular graph has the global parameters,
[[c_0,a_0,b_0],[c_1,a_1,b_1],......,[c_d,a_d,b_d]] for the
intersection array [b_0,b_1,.....b_{d-1};c_1,c_2,.....c_d]
where a_i+b_i+c_i=k , k= degree of every vertex.
Parameters
----------
b : list
c : list
Returns
-------
iterable
An iterable over three tuples.
Examples
--------
>>> G = nx.dodecahedral_graph()
>>> b, c = nx.intersection_array(G)
>>> list(nx.global_parameters(b, c))
[(0, 0, 3), (1, 0, 2), (1, 1, 1), (1, 1, 1), (2, 0, 1), (3, 0, 0)]
References
----------
.. [1] Weisstein, Eric W. "Global Parameters."
From MathWorld--A Wolfram Web Resource.
http://mathworld.wolfram.com/GlobalParameters.html
See Also
--------
intersection_array
"""
return ((y, b[0] - x - y, x) for x, y in zip(b + [0], [0] + c))
@not_implemented_for("directed", "multigraph")
def intersection_array(G):
"""Returns the intersection array of a distance-regular graph.
Given a distance-regular graph G with integers b_i, c_i,i = 0,....,d
such that for any 2 vertices x,y in G at a distance i=d(x,y), there
are exactly c_i neighbors of y at a distance of i-1 from x and b_i
neighbors of y at a distance of i+1 from x.
A distance regular graph's intersection array is given by,
[b_0,b_1,.....b_{d-1};c_1,c_2,.....c_d]
Parameters
----------
G: Networkx graph (undirected)
Returns
-------
b,c: tuple of lists
Examples
--------
>>> G = nx.icosahedral_graph()
>>> nx.intersection_array(G)
([5, 2, 1], [1, 2, 5])
References
----------
.. [1] Weisstein, Eric W. "Intersection Array."
From MathWorld--A Wolfram Web Resource.
http://mathworld.wolfram.com/IntersectionArray.html
See Also
--------
global_parameters
"""
# test for regular graph (all degrees must be equal)
degree = iter(G.degree())
(_, k) = next(degree)
for _, knext in degree:
if knext != k:
raise nx.NetworkXError("Graph is not distance regular.")
k = knext
path_length = dict(nx.all_pairs_shortest_path_length(G))
diameter = max(max(path_length[n].values()) for n in path_length)
bint = {} # 'b' intersection array
cint = {} # 'c' intersection array
for u in G:
for v in G:
try:
i = path_length[u][v]
except KeyError as err: # graph must be connected
raise nx.NetworkXError("Graph is not distance regular.") from err
# number of neighbors of v at a distance of i-1 from u
c = len([n for n in G[v] if path_length[n][u] == i - 1])
# number of neighbors of v at a distance of i+1 from u
b = len([n for n in G[v] if path_length[n][u] == i + 1])
# b,c are independent of u and v
if cint.get(i, c) != c or bint.get(i, b) != b:
raise nx.NetworkXError("Graph is not distance regular")
bint[i] = b
cint[i] = c
return (
[bint.get(j, 0) for j in range(diameter)],
[cint.get(j + 1, 0) for j in range(diameter)],
)
# TODO There is a definition for directed strongly regular graphs.
@not_implemented_for("directed", "multigraph")
def is_strongly_regular(G):
"""Returns True if and only if the given graph is strongly
regular.
An undirected graph is *strongly regular* if
* it is regular,
* each pair of adjacent vertices has the same number of neighbors in
common,
* each pair of nonadjacent vertices has the same number of neighbors
in common.
Each strongly regular graph is a distance-regular graph.
Conversely, if a distance-regular graph has diameter two, then it is
a strongly regular graph. For more information on distance-regular
graphs, see :func:`is_distance_regular`.
Parameters
----------
G : NetworkX graph
An undirected graph.
Returns
-------
bool
Whether `G` is strongly regular.
Examples
--------
The cycle graph on five vertices is strongly regular. It is
two-regular, each pair of adjacent vertices has no shared neighbors,
and each pair of nonadjacent vertices has one shared neighbor::
>>> G = nx.cycle_graph(5)
>>> nx.is_strongly_regular(G)
True
"""
# Here is an alternate implementation based directly on the
# definition of strongly regular graphs:
#
# return (all_equal(G.degree().values())
# and all_equal(len(common_neighbors(G, u, v))
# for u, v in G.edges())
# and all_equal(len(common_neighbors(G, u, v))
# for u, v in non_edges(G)))
#
# We instead use the fact that a distance-regular graph of diameter
# two is strongly regular.
return is_distance_regular(G) and diameter(G) == 2
|