Код: Выделить всё
import networkx as nx
G = nx.DiGraph() # a directed graph
G.add_edge('a', 'b')
print G['a'] # prints {'b': {}}
print G['b'] # prints {}
< /code>
Я хочу использовать направленные графики, потому что я кодирую зависимости, которые имеют направления (в приведенном выше примере у меня есть закрытая форма для «b», условных на «A», а не наоборот). < /p>
Для данного узла я хочу найти предшественники этого узла. Для приведенного выше примера Par ('b') должен вернуть ['a']. Networkx имеет функцию преемника, которая находит детей любого узла. Очевидно, что, проходя через все узлы и найдя те, у кого есть «b» в качестве ребенка, будет работать, но это будет ω (n) в количестве узлов (что будет слишком дорого для моего приложения). < /P>
Я не могу представить, что что-то, что это просто остается из этого хорошо сделанного пакета, но ничего не может найти. < /p>
Один эффективный вариант - сохранить направленную и неистовую версию графика; Все неправомерные края по существу реализованы путем добавления оба направленных краев, и поэтому можно было бы принять в соответствии с смежными узлами и детьми (что было бы предшественником). < /p>
Проблема в том, что я не уверен в наиболее питоническом способе обернуть существующий класс Digraph и график Networkx для этого. На самом деле я просто хочу получить класс PGRAPH, который ведет себя точно так же, как класс NetworkX Digraph, но имеет функцию предшественников (узлов)
Должен ли pgraph наследовать от Digraph и инкапсулировать график (для использования в функции предшественников)? Как тогда я должен заставить все узлы и края быть добавленными как к направленным, так и к неистовым графам, которые он содержит? Должен ли я просто вернуть функции для добавления и удаления узлов и краев в PGRAPH (так что они добавляются и удаляются как из направленной, так и из неисточной версии)? Я волнуюсь, что если я пропущу что -то неясное, я буду на головной боли позже, что может не подразумевать хороший дизайн. < /P>
или (и, пожалуйста, пусть это будет правдой < /code>). Есть ли просто простой способ получить предшественники узла в networkx.digraph, и я полностью пропустил? />
edit: < /p>
Я думаю, что это выполняет задание. PGRAPH наследует от Digraph и инкапсулирует другой диграф (этот перевернулся). Я переопределял методы добавления и удаления узлов и краев. < /p>
import networkx as nx
class PGraph(nx.DiGraph):
def __init__(self):
nx.DiGraph.__init__(self)
self.reversed_graph = nx.DiGraph()
def add_node(self, n, attr_dict=None, **attr):
nx.DiGraph.add_node(self, n, attr_dict, **attr)
self.reversed_graph.add_node(n, attr_dict, **attr)
def add_nodes_from(self, ns, attr_dict=None, **attr):
nx.DiGraph.add_nodes_from(self, ns, attr_dict, **attr)
self.reversed_graph.add_nodes_from(ns, attr_dict, **attr)
def add_edge(self, a, b, attr_dict=None, **attr):
nx.DiGraph.add_edge(self, a, b, attr_dict, **attr)
self.reversed_graph.add_edge(b, a, attr_dict, **attr)
def add_edges_from(self, es, attr_dict=None, **attr):
nx.DiGraph.add_edges_from(self, es, attr_dict, **attr)
self.reversed_graph.add_edges_from(es, attr_dict, **attr)
def remove_node(self, n):
nx.DiGraph.remove_node(self, n)
self.reversed_graph.remove_node(n)
def remove_nodes_from(self, ns):
nx.DiGraph.remove_nodes_from(self, ns)
self.reversed_graph.remove_nodes_from(ns)
def remove_edge(self, a, b):
nx.DiGraph.remove_edge(self, b, a)
self.reversed_graph.remove_edge(a, b)
def remove_edges_from(self, es):
nx.DiGraph.remove_edges_from(self, es)
self.reversed_graph.remove_edges_from([ (b,a) for a,b in es])
# the predecessors function I wanted
def predecessors(self, n):
return self.reversed_graph.successors(n)
< /code>
Что вы думаете об этом решении? Это может удвоить использование памяти, но я думаю, что это приемлемо. Это слишком сложно? Это хороший дизайн?
Подробнее здесь: https://stackoverflow.com/questions/381 ... h-networkx