Example #1
0
def subgraph_isomorphism_vertex_counts(edge_index, **kwargs):
    
    ##### vertex structural identifiers #####
    
    subgraph_dict, induced, num_nodes = kwargs['subgraph_dict'], kwargs['induced'], kwargs['num_nodes']
    directed = kwargs['directed'] if 'directed' in kwargs else False
    
    G_gt = gt.Graph(directed=directed)
    G_gt.add_edge_list(list(edge_index.transpose(1,0).cpu().numpy()))
    gt.stats.remove_self_loops(G_gt)
    gt.stats.remove_parallel_edges(G_gt)  
       
    # compute all subgraph isomorphisms
    sub_iso = gt_topology.subgraph_isomorphism(subgraph_dict['subgraph'], G_gt, induced=induced, subgraph=True, generator=True)
    
    ## num_nodes should be explicitly set for the following edge case: 
    ## when there is an isolated vertex whose index is larger
    ## than the maximum available index in the edge_index
    
    counts = np.zeros((num_nodes, len(subgraph_dict['orbit_partition'])))
    for sub_iso_curr in sub_iso:
        for i,node in enumerate(sub_iso_curr):
            # increase the count for each orbit
            counts[node, subgraph_dict['orbit_membership'][i]] +=1
    counts = counts/subgraph_dict['aut_count']
        
    counts = torch.tensor(counts)
    
    return counts
Example #2
0
    def matching_subgraph(self, sub):
        """Find all indices of atoms which match the given graph.

        Args:
            sub (graph_tool.Graph): the subgraph

        Returns:
            List: list of lists of atomic indices matching the atoms in sub
                to those in this molecule
        """

        try:
            import graph_tool.topology as top
        except ImportError:
            raise RuntimeError(
                "Please install the graph_tool library for graph operations")

        g = self.bond_graph()
        matches = top.subgraph_isomorphism(
            sub,
            g,
            vertex_label=(
                sub.vertex_properties["element"],
                g.vertex_properties["element"],
            ),
        )
        return [tuple(x.a) for x in matches]
Example #3
0
    def matching_fragments(self, fragment, method="connectivity"):
        """
        Find the indices of a matching fragment to the given
        molecular fragment

        Args:
            fragment (Molecule): Molecule object containing the desired fragment
            method (str, optional): the method for matching

        Returns:
            List[dict]: List of maps between matching indices in this molecule and those
                in the fragment
        """
        try:
            import graph_tool.topology as top
        except ImportError:
            raise RuntimeError(
                "Please install the graph_tool library for graph operations")

        sub = fragment.bond_graph()
        g = self.bond_graph()
        matches = top.subgraph_isomorphism(
            sub,
            g,
            vertex_label=(
                sub.vertex_properties["element"],
                g.vertex_properties["element"],
            ),
        )
        return [list(x.a) for x in matches]
Example #4
0
def match_graphs(G1, G2) -> List[Tuple[List[int], List[int]]]:
    """
    Compute graph isomorphisms.

    Parameters
    ----------
    G1:
        Graph 1
    G2:
        Graph 2

    Returns
    -------
    List[Tuple[List[int],List[int]]]
        All possible mappings between nodes of graph 1 and graph 2 (isomorphisms)

    Raises
    ------
    ValueError
        If the graphs `G1` and `G2` are not isomorphic
    """

    try:
        maps = topology.subgraph_isomorphism(
            G1,
            G2,
            vertex_label=(
                G1.vertex_properties["atomicnum"],
                G2.vertex_properties["atomicnum"],
            ),
            subgraph=False,
        )
    except KeyError:  # No "atomicnum" vertex property
        warnings.warn("No atomic number information stored on nodes. " +
                      "Node matching is not performed...")

        maps = topology.subgraph_isomorphism(G1, G2, subgraph=False)

    # Check if graphs are actually isomorphic
    if len(maps) == 0:
        # TODO: Create a new exception
        raise ValueError(f"Graphs {G1} and {G2} are not isomorphic.")

    n = num_vertices(G1)

    # Extract all isomorphisms in a list
    return [(np.arange(0, n, dtype=int), m.a) for m in maps]
def automorphism_orbits(edge_list, print_msgs=True, **kwargs):

    ##### vertex automorphism orbits #####

    directed = kwargs['directed'] if 'directed' in kwargs else False

    graph = gt.Graph(directed=directed)
    graph.add_edge_list(edge_list)
    gt.stats.remove_self_loops(graph)
    gt.stats.remove_parallel_edges(graph)

    # compute the vertex automorphism group
    aut_group = gt_topology.subgraph_isomorphism(graph,
                                                 graph,
                                                 induced=False,
                                                 subgraph=True,
                                                 generator=False)

    orbit_membership = {}
    for v in graph.get_vertices():
        orbit_membership[v] = v

    # whenever two nodes can be mapped via some automorphism, they are assigned the same orbit
    for aut in aut_group:
        for original, vertex in enumerate(aut):
            role = min(original, orbit_membership[vertex])
            orbit_membership[vertex] = role

    orbit_membership_list = [[], []]
    for vertex, om_curr in orbit_membership.items():
        orbit_membership_list[0].append(vertex)
        orbit_membership_list[1].append(om_curr)

    # make orbit list contiguous (i.e. 0,1,2,...O)
    _, contiguous_orbit_membership = np.unique(orbit_membership_list[1],
                                               return_inverse=True)

    orbit_membership = {
        vertex: contiguous_orbit_membership[i]
        for i, vertex in enumerate(orbit_membership_list[0])
    }

    orbit_partition = {}
    for vertex, orbit in orbit_membership.items():
        orbit_partition[orbit] = [
            vertex
        ] if orbit not in orbit_partition else orbit_partition[orbit] + [
            vertex
        ]

    aut_count = len(aut_group)

    if print_msgs:
        print('Orbit partition of given substructure: {}'.format(
            orbit_partition))
        print('Number of orbits: {}'.format(len(orbit_partition)))
        print('Automorphism count: {}'.format(aut_count))

    return graph, orbit_partition, orbit_membership, aut_count
Example #6
0
def match_graphs(G1, G2) -> List[Tuple[List[int], List[int]]]:
    """
    Compute graph isomorphisms.

    Parameters
    ----------
    G1:
        Graph 1
    G2:
        Graph 2

    Returns
    -------
    List[Tuple[List[int],List[int]]]
        All possible mappings between nodes of graph 1 and graph 2 (isomorphisms)

    Raises
    ------
    NonIsomorphicGraphs
        If the graphs `G1` and `G2` are not isomorphic
    """

    try:
        maps = topology.subgraph_isomorphism(
            G1,
            G2,
            vertex_label=(
                G1.vertex_properties["aprops"],
                G2.vertex_properties["aprops"],
            ),
            subgraph=False,
        )
    except KeyError:
        warnings.warn(warn_no_atomic_properties)

        maps = topology.subgraph_isomorphism(G1, G2, subgraph=False)

    # Check if graphs are actually isomorphic
    if len(maps) == 0:
        raise NonIsomorphicGraphs(error_non_isomorphic_graphs)

    n = num_vertices(G1)

    # Extract all isomorphisms in a list
    return [(np.arange(0, n, dtype=int), m.a) for m in maps]
def subgraph_isomorphism_edge_counts(edge_index, **kwargs):

    ##### edge structural identifiers #####

    subgraph_dict, induced = kwargs['subgraph_dict'], kwargs['induced']
    directed = kwargs['directed'] if 'directed' in kwargs else False

    edge_index = edge_index.transpose(1, 0).cpu().numpy()
    edge_dict = {}
    for i, edge in enumerate(edge_index):
        edge_dict[tuple(edge)] = i

    if not directed:
        subgraph_edges = to_undirected(
            torch.tensor(
                subgraph_dict['subgraph'].get_edges().tolist()).transpose(
                    1, 0)).transpose(1, 0).tolist()

    G_gt = gt.Graph(directed=directed)
    G_gt.add_edge_list(list(edge_index))
    gt.stats.remove_self_loops(G_gt)
    gt.stats.remove_parallel_edges(G_gt)

    # compute all subgraph isomorphisms
    sub_iso = gt_topology.subgraph_isomorphism(subgraph_dict['subgraph'],
                                               G_gt,
                                               induced=induced,
                                               subgraph=True,
                                               generator=True)

    counts = np.zeros(
        (edge_index.shape[0], len(subgraph_dict['orbit_partition'])))

    for sub_iso_curr in sub_iso:
        mapping = sub_iso_curr.get_array()
        #         import pdb;pdb.set_trace()
        for i, edge in enumerate(subgraph_edges):

            # for every edge in the graph H, find the edge in the subgraph G_S to which it is mapped
            # (by finding where its endpoints are matched).
            # Then, increase the count of the matched edge w.r.t. the corresponding orbit
            # Repeat for the reverse edge (the one with the opposite direction)

            edge_orbit = subgraph_dict['orbit_membership'][i]
            mapped_edge = tuple([mapping[edge[0]], mapping[edge[1]]])
            counts[edge_dict[mapped_edge], edge_orbit] += 1

    counts = counts / subgraph_dict['aut_count']

    counts = torch.tensor(counts)

    return counts
Example #8
0
def check_claim(graphs, n, g):
    for m in range(n - 1, 3, -1):
        for _, h in graphs.get(m, []):
            if subgraph_isomorphism(h, g, max_n=1, induced=True):
                return m
    return None
Example #9
0
def edge_automorphism_orbits(edge_list, **kwargs):
    
    ##### edge automorphism orbits according to the line graph #####
    
    directed=kwargs['directed'] if 'directed' in kwargs else False

    graph_nx = nx.from_edgelist(edge_list)
    graph = gt.Graph(directed=directed)
    graph.add_edge_list(edge_list)
    gt.stats.remove_self_loops(graph)
    gt.stats.remove_parallel_edges(graph)
    aut_group = gt_topology.subgraph_isomorphism(graph, graph, induced=False, subgraph=True, generator=False)
    aut_count = len(aut_group)
    
    ##### compute line graph vertex automorphism orbits #####

    graph_nx_line = nx.line_graph(graph_nx)
    mapping = {node: i for i,node in enumerate(graph_nx_line.nodes)}
    inverse_mapping = {i: node for i,node in enumerate(graph_nx_line.nodes)}

    graph_nx_line = nx.relabel_nodes(graph_nx_line, mapping)
    line_graph = gt.Graph(directed=directed)
    line_graph.add_edge_list(list(graph_nx_line.edges))

    gt.stats.remove_self_loops(line_graph)
    gt.stats.remove_parallel_edges(line_graph)  

    aut_group_edges = gt_topology.subgraph_isomorphism(line_graph, line_graph, induced=False, subgraph=True, generator=False)

    orbit_membership = {}
    for v in line_graph.get_vertices():
        orbit_membership[v] = v

    for aut in aut_group_edges:
        for original, vertex in enumerate(aut):
            role = min(original, orbit_membership[vertex])
            orbit_membership[vertex] = role

    orbit_membership_list = [[],[]]
    for vertex, om_curr in orbit_membership.items():
        orbit_membership_list[0].append(vertex)
        orbit_membership_list[1].append(om_curr)

    _, contiguous_orbit_membership = np.unique(orbit_membership_list[1], return_inverse = True)

    orbit_membership = {vertex: contiguous_orbit_membership[i] for i,vertex in enumerate(orbit_membership_list[0])}

    orbit_partition= {}
    for vertex, orbit in orbit_membership.items():
        orbit_partition[orbit] = [inverse_mapping[vertex]] if orbit not in orbit_partition else orbit_partition[orbit]+[inverse_mapping[vertex]]    

    ##### transfer line graph vertex automorphism orbits to original edges #####

    orbit_membership_new = {}
    for i,edge in enumerate(graph.get_edges()): 
        mapped_edge = mapping[tuple(edge)] if tuple(edge) in mapping else mapping[tuple([edge[1],edge[0]])]
        orbit_membership_new[i] = orbit_membership[mapped_edge]

    print('Edge orbit partition of given substructure: {}'.format(orbit_partition)) 
    print('Number of edge orbits: {}'.format(len(orbit_partition)))
    print('Graph (vertex) automorphism count: {}'.format(aut_count))
    
    return graph, orbit_partition, orbit_membership_new, aut_count
Example #10
0
def main():

    # vocab_file = 'vocabulary.subgraph'
    # subgraph_process(get_vocabulary(vocab_file))

    print subgraph_isomorphism(vocab_subgraph_0.gexf, graph_of_words_0.gexf)