Как топологически отсортировать под/вложенный граф?

Я создал облегченную графическую библиотеку, которая имеет 3 объекта (Вершина, Край, График) и 1 функцию (topo_sort), которая выглядит так:

class DAGError(Exception): pass

def topo_sort(graph):
    sorted_list = []
    def visit(vertex):
        nonlocal sorted_list
        if vertex.idle:
            raise DAGError('Graph has at least one cycle.')
        if not vertex.done:
            vertex.idle = True
            for neighbor in vertex.vertices():
                visit(neighbor)
            vertex.done = True
            vertex.idle = False
            sorted_list.insert(0, vertex)
    queue = [vertex for vertex in graph.vertices() if not vertex.done]
    while queue:
        visit(queue.pop(0))
    return iter(sorted_list)

И это работает нормально, если у меня плоский DAG. Но чего я хочу добиться, так это добавить подграфы (или вложенные графы) в мой основной граф, как вы можете видеть на этой иллюстрации:

иллюстрация вложенного/подграфа

Это по-прежнему группа обеспечения доступности баз данных, поэтому, если я запустил свою функцию для нее, обычный вывод topo_sort будет примерно таким:

V0, V3, V1, V5, V4, V8, V7, V12, V11, V13, V14, V2, V6, V10, V9, V15, V17, V16

Однако я предпочитаю вывод, когда все вершины, от которых зависит подграф, "обрабатываются" до того, как будут обработаны вершины подграфа, поэтому должно быть что-то вроде этого:

V0, V1, V8,        # vertices of maingraph
V3, V5, V4, V12    # vertices of subgraph_0
V7, V11, V13,      # vertices of subgraph_1
V14                # vertex   of subgraph_0
V2                 # vertex   of maingraph
V6, V10, V9, V15   # vertices of subgraph_2
V16, V17           # vertices of maingraph

Но я не смог найти никаких ресурсов на:

  • как «отметить» или «сохранить» вершину в графе как часть подграфа?
  • как отсортировать вершины на основе их зависимостей подграфа (как в примере выше)?
  • как получить или обработать подграф как независимый граф?

Я надеюсь, что смог достаточно подробно объяснить свою проблему - хотя, если чего-то не хватает, сообщите мне, и я дополню свой вопрос недостающими частями.

Заранее спасибо!


ИЗМЕНИТЬ:

Я нашел это (библиотека Boost Graph, BGL) и похоже, что он решает очень похожую (или точно такую ​​же?) проблему, что и у меня, хотя я не знаком с C++, поэтому не понимаю, как это работает и что именно он делает - но я поместил это здесь, может быть, кому-то будет полезно ответить на мои вопросы.


РЕДАКТИРОВАТЬ 2:

Я также принимаю псевдокод, а не только питон! Конечно, если об этом знает существующая библиотека Python, мне это интересно, однако я не хочу использовать такую ​​огромную библиотеку, как graph-tools, например, - поэтому я создал свою собственную, поэтому я предпочитаю реализации больше, чем библиотеки .


person Peter Varo    schedule 18.08.2013    source источник


Ответы (2)


Для вас может быть немного поздно, но для других людей с похожими проблемами:

как «отметить» или «сохранить» вершину в графе как часть подграфа?

Почему бы просто не дать объекту вершины атрибут subgraph, содержащий целое число или строку, обозначающую, к какому подграфу принадлежит вершина? (Если вы хотите использовать NetworkX, используйте словарь атрибутов узла) Таким образом, вы можете проверить этот атрибут подграфа в своем алгоритме сортировки.

как отсортировать вершины на основе их зависимостей подграфа (как в примере выше)?

Я не эксперт по топологической сортировке, но предполагая, что каждая вершина «знает» подграф, к которому она принадлежит, вот что я придумал (используя NetworkX, но вы можете легко реализовать части, которые я использовал, в своей собственной библиотеке): приведенный ниже код собирает все описанные вами «зависимости» (все вершины, которые должны предшествовать текущей). Вы можете использовать эту информацию, чтобы изменить функцию topol_sort() таким образом, чтобы она добавляла текущую вершину в список только в том случае, если не все вершины в ее зависимостях уже находятся в списке.

import networkx as nx

# define the graph and the subgraphs suitable for NetworkX
G = ...
subgraphs = ...

for subgraph in subgraphs:
    # find all vertices that the current subgraph depends on
    dependencies = set()
    for vertex in subgraph:
        anc = nx.ancestors(G, vertex) # anc is the set of all vertices having a path to 'vertex'
        dependencies.union(anc)
    dependencies -= subgraph.nodes()
    # store these dependencies under every vertex of the current subgraph
    for vertex in subgraph:
        G[vertex].node['depends'] = dependencies

# run modified topological sorting
topo_sort_mod(G)

как получить или обработать подграф как независимый граф?

Я не уверен, что вы именно хотите здесь. Может быть, этот помогает (опять же, используя NetworkX), особенно эта часть:

Чтобы создать подграф с собственной копией атрибутов ребра/узла, используйте: nx.Graph(G.subgraph(nbunch))

Если атрибуты края являются контейнерами, то глубокую копию можно получить, используя: G.subgraph(nbunch).copy()

Надеюсь, это кому-нибудь поможет... :)

person trophallaxis    schedule 26.02.2015

прочитал ваше заявление о Graph-tools, но все еще не уверен, хотите ли вы использовать библиотеку для выполнения определенной работы или хотите понять, как ее написать самостоятельно.

Может быть, вы посмотрите на

General Samples
[http://networkx.github.io/examples.html][1]

DAG Example
[http://networkx.lanl.gov/archive/networkx-1.6/_modules/networkx/algorithms/dag.html][2]

и посмотрите, поможет ли это вам решить вашу проблему?

person Peter Rosemann    schedule 19.08.2013
comment
Спасибо @Peter - я уже знал networkx, но я перепроверил его, и хотя я прочитал во всех статьях упоминается слово "подграф" кажется, что networkx не имеет функций, которые я ищу (или, по крайней мере, я не знаю of) -- хотя у него есть метод subgraph(), но он только повторно ссылается на часть графа, что не влияет на алгоритм сортировки. В любом случае, еще раз спасибо, но ни одна из этих ссылок не была полезной .. (Кстати, я предпочитаю понимать и реализовывать это самостоятельно) - person Peter Varo; 20.08.2013