How to partially compare two graphs

后端 未结 1 445
遇见更好的自我
遇见更好的自我 2020-12-28 10:50

For example, these two graphs is considered to be a perfect partial match:

0 - 1

1 - 2

2 - 3

3 - 0

AND

0 - 1

1 - 2

相关标签:
1条回答
  • 2020-12-28 11:35

    This is the subgraph isomorphism problem: http://en.wikipedia.org/wiki/Subgraph_isomorphism_problem

    There is one algorithm mentioned in the article due to Ullmann.

    Ullmann's algorithm is an extension of a depth-first search. A depth-first search would work like this:

    def search(graph,subgraph,assignments):
      i=len(assignments)
    
      # Make sure that every edge between assigned vertices in the subgraph is also an
      # edge in the graph.
      for edge in subgraph.edges:
        if edge.first<i and edge.second<i:
          if not graph.has_edge(assignments[edge.first],assignments[edge.second]):
            return False
    
      # If all the vertices in the subgraph are assigned, then we are done.
      if i==subgraph.n_vertices:
        return True
    
      # Otherwise, go through all the possible assignments for the next vertex of
      # the subgraph and try it.
      for j in possible_assignments[i]:
        if j not in assignments:
          assignments.append(j)
          if search(graph,subgraph,assignments):
            # This worked, so we've found an isomorphism.
            return True
          assignments.pop()
    
    def find_isomorphism(graph,subgraph):
      assignments=[]
      if search(graph,subgraph,assignments):
        return assignments
      return None
    

    For the basic algorithm, possible_assignments[i] = range(0,graph.n_vertices). That is, all the vertices are a possibility.

    Ullmann extends this basic algorithm by narrowing the possibilities:

    def update_possible_assignments(graph,subgraph,possible_assignments):
      any_changes=True
      while any_changes:
        any_changes = False
        for i in range(0,len(subgraph.n_vertices)):
          for j in possible_assignments[i]:
            for x in subgraph.adjacencies(i):
              match=False
              for y in range(0,len(graph.n_vertices)):
                if y in possible_assignments[x] and graph.has_edge(j,y):
                  match=True
              if not match:
                possible_assignments[i].remove(j)
                any_changes = True
    

    The idea is that if node i of the subgraph could possibly match node j of the graph, then for every node x that is adjacent to node i in the subgraph, it has to be possible to find a node y that is adjacent to node j in the graph. This process helps more than might first be obvious, because each time we eliminate a possible assignment, this may cause other possible assignments to be eliminated, since they are interdependent.

    The final algorithm is then:

    def search(graph,subgraph,assignments,possible_assignments):
      update_possible_assignments(graph,subgraph,possible_assignments)
    
      i=len(assignments)
    
      # Make sure that every edge between assigned vertices in the subgraph is also an
      # edge in the graph.
      for edge in subgraph.edges:
        if edge.first<i and edge.second<i:
          if not graph.has_edge(assignments[edge.first],assignments[edge.second]):
            return False
    
      # If all the vertices in the subgraph are assigned, then we are done.
      if i==subgraph.n_vertices:
        return True
    
      for j in possible_assignments[i]:
        if j not in assignments:
          assignments.append(j)
    
          # Create a new set of possible assignments, where graph node j is the only 
          # possibility for the assignment of subgraph node i.
          new_possible_assignments = deep_copy(possible_assignments)
          new_possible_assignments[i] = [j]
    
          if search(graph,subgraph,assignments,new_possible_assignments):
            return True
    
          assignments.pop()
        possible_assignments[i].remove(j)
        update_possible_assignments(graph,subgraph,possible_assignments)
    
    def find_isomorphism(graph,subgraph):
      assignments=[]
      possible_assignments = [[True]*graph.n_vertices for i in range(subgraph.n_vertices)]
      if search(graph,subgraph,assignments,possible_assignments):
        return assignments
      return None
    
    0 讨论(0)
提交回复
热议问题