def test_isomorphism_nonmatch(graph, subgraph, attrs): """ Test against networkx reference implementation using graphs that are probably not subgraphs without considering symmetry. """ if attrs is None: node_match = lambda n1, n2: True else: node_match = nx.isomorphism.categorical_node_match( attrs, [None] * len(attrs)) note(("Graph nodes", graph.nodes(data=True))) note(("Graph edges", graph.edges(data=True))) note(("Subgraph nodes", subgraph.nodes(data=True))) note(("Subgraph edges", subgraph.edges(data=True))) ref_time = perf_counter() matcher = nx.isomorphism.GraphMatcher(graph, subgraph, node_match=node_match, edge_match=node_match) expected = make_into_set(matcher.subgraph_isomorphisms_iter()) ref_time -= perf_counter() a_ism_time = perf_counter() ismags = vermouth.ismags.ISMAGS(graph, subgraph, node_match=node_match, edge_match=node_match) asymmetric = make_into_set(ismags.find_isomorphisms(False)) a_ism_time -= perf_counter() s_ism_time = perf_counter() ismags = vermouth.ismags.ISMAGS(graph, subgraph, node_match=node_match, edge_match=node_match) symmetric = make_into_set(ismags.find_isomorphisms(True)) s_ism_time -= perf_counter() note(("Symmetric", symmetric)) note(("Asymmetric", asymmetric)) note(("Expected", expected)) if a_ism_time < ref_time: event('Asymmetric ISMAGS faster than reference') if s_ism_time < a_ism_time: event('Symmetric ISMAGS faster than asymmetric') if s_ism_time < ref_time: event('Symmetric ISMAGS faster than reference') assert asymmetric == expected assert symmetric <= asymmetric if symmetric == asymmetric and expected: assert ismags.analyze_symmetry(subgraph, ismags._sgn_partitions, ismags._sge_colors) == ([], {}) elif symmetric != asymmetric: assert ismags.analyze_symmetry(subgraph, ismags._sgn_partitions, ismags._sge_colors) != ([], {})
def test_asymmetric_self_isomorphism(graphs): """ Compare with reference implementation """ ismags = vermouth.ismags.ISMAGS(graphs, graphs) ismags_answer = list(ismags.find_isomorphisms(False)) graph_matcher = nx.isomorphism.GraphMatcher(graphs, graphs) nx_answer = list(graph_matcher.isomorphisms_iter()) assert make_into_set(ismags_answer) == make_into_set(nx_answer)
def test_broken_edgecase(): """ In this edgecase the ordering of the nodes matters for the symmetries found. This is a bad thing. It happens, because _refine_node_partitions in _couple_nodes does *not* switch node orders, causing it to produce an invalid coupling, losing out on a permutation. """ graph = nx.Graph() nx.add_path(graph, range(5)) graph.add_edges_from([(2, 5), (5, 6)]) ismags = vermouth.ismags.ISMAGS(graph, graph) ismags_answer = list(ismags.find_isomorphisms(True)) assert len(ismags_answer) == 1 graph = nx.relabel_nodes(graph, {0: 0, 1: 1, 2: 2, 3: 3, 4: 6, 5: 4, 6: 5}) ismags = vermouth.ismags.ISMAGS(graph, graph) ismags_answer = list(ismags.find_isomorphisms(True)) assert len(ismags_answer) == 1
def test_symmetric_self_isomorphism(graphs): """ Make sure that when considering symmetry, there is only one isomorphism between a graph and itself """ ismags = vermouth.ismags.ISMAGS(graphs, graphs) iso = list(ismags.find_isomorphisms(True)) assert make_into_set(iso) == make_into_set([{n: n for n in graphs}]) graph_matcher = nx.isomorphism.GraphMatcher(graphs, graphs) nx_answer = list(graph_matcher.isomorphisms_iter()) assert make_into_set(iso) <= make_into_set(nx_answer)
def test_hypo_symmetric_self_isomorphism(subgraph, attrs): """ Make sure that when considering symmetry, there is only one isomorphism between a graph and itself """ if attrs is None: node_match = lambda n1, n2: True else: node_match = nx.isomorphism.categorical_node_match(attrs, [None]*len(attrs)) note(("Graph nodes", subgraph.nodes(data=True))) note(("Graph edges", subgraph.edges(data=True))) ismags = vermouth.ismags.ISMAGS(subgraph, subgraph, node_match=node_match, edge_match=node_match) found = make_into_set(ismags.find_isomorphisms(True)) note(("Found", found)) assert found == make_into_set([{n: n for n in subgraph}])