6. Текст программы
/**
* Поиск минимального остового дерева.
* Главный предикат: magicTree(Graph, Tree).
* Тесты: go.
*/
/**
* magicTree(Graph, Tree).
* Строит минимальное остовное дерево для связного графа Graph.
* Параметр: Graph граф.
* Возвращает: Tree минимальное остовное дерево для графа Graph.
*/
magicTree(Graph, Tree):-sortGraph(Graph, SortedGraph), treeBuilder(SortedGraph, Tree).
/**
* treeBuilder(Graph, Tree).
* Доказывает, что дерево Tree получено путем последовательного добавления ребер из графа Graph.
* Параметр: Graph граф.
* Параметр: Tree дерево, множество вершин которого совпадает с множеством вершин графа Graph.
*/
treeBuilder(Graph, Tree):- Graph = [Edge|RestEdges], spread([Edge], Tree, RestEdges).
/**
* spread(Tree, UpdatedTree, Graph).
* На основе дерева Tree строит дерево UpdatedTree, покрывающее все вершины графа Graph и содержащее ребра
* только из графа Graph.
* Параметр: Tree исходное дерево.
* Возвращает: UpdatedTree дерево покрывающее все вершины графа Graph.
* Параметр: Graph граф из которого берутся возможные ребра для расширения дерева.
*/
spread(Tree1, Tree, Graph):-
addedge(Tree1, Tree2, Graph),
Graph = [_ | RestEdges],
spread(Tree2, Tree, RestEdges).
spread(Tree, Tree, Graph):-not(addedge(Tree, _, Graph)).
/**
* addedge(Forest, updatedForest, Graph).
* Расширяет лес Forest до леса UpdatedForest путем добавления следующего допустимого ребра из графа Graph.
* Параметр: Forest исходный лес.
* Возвращает: UpdatedForest расширенный исходный лес.
* Параметр: Graph граф из которого берутся возможные ребра для расширения леса.
*/
addedge(_,_,[]):-fail.
addedge(Forest, UpdatedForest, [Edge|LastEdges]):-
[A, B, _] = Edge,
saveForest(A, B, Forest),
UpdatedForest = [Edge | Forest], !;
addedge(Forest,UpdatedForest, LastEdges).
/**
* saveForest(Vertex0, Vertex1, Forest).
* Проверяет, что добавление ребра между вершинами Vertex0 и Vertex1 не нарушает свойство леса у Forest.
* Параметр: Vertex0 вершина.
* Параметр: Vertex1 вершина.
* Параметр: Forest лес.
*/
saveForest(A, B, Forest):-not(path(A, B, Forest,_)).
/**
* not(P).
* Предикат отрицания.
* Параметр: P предикат, чьё доказательство будет отрицаться.
*/
not(P) :- P, !, fail.
not(_) :- true.
/**
* longer(Edge0, Edge1).
* Предикат доказывает, что вес ребра Edge0 больше, чем вес ребра Edge1.
* Параметр: Edge0 ребро графа.
* Параметр: Edge1 ребро графа.
*/
longer([_, _, X], [_, _, Y]) :- X > Y.
/**
* sortGraph(Graph, SortedGraph).
* Сортирует представление графа по возрастанию веса ребер.
* Параметр: Graph представление графа в виде списка его ребер
* ([E1, E2,...En], где Ei=[Vertex0, Vertex1, Weight]).
* Возвращает: SortedGraph список ребер графа, отсортированный по возрастанию
* веса ребер.
*
*/
sortGraph(Graph, SortedGraph) :-
swap(Graph, Tmp), !,
sortGraph(Tmp, SortedGraph).
sortGraph(SortedGraph, SortedGraph).
/**
* swap(List1, List2).
* Вспомогательный предикат для "пузырьковой" сортировки.
* Переставляет местами первые два элемента списка, если их порядок не удовлетворяет
* условию сортировки.
*/
swap([X, Y | Tail], [Y, X | Tail]) :- longer(X, Y).
swap([Z | Tail], [Z | Tail1]) :- swap(Tail, Tail1).
/**
* adjacent(Vertex0, Vertex1, Graph).
* Доказывает наличие ребра между двумя вершинами в графе.
* Параметр: Vertex0 вершина графа.
* Параметр: Vertex1 вершина графа.
* Параметр: Graph граф.
*/
adjacent(V0, V1, Graph):-
member([V0, V1, W], Graph);
member([V1, V0, W], Graph).
/**
* node(Vertex, Graph).
* Доказывает принадлежность вершины к графу.
* Параметр: Vertex вершина графа.
* Параметр: Graph граф.
*/
node(V, Graph):-adjacent(V, _, Graph).
/**
* path(Vertex0, Vertex1, Graph, Path).
* Доказывает наличие в графе пути между двумя вершинами и сохраняет этот
* ациклический путь.
* Параметр: Vertex0 вершина отправления.
* Параметр: Vertex1 вершина назначения.
* Параметр: Graph граф.
* Возвращает: Path ациклический путь между вершинами.
*/
path(V0, V1, Graph, Path) :- path1(V0, [V1], Graph, Path).
path1(V, [V|Path1], _, [V|Path1]).
path1(V, [Y|Path1], Graph, Path) :-
adjacent(X, Y, Graph),
not(member(X, Path1)),
path1(V, [X, Y | Path1], Graph, Path).
/**
* Тестовые сценарии
*/
runTestCase(N):- N > -1, N1 is N - 1, runTestCase(N1), !, testMod(N).
runTestCase(-1).
modTestTemplate(Graph):-magicTree(Graph, X), write(X), nl.
modAssertTemplate(Graph, Mod):-magicTree(Graph, Mod), write('assert '), write(Mod), nl.
testMod(0):-modTestTemplate([[a,b,12], [b,c,10], [c,a,2]]).
testMod(1):-modTestTemplate([[a,b,1], [b,c,1], [c,a,1], [b,d,3], [a,d,2], [c, d, 0]]).
testMod(2):-modTestTemplate([[a,b,1], [b,c,3], [c,a,20], [b,d,4], [a,d,3], [c, d, 0]]).
testMod(3):-modTestTemplate([[a, b, 2]]).
testMod(4):-modAssertTemplate([[a,b,2]], [[a,b,2]]).
testMod(5):-modAssertTemplate([[a, b,1], [b, c,2], [c, a,3]], [[b,c,2], [a,b,1]]).
testMod(6):-modAssertTemplate([[a, b,3], [b, c,2], [c, a,1]], [[b,c,2], [c,a,1]]).
testMod(7):-modAssertTemplate([[a, b,2], [b, c,3], [c, a,1]], [[a,b,2], [c,a,1]]).
testMod(8):-
modAssertTemplate([[a, b,1], [b, c,2], [c, d,3], [d, a,4], [d, b,5], [a, c,6]],
[[c,d,3], [b,c,2], [a,b,1]]).
testMod(9):-
modAssertTemplate([[a, b,1], [b, c,2], [c, d,4], [d, a,54], [d, b,55], [a, c,3]],
[[c,d,4], [b,c,2], [a,b,1]]).
testMod(10):-
modAssertTemplate([[a, b,1], [b, c,7], [c, d,2], [d, a,4], [d, b,5], [a, c,6]],
[[d,a,4], [c,d,2], [a,b,1]]).
testMod(11):-
modAssertTemplate([[a, b,0], [b, c,0], [c, d,0], [d, a,0], [d, b,0], [a, c,0]],
[[c,d,0], [b,c,0], [a,b,0]]).
testMod(12):-
modTestTemplate([[a,b,10], [a,i,7], [a,h,11], [b,i,2], [b,j,5], [b,c,10], [c,j,4], [c,d,1],
[d,e,3], [e,j,8], [e,i,2], [f,g,16], [f,i,17], [f,j,3], [g,h,22], [g,i,4], [i,j,6]]).
testMod(13):-
modTestTemplate([[a,b,10], [b,c,10], [c,d,10], [d,e,10], [e,f,10], [f,g,10], [g,h,10], [h,a,10],
[a,i,1], [b,j,1], [c,j,1], [d,j,1], [e,j,1], [f,i,1], [g,i,1], [h,i,1], [i,j,1]]).
testMod(14):-
modTestTemplate([[a,b,1], [a,g,30], [a,f,100], [b,g,28], [b,c,5], [b,h,2], [c,h,2], [c,i,4],
[c,d,10], [d,i,5], [d,j,23], [d,e,25], [e,j,1], [j,i,17], [i,h,11], [h,g,27], [g,f,70]]).
/**
* Предикат для запуска всех сценариев тестирования.
*/
go:-runTestCase(14).