125
121
faster_graph_could_be_isomorphic=faster_could_be_isomorphic
127
def is_isomorphic(G1,G2,weighted=False,rtol=1e-6,atol=1e-9):
123
def is_isomorphic(G1, G2, node_match=None, edge_match=None):
128
124
"""Returns True if the graphs G1 and G2 are isomorphic and False otherwise.
132
G1, G2: NetworkX graph instances
133
The two graphs G1 and G2 must be the same type.
135
weighted: bool, optional
136
Optionally check isomorphism for weighted graphs.
137
G1 and G2 must be valid weighted graphs.
139
rtol: float, optional
140
The relative error tolerance when checking weighted edges
142
atol: float, optional
143
The absolute error tolerance when checking weighted edges
129
The two graphs G1 and G2 must be the same type.
131
node_match : callable
132
A function that returns True if node n1 in G1 and n2 in G2 should
133
be considered equal during the isomorphism test.
134
If node_match is not specified then node attributes are not considered.
136
The function will be called like
138
node_match(G1.node[n1], G2.node[n2]).
140
That is, the function will receive the node attribute dictionaries
141
for n1 and n2 as inputs.
143
edge_match : callable
144
A function that returns True if the edge attribute dictionary
145
for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should
146
be considered equal during the isomorphism test. If edge_match is
147
not specified then edge attributes are not considered.
149
The function will be called like
151
edge_match(G1[u1][v1], G2[u2][v2]).
153
That is, the function will receive the edge attribute dictionaries
154
of the edges under consideration.
147
Uses the vf2 algorithm.
148
Works for Graph, DiGraph, MultiGraph, and MultiDiGraph
158
Uses the vf2 algorithm [1]_.
162
>>> import networkx.algorithms.isomorphism as iso
164
For digraphs G1 and G2, using 'weight' edge attribute (default: 1)
166
>>> G1 = nx.DiGraph()
167
>>> G2 = nx.DiGraph()
168
>>> G1.add_path([1,2,3,4],weight=1)
169
>>> G2.add_path([10,20,30,40],weight=2)
170
>>> em = iso.numerical_edge_match('weight', 1)
171
>>> nx.is_isomorphic(G1, G2) # no weights considered
173
>>> nx.is_isomorphic(G1, G2, edge_match=em) # match weights
176
For multidigraphs G1 and G2, using 'fill' node attribute (default: '')
178
>>> G1 = nx.MultiDiGraph()
179
>>> G2 = nx.MultiDiGraph()
180
>>> G1.add_nodes_from([1,2,3],fill='red')
181
>>> G2.add_nodes_from([10,20,30,40],fill='red')
182
>>> G1.add_path([1,2,3,4],weight=3, linewidth=2.5)
183
>>> G2.add_path([10,20,30,40],weight=3)
184
>>> nm = iso.categorical_node_match('fill', 'red')
185
>>> nx.is_isomorphic(G1, G2, node_match=nm)
188
For multidigraphs G1 and G2, using 'weight' edge attribute (default: 7)
190
>>> G1.add_edge(1,2, weight=7)
191
>>> G2.add_edge(10,20)
192
>>> em = iso.numerical_multiedge_match('weight', 7, rtol=1e-6)
193
>>> nx.is_isomorphic(G1, G2, edge_match=em)
196
For multigraphs G1 and G2, using 'weight' and 'linewidth' edge attributes
197
with default values 7 and 2.5. Also using 'fill' node attribute with
200
>>> em = iso.numerical_multiedge_match(['weight', 'linewidth'], [7, 2.5])
201
>>> nm = iso.categorical_node_match('fill', 'red')
202
>>> nx.is_isomorphic(G1, G2, edge_match=em, node_match=nm)
207
numerical_node_match, numerical_edge_match, numerical_multiedge_match
208
categorical_node_match, categorical_edge_match, categorical_multiedge_match
212
.. [1] L. P. Cordella, P. Foggia, C. Sansone, M. Vento,
213
"An Improved Algorithm for Matching Large Graphs",
214
3rd IAPR-TC15 Workshop on Graph-based Representations in
215
Pattern Recognition, Cuen, pp. 149-159, 2001.
216
http://amalfi.dis.unina.it/graph/db/papers/vf-algorithm.pdf
157
# assert(G1.weighted and G2.weighted)
158
if not G1.is_directed() and not G1.is_multigraph():
159
assert(not G2.is_directed() and not G2.is_multigraph())
160
gm = nx.WeightedGraphMatcher(G1,G2,rtol,atol)
161
elif not G1.is_directed() and G1.is_multigraph():
162
assert(not G2.is_directed() and G2.is_multigraph())
163
gm = nx.WeightedMultiGraphMatcher(G1,G2,rtol,atol)
164
elif G1.is_directed() and not G1.is_multigraph():
165
assert(G2.is_directed() and not G2.is_multigraph())
166
gm = nx.WeightedDiGraphMatcher(G1,G2,rtol,atol)
168
assert(G2.is_directed() and G2.is_multigraph())
169
gm = nx.WeightedMultiDiGraphMatcher(G1,G2,rtol,atol)
218
if G1.is_directed() and G2.is_directed():
219
GM = nx.algorithms.isomorphism.DiGraphMatcher
220
elif (not G1.is_directed()) and (not G2.is_directed()):
221
GM = nx.algorithms.isomorphism.GraphMatcher
171
if G1.is_directed() and G2.is_directed():
172
gm= nx.DiGraphMatcher(G1,G2)
173
elif not (G1.is_directed() and G2.is_directed()):
174
gm = nx.GraphMatcher(G1,G2)
176
# Graphs are of mixed type. We could just return False,
177
# but then there is the case of completely disconnected graphs...
178
# which could be isomorphic.
179
raise NetworkXError("Graphs G1 and G2 are not of the same type.")
181
return gm.is_isomorphic()
223
raise NetworkXError("Graphs G1 and G2 are not of the same type.")
225
gm = GM(G1, G2, node_match=node_match, edge_match=edge_match)
227
return gm.is_isomorphic()