В настоящее время я работаю над реализацией алгоритма топологической сортировки с удалением источника для ориентированного графа. В основном алгоритм выглядит следующим образом:
- Найти узел в графе без входящих ребер
- Удалить этот узел и все ребра, выходящие из него, и записать его значение
- Повторяйте 1 и 2, пока не удалите все узлы
Так, например, график
будетимеют топологический вид a, e, b, f, c, g, d, h . (Примечание: топологические сортировки не уникальны, и, следовательно, может быть и другая топологическая сортировка)
В настоящее время я работаю над реализацией этого в Прологе с графом, представленным в виде списка следующим образом:
[[a, [b, e, f]], [b, [f, g]], [c, [g, d]], [d, [h]], [e, [f]], [f, []], [g, [h]], [h, []]]
Где [a, [b, e,f]] термин, например, представляет ребра, идущие от a до b , e и f соответственно, и [b, [f, g]] термин представляет ребра, идущие от b до f и g . Другими словами, первый элемент в массиве «кортеж» - это узел «от», а следующий массив содержит места назначения ребер, идущих от узла «от». Я также работаю в предположении, что для каждой вершины есть одно уникальное имя, и поэтому, когда я его нахожу, я могу удалить его, не беспокоясь о возможных дубликатах.
Я написал следующий код
% depends_on shows that D is adjacent to A, i.e. I travel from A to D on the graph
% returns true if A ----> D
depends_on(G,A,D) :- member([A,Ns],G), member(D,Ns).
% doesnt_depend_on shows that node D doesnt have paths leading to it
doesnt_depend_on(G, D) :- \+ depends_on(G, _, D).
% removes node from a graph with the given value
remove_graph_node([ [D,_] | T], D, T). % base case -- FOUND IT return the tail only since we already popped it
remove_graph_node([ [H,Ns] | T], D, R) :- \+ H=D,remove_graph_node( T, D, TailReturn), append([[H,Ns]], TailReturn, R).
%----------------------------------------------------
source_removal([], []]). % Second parameter is empty list due to risk of a cycle
source_removal(G,Toposort):-member([D,_], G),
doesnt_depend_on(G,D),
remove_graph_node(G,D,SubG),
source_removal(SubG, SubTopoSort),
append([D], SubTopoSort, AppendResult),
Toposort is AppendResult.
И я протестировал depends_on
, doesnt_depend_on
и remove_graph_node
вручную, используя график [ [a,[b,e,f]], [b,[f,g]], [c,[g,d]], [d,[h]], [e,[f]], [f,[]], [g,[h]], [h,[]] ]
и вручную изменяя переменные параметров (особенно когда речь идет об именах узлов, таких как a , b , c и т. Д.). После тщательного тестирования я могу подтвердить, что они работают.
Однако моя проблема заключается в отладке команды source_removal
. В нем я неоднократно удаляю узел без направленного ребра, указывающего на него вместе с его исходящими ребрами, и затем пытаюсь добавить имя узла в список Toposort
, который я строю.
В конце работы функции я ожидаю получить массив выходных данных, например [a,e,b,f,c,g,d,h]
для параметра Toposort
. Вместо этого я получил
?- source_removal([ [a,[b,e,f]], [b,[f,g]], [c,[g,d]], [d,[h]], [e,[f]], [f,[]], [g,[h]], [h,[]] ], Result).
false.
Я получил false в качестве вывода вместо списка, который я пытаюсь построить.
Я потратил часы, пытаясь отладить source_removal
функция, но ничего не удалось придумать. Я был бы очень признателен, если бы кто-нибудь захотел взглянуть на это другими глазами и помочь мне выяснить, в чем заключается проблема с функцией source_removal
. Я был бы очень признателен.
Спасибо за потраченное время на чтение этого поста и заранее.