Сокращение в конце утверждения Пролога
Я столкнулся с этим разрезом, который должен возвращать true, если существует ребро AB или BA для некоторого узла B графа Graph.
node(A,Graph) :- adjacent(A,_,Graph),!.
Проблема в том, что я не понимаю, почему удаление этого среза повлияет на возвращаемые решения.
Насколько я понимаю, единственное использование для вырезки в конце оператора Prolog - это когда есть другой оператор с тем же именем [другой узел (...)], который мы не хотим вызывать, если первый из них последует, Примером может служить функция, которая принимает X и Y и возвращает большую в качестве третьего параметра.
max1(X, Y, X) :- X > Y, !.
max1(_X, Y, Y).
Тем не менее, нет другого оператора, называемого node(...), поэтому я не вижу, как сокращение может повлиять на решения.
Это мой код Это должно найти остовное дерево. Это подробно объясняется здесь. Компилятор SWI-Prolog 7.6.4 для Linux.
:- op(900, fy, not).
stree1( Graph, Tree) :-
subset( Graph, Tree), tree( Tree), covers( Tree, Graph).
tree( Tree) :-
connected( Tree), not hasacycle( Tree).
connected( Graph) :-
not ( node( A, Graph), node( B, Graph), not path( A, B, Graph, _) ).
hasacycle( Graph) :-
adjacent( Node1, Node2, Graph),
path( Node1, Node2, Graph, [Node1, X, Y | _] ).
covers( Tree, Graph) :-
not ( node( Node, Graph), not node( Node, Tree) ).
subset( [], [] ).
subset( [X | Set], Subset) :- subset( Set, Subset).
subset( [X | Set], [X | Subset]) :- subset( Set, Subset).
adjacent( Node1, Node2, Graph) :-
member( Node1-Node2, Graph)
;
member( Node2-Node1, Graph).
node( Node, Graph) :- adjacent( Node, _, Graph).
path( A, Z, Graph, Path) :-
path1( A, [Z], Graph, Path).
path1( A, [A | Path1], _, [A | Path1] ).
path1( A, [Y | Path1], Graph, Path) :-
adjacent( X, Y, Graph),
not member( X, Path1),
path1( A, [X, Y | Path1], Graph, Path).
Решения возвращены без разреза (правильно)
?- stree1([a-b, b-c, b-d, c-d], Tree).
Tree = [a-b, b-d, c-d] ;
Tree = [a-b, b-c, c-d] ;
Tree = [a-b, b-c, b-d] ;
false.
Решения возвращены с разрезом (неверно)
?- stree1([a-b, b-c, b-d, c-d], Tree).
Tree = [a-b] ;
Tree = [a-b, c-d] ;
Tree = [a-b, b-d] ;
Tree = [a-b, b-d, c-d] ;
Tree = [a-b, b-c] ;
Tree = [a-b, b-c, c-d] ;
Tree = [a-b, b-c, b-d] ;
false.
1 ответ
"Насколько я понимаю, единственное использование для сокращения в конце оператора Prolog - это когда есть другой оператор с тем же именем [другой узел (...)], который мы не хотим вызывать, если первый succeedes ".
Ну, это не так для вашего состояния, так как вы используете member/2
Предикат, который будет работать с возвратом. В этой ситуации использование сокращений приведет к удалению дерева решений, которое Prolog использует при возврате, и может привести к изменению полученных результатов. Чтобы объяснить это на примере, см. Слегка измененный код вашего исходного поста здесь:
node( Node, Graph , Target) :- adjacent( Node, Target, Graph),!.
adjacent( Node1, Node2, Graph) :-
member( Node1-Node2, Graph)
;
member( Node2-Node1, Graph).
Когда вы выполните этот запрос в консоли, вы увидите вывод:
?- node(l,[l-x,l-y],Target).
Target = x
Зачем? Потому что в начале есть два листа вашего дерева поиска. Либо пара (lx), либо (ly) удовлетворяет условию в adjacent/3
, Затем, в соответствии с поиском по глубине, выбирается пара (lx), и, так как у вас есть !
оператора в вашем коде, остальная часть дерева поиска теперь сокращена. Следовательно, вы получите результат как Target = x
Однако, если вы удалите !
утверждение из кода, что вы увидите, это:
?- node(l,[l-x,l-y],Target).
Target = x ;
Target = y ;
false.
Здесь вы видите, что оба листа дерева поиска выполняются последовательно, согласно порядку глубины, и вы видите два результата. Это то, что заставляет вас видеть разные результаты, когда !
существует или нет.