""" Tests for VF2 isomorphism algorithm for weighted graphs. """ from operator import eq import math import networkx as nx import networkx.algorithms.isomorphism as iso def test_simple(): # 16 simple tests w = "weight" edges = [(0, 0, 1), (0, 0, 1.5), (0, 1, 2), (1, 0, 3)] for g1 in [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]: g1.add_weighted_edges_from(edges) g2 = g1.subgraph(g1.nodes()) if g1.is_multigraph(): em = iso.numerical_multiedge_match("weight", 1) else: em = iso.numerical_edge_match("weight", 1) assert nx.is_isomorphic(g1, g2, edge_match=em) for mod1, mod2 in [(False, True), (True, False), (True, True)]: # mod1 tests a regular edge # mod2 tests a selfloop if g2.is_multigraph(): if mod1: data1 = {0: {"weight": 10}} if mod2: data2 = {0: {"weight": 1}, 1: {"weight": 2.5}} else: if mod1: data1 = {"weight": 10} if mod2: data2 = {"weight": 2.5} g2 = g1.subgraph(g1.nodes()).copy() if mod1: if not g1.is_directed(): g2._adj[1][0] = data1 g2._adj[0][1] = data1 else: g2._succ[1][0] = data1 g2._pred[0][1] = data1 if mod2: if not g1.is_directed(): g2._adj[0][0] = data2 else: g2._succ[0][0] = data2 g2._pred[0][0] = data2 assert not nx.is_isomorphic(g1, g2, edge_match=em) def test_weightkey(): g1 = nx.DiGraph() g2 = nx.DiGraph() g1.add_edge("A", "B", weight=1) g2.add_edge("C", "D", weight=0) assert nx.is_isomorphic(g1, g2) em = iso.numerical_edge_match("nonexistent attribute", 1) assert nx.is_isomorphic(g1, g2, edge_match=em) em = iso.numerical_edge_match("weight", 1) assert not nx.is_isomorphic(g1, g2, edge_match=em) g2 = nx.DiGraph() g2.add_edge("C", "D") assert nx.is_isomorphic(g1, g2, edge_match=em) class TestNodeMatch_Graph: def setup_method(self): self.g1 = nx.Graph() self.g2 = nx.Graph() self.build() def build(self): self.nm = iso.categorical_node_match("color", "") self.em = iso.numerical_edge_match("weight", 1) self.g1.add_node("A", color="red") self.g2.add_node("C", color="blue") self.g1.add_edge("A", "B", weight=1) self.g2.add_edge("C", "D", weight=1) def test_noweight_nocolor(self): assert nx.is_isomorphic(self.g1, self.g2) def test_color1(self): assert not nx.is_isomorphic(self.g1, self.g2, node_match=self.nm) def test_color2(self): self.g1.nodes["A"]["color"] = "blue" assert nx.is_isomorphic(self.g1, self.g2, node_match=self.nm) def test_weight1(self): assert nx.is_isomorphic(self.g1, self.g2, edge_match=self.em) def test_weight2(self): self.g1.add_edge("A", "B", weight=2) assert not nx.is_isomorphic(self.g1, self.g2, edge_match=self.em) def test_colorsandweights1(self): iso = nx.is_isomorphic(self.g1, self.g2, node_match=self.nm, edge_match=self.em) assert not iso def test_colorsandweights2(self): self.g1.nodes["A"]["color"] = "blue" iso = nx.is_isomorphic(self.g1, self.g2, node_match=self.nm, edge_match=self.em) assert iso def test_colorsandweights3(self): # make the weights disagree self.g1.add_edge("A", "B", weight=2) assert not nx.is_isomorphic( self.g1, self.g2, node_match=self.nm, edge_match=self.em ) class TestEdgeMatch_MultiGraph: def setup_method(self): self.g1 = nx.MultiGraph() self.g2 = nx.MultiGraph() self.GM = iso.MultiGraphMatcher self.build() def build(self): g1 = self.g1 g2 = self.g2 # We will assume integer weights only. g1.add_edge("A", "B", color="green", weight=0, size=0.5) g1.add_edge("A", "B", color="red", weight=1, size=0.35) g1.add_edge("A", "B", color="red", weight=2, size=0.65) g2.add_edge("C", "D", color="green", weight=1, size=0.5) g2.add_edge("C", "D", color="red", weight=0, size=0.45) g2.add_edge("C", "D", color="red", weight=2, size=0.65) if g1.is_multigraph(): self.em = iso.numerical_multiedge_match("weight", 1) self.emc = iso.categorical_multiedge_match("color", "") self.emcm = iso.categorical_multiedge_match(["color", "weight"], ["", 1]) self.emg1 = iso.generic_multiedge_match("color", "red", eq) self.emg2 = iso.generic_multiedge_match( ["color", "weight", "size"], ["red", 1, 0.5], [eq, eq, math.isclose], ) else: self.em = iso.numerical_edge_match("weight", 1) self.emc = iso.categorical_edge_match("color", "") self.emcm = iso.categorical_edge_match(["color", "weight"], ["", 1]) self.emg1 = iso.generic_multiedge_match("color", "red", eq) self.emg2 = iso.generic_edge_match( ["color", "weight", "size"], ["red", 1, 0.5], [eq, eq, math.isclose], ) def test_weights_only(self): assert nx.is_isomorphic(self.g1, self.g2, edge_match=self.em) def test_colors_only(self): gm = self.GM(self.g1, self.g2, edge_match=self.emc) assert gm.is_isomorphic() def test_colorsandweights(self): gm = self.GM(self.g1, self.g2, edge_match=self.emcm) assert not gm.is_isomorphic() def test_generic1(self): gm = self.GM(self.g1, self.g2, edge_match=self.emg1) assert gm.is_isomorphic() def test_generic2(self): gm = self.GM(self.g1, self.g2, edge_match=self.emg2) assert not gm.is_isomorphic() class TestEdgeMatch_DiGraph(TestNodeMatch_Graph): def setup_method(self): TestNodeMatch_Graph.setup_method(self) self.g1 = nx.DiGraph() self.g2 = nx.DiGraph() self.build() class TestEdgeMatch_MultiDiGraph(TestEdgeMatch_MultiGraph): def setup_method(self): TestEdgeMatch_MultiGraph.setup_method(self) self.g1 = nx.MultiDiGraph() self.g2 = nx.MultiDiGraph() self.GM = iso.MultiDiGraphMatcher self.build()