2016-07-12 19 views
0

ich alle Paare von Eckpunkten des gleichen Typs auswählen muß, dieeffiziente Weise alle Paare von Scheitelpunkten auszuwählen, die in einem zweiteiligen Netzwerk gemeinsame Nachbarn teilen

Zum Beispiel in einem zweiteiligen Netzwerk gemeinsame Nachbarn teilen:

enter image description here

In diesem Diagramm I habe: (A, B), (A, C), (B, C), (C, D), (1,2) und (2,3)

I kann durch eine quadratische Lösung lösen:

import igraph 
import time 

def common_neighbors(adjlist, i, j): 
    return len(adjlist[i].intersection(adjlist[j])) 

def matching_1(graph, row, column): 
    adjlist = map(set, graph.get_adjlist()) 
    matching = [] 
    dict_edges = dict() 
    for i in range(row): 
     for j in range(i+1, row): 
      if common_neighbors(adjlist, i, j) > 0: 
       matching.append((i, j)) 
    dict_edges = dict() 
    for i in range(row, row+column): 
     for j in range(i+1, row+column): 
      if common_neighbors(adjlist, i, j) > 0: 
       matching.append((i, j)) 
    return matching 

def matching_2(graph, row, column): 
    adjlist = map(set, graph.get_adjlist()) 
    matching = [] 
    for vertex in range(row): 
     twohops = set((twohop for onehop in adjlist[vertex] for twohop in adjlist[onehop])) -set([vertex]) 
     for twohop in twohops: 
      matching.append((vertex, twohop)) 
    for vertex in range(row, row+column): 
     twohops = set((twohop for onehop in adjlist[vertex] for twohop in adjlist[onehop])) -set([vertex]) 
     for twohop in twohops: 
      matching.append((vertex, twohop)) 
    return matching 

if __name__ == "__main__": 

    row, column = 500, 500 
    graph = igraph.Graph.Full_Bipartite(row, column) 

    tp_start = time.time() 
    m = matching_1(graph, row, column) 
    print "%.4f" % (time.time()-tp_start) 

    tp_start = time.time() 
    m = matching_2(graph, row, column) 
    print "%.4f" % (time.time()-tp_start) 

Dies ist die logischste Art und Weise, wie ich es mir vorstellen kann. Wenn jemand einen effizienteren Weg kennt, bin ich ganz Ohr. Jede Hilfe wird sehr geschätzt.

Antwort

1

Sie berechnen im Grunde die Kantenlisten der zwei bipartiten Projektionen Ihres ursprünglichen Netzwerks. IGRAPH verfügt über eine integrierte Methode für diese Annahme, dass Ihre Eckpunkte haben einen Vertex-Attribut namens type, welcher Teil des Diagramms beschreibt die Eckpunkte gehören:

>>> g=Graph.Formula("A--1--B--2--C--3--D, A--2") 
>>> g.vs["type"] = [name in "ABCD" for name in g.vs["name"]] 
>>> g1, g2 = g.bipartite_projection() 
>>> [tuple(g1.vs[pair]["name"]) for pair in g1.get_edgelist()] 
[('1', '2'), ('2', '3')] 
>>> [tuple(g2.vs[pair]["name"]) for pair in g2.get_edgelist()] 
[('A', 'B'), ('A', 'C'), ('B', 'C'), ('C', 'D')] 
+0

Sie für Ihre prompte Antwort danken, @ tamás. Ich würde gerne mehr über diese Funktion wissen: 'bipartite_projection'. Ich habe die Dokumentation gelesen, aber der Algorithmus wurde nicht in der Datei angegeben: [link] (http://igraph.org/python/doc/igraph-pysrc.html#Graph.bipartite_projection). Sie wissen, welcher Algorithmus verwendet wurde und wo dies die vollständige Dokumentation dieser Funktion auf der Webseite von igraph? –

+1

Nun, es gibt nicht wirklich einen bestimmten Algorithmus dahinter - es ist eine einfache Implementierung, die aus der Definition der bipartiten Projektion folgt. Die Dokumentation der entsprechenden C-Funktion ist hier: http://igraph.org/c/doc/igraph-Bipartite.html#igraph_bipartite_projection –

+0

Ich freue mich über Ihre schnelle Antwort, danke @ Tamás. In dieser Dokumentation ist die Zeitkomplexität O (| V | * d^2 + | E |). Aber ich kann das durch eine quadratische Lösung lösen. Ich bin neugierig darauf, wie man diese Komplexität bekommt? Eine Antwort wird sehr geschätzt. –