Using And/Or in Prolog - prolog

So I'm relatively new to prolog and I've came across some code on the internet which can be used to represent an And/Or node.
% a is an or node with successors b,c,d.
or(a,[b,c,d]).
% c is an and node with successor d,e,f.
and(c,[d,e,f]).
% d is a terminal (solvable) node.
goal(d).
I'm confused as to how this predicates could be used to find a solvable node.
And references to point me in the right direction would be marvelous

You appear to have found question 2 (c) from the University of East Anglia's School of Computing Sciences Main Series UG Examination 2013/14 (found using a quoted text search on Google), asking:
Given an AND/OR tree specified by a set of Prolog clauses of the form
% a is an or node with successors b,c,d.
or(a,[b,c,d]).
% c is an and node with successor d,e,f.
and(c,[d,e,f]).
% d is a terminal (solvable) node.
goal(d).
write a Prolog program whose main clause, solve(X), succeeds if and only if X is solvable.
As background:
An and-node is solvable if and only if all of its successors are solvable.
An or-node is solvable if and only if at least one of its successors is solvable.
A terminal node is solvable if it is a goal.
The Prolog program requested could look something like this:
%not necessary - without this solve_and([]) will be false anyway
solve_and([]) :-
false.
solve_and([H]) :-
solve(H).
solve_and([H|T]) :-
solve(H),
solve_and(T).
%not necessary - without this solve_or([]) will be false anyway
solve_or([]) :-
false.
solve_or([H|T]) :-
solve(H);
solve_or(T).
solve(X) :-
goal(X),
!.
solve(X) :-
and(X, A),
solve_and(A),
!.
solve(X) :-
or(X, A),
solve_or(A),
!.
This works nicely from the perspective of a consumer - one that calls solve with X already grounded to check for correctness, but the cuts (!) make it a poor generator of solvable Xs. Removing the cuts from the solve rules should make the system bidirectional.

This particular problem wants you to write a predicate to determine if a given node is solvable. In other words, if you were to query solve(z) it would succeed or fail depending upon whether z were solvable.
You would start by writing out what the rules are. Jim Ashworth already did this in his answer, but I'll restate them here:
Rule 1: Node X is solvable if node X is a goal
Rule 2: Node X is solvable if X is the conjunction (and) of one or more nodes that are all solvable
Rule 3: Node X is solvable if X is the disjunction (or) of one or more nodes, at least one of which is solvable
Let's start by simply writing this in Prolog.
% Rule 1
solve(X) :- goal(X).
% Rule 2
solve(X) :-
and(X, Subgoals),
all_solvable(Subgoals).
% Rule 3
solve(X) :-
or(X, Subgoals),
at_least_one_solvable(Subgoals).
Now we need to write predicates all_solvable/1 and at_least_one_solvable/1:
% Auxiliary predicates used above
all_solvable([]).
all_solvable([Node|Nodes]) :-
solve(Node),
all_solvable(Nodes).
at_least_one_solvable([Node]) :- solve(Node).
at_least_one_solvable([Node, NextNode|Nodes]) :-
( solve(Node)
-> true
; at_least_one_solvable([NextNode|Nodes])
).
You can see that this is almost the same as Jim's answer, which was completely in the right direction. I'm just providing some improvements from a Prolog perspective. For this reason, I think Jim deserves the credit for the answer. Differences, besides my choice of predicate names, are:
I omitted absolutely failing goals as being superfluous
I used the p1 -> p2 ; p3 construct to handle the "succeed once" for the disjunctive case
The all_solvable/1 will succeed even if there are no subgoals (most general solution)
I avoided cuts otherwise to allow for the general solutions to occur
Above, the p1 -> p2 ; p3 construct behaves as p1, !, p2 ; p3. So for some cases, the cut is helpful, as Jim pointed out in his comment, that you are only looking for solvability once in this problem, not multiple ways of solvability. You can also find a way to use the once/1 predicate to achieve this (you can look that one up as an exercise).
An alternative implementation for all_solvable/1:
all_solvable(Goals) :- maplist(solve, Goals).
Here, maplist(solvable, Goals) will succeed if and only if solvable succeeds for every element of the Goals list.
As with Jim's solution, this will tell you if a specific goal is solvable (although Jim's answer won't leave a choice point as my solution does):
| ?- solve(a).
true? ;
no
| ?-
An additional benefit of the above solution is that it answers the general query properly with all of the correct solutions:
| ?- solve(X).
X = d ? ;
X = a ? ;
no
| ?-

Related

Reading a cut ! in Prolog

I am reading through Learn Prolog Now! 's chapter on cuts and at the same time Bratko's Prolog Programming for Artificial Intelligence, Chapter 5: Controlling Backtracking. At first it seemed that a cut was a straight-forward way to mimic an if-else clause known from other programming languages, e.g.
# Find the largest number
max(X,Y,Y):- X =< Y,!.
max(X,Y,X).
However, as is noted down the line this code will fail in cases where all variables are instantiated even when we expect false, e.g.
?- max(2,3,2).
true.
The reason is clear: the first rule fails, the second does not have any conditions connected to it anymore, so it will succeed. I understand that, but then a solution is proposed (here's a swish):
max(X,Y,Z):- X =< Y,!, Y = Z.
max(X,Y,X).
And I'm confused how I should read this. I thought ! meant: 'if everything that comes before this ! is true, stop termination including any other rules with the same predicate'. That can't be right, though, because that would mean that the instantiation of Y = Z only happens in case of failure, which would be useless for that rule.
So how should a cut be read in a 'human' way? And, as an extension, how should I read the proposed solution for max/3 above?
See also this answer and this question.
how should I read the proposed solution for max/3 above?
max(X,Y,Z):- X =< Y, !, Y = Z.
max(X,Y,X).
You can read this as follows:
When X =< Y, forget the second clause of the predicate, and unify Y and Z.
The cut throws away choice points. Choice points are marks in the proof tree that tell Prolog where to resume the search for more solutions after finding a solution. So the cut cuts away parts of the proof tree. The first link above (here it is again) discusses cuts in some detail, but big part of that answer is just citing what others have said about cuts elsewhere.
I guess the take home message is that once you put a cut in a Prolog program, you force yourself to read it operationally instead of declaratively. In order to understand which parts of the proof tree will be cut away, you (the programmer) have to go through the motions, consider the order of the clauses, consider which subgoals can create choice points, consider which solutions are lost. You need to build the proof tree (instead of letting Prolog do it).
There are many techniques you can use to avoid creating choice points you know you don't need. This however is a bit of a large topic. You should read the available material and ask specific questions.
The problem with your code is that the cut is never reached when evaluating your query.
The first step of trying to evaluate a goal with a rule is pattern matching.
The goal max(2,3,2) doesn't match the pattern max(X,Y,Y), since the second and third arguments are the same in the pattern and 3 and 2 don't pattern-match with each other. As such, this rule has already failed at the pattern matching stage, thus the evaluator doesn't get as far as testing X =< Y, let alone reaching the !.
But your understanding of cuts is pretty much correct. Given this code
a(X) :- b(X).
a(X) :- c(X).
b(X) :- d(X), !.
b(X) :- e(X).
c(3).
d(4).
d(5).
e(6).
and the goal
?- a(X).
The interpreter will begin with the first rule, by trying to satisfy b(X). In the process, it discovers that d(4) provides a solution, so binds the value 4 to X. Then the cut kicks in, which discards the backtracking on b(X), thus no further solutions to b(X) are found. However, it does not remove the backtracking on a(X), therefore if you ask Prolog to find another solution then it will find X = 3 through the a(X) :- c(X). rule. If you changed the first rule to a(X) :- b(X), !. then it would fail to find X = 3.
Although the cut means no X = 5 solution is found, if your query is
?- a(5).
then the interpreter will return true. This is because the a(5) calls b(5), which calls d(5), which is defined to be true. The d(4) fact fails pattern matching, therefore it does not trigger the cut like it does when querying a(X).
This is an example of a red cut (see my comment on user1812457's answer). Perhaps a good reason to avoid red cuts, besides them breaking logical purity, is to avoid bugs resulting from this behaviour.

Prolog and limitations of backtracking

This is probably the most trivial implementation of a function that returns the length of a list in Prolog
count([], 0).
count([_|B], T) :- count(B, U), T is U + 1.
one thing about Prolog that I still cannot wrap my head around is the flexibility of using variables as parameters.
So for example I can run count([a, b, c], 3). and get true. I can also run count([a, b], X). and get an answer X = 2.. Oddly (at least for me) is that I can also run count(X, 3). and get at least one result, which looks something like X = [_G4337877, _G4337880, _G4337883] ; before the interpreter disappears into an infinite loop. I can even run something truly "flexible" like count(X, A). and get X = [], A = 0 ; X = [_G4369400], A = 1., which is obviously incomplete but somehow really nice.
Therefore my multifaceted question. Can I somehow explain to Prolog not to look beyond first result when executing count(X, 3).? Can I somehow make Prolog generate any number of solutions for count(X, A).? Is there a limitation of what kind of solutions I can generate? What is it about this specific predicate, that prevents me from generating all solutions for all possible kinds of queries?
This is probably the most trivial implementation
Depends from viewpoint: consider
count(L,C) :- length(L,C).
Shorter and functional. And this one also works for your use case.
edit
library CLP(FD) allows for
:- use_module(library(clpfd)).
count([], 0).
count([_|B], T) :- U #>= 0, T #= U + 1, count(B, U).
?- count(X,3).
X = [_G2327, _G2498, _G2669] ;
false.
(further) answering to comments
It was clearly sarcasm
No, sorry for giving this impression. It was an attempt to give you a synthetic answer to your question. Every details of the implementation of length/2 - indeed much longer than your code - have been carefully weighted to give us a general and efficient building block.
There must be some general concept
I would call (full) Prolog such general concept. From the very start, Prolog requires us to solve computational tasks describing relations among predicate arguments. Once we have described our relations, we can query our 'knowledge database', and Prolog attempts to enumerate all answers, in a specific order.
High level concepts like unification and depth first search (backtracking) are keys in this model.
Now, I think you're looking for second order constructs like var/1, that allow us to reason about our predicates. Such constructs cannot be written in (pure) Prolog, and a growing school of thinking requires to avoid them, because are rather difficult to use. So I posted an alternative using CLP(FD), that effectively shields us in some situation. In this question specific context, it actually give us a simple and elegant solution.
I am not trying to re-implement length
Well, I'm aware of this, but since count/2 aliases length/2, why not study the reference model ? ( see source on SWI-Prolog site )
The answer you get for the query count(X,3) is actually not odd at all. You are asking which lists have a length of 3. And you get a list with 3 elements. The infinite loop appears because the variables B and U in the first goal of your recursive rule are unbound. You don't have anything before that goal that could fail. So it is always possible to follow the recursion. In the version of CapelliC you have 2 goals in the second rule before the recursion that fail if the second argument is smaller than 1. Maybe it becomes clearer if you consider this slightly altered version:
:- use_module(library(clpfd)).
count([], 0).
count([_|B], T) :-
T #> 0,
U #= T - 1,
count(B, U).
Your query
?- count(X,3).
will not match the first rule but the second one and continue recursively until the second argument is 0. At that point the first rule will match and yield the result:
X = [_A,_B,_C] ?
The head of the second rule will also match but its first goal will fail because T=0:
X = [_A,_B,_C] ? ;
no
In your above version however Prolog will try the recursive goal of the second rule because of the unbound variables B and U and hence loop infinitely.

Prolog: redundant program points in failure-slice?

We are implementing diagnostic tools for explaining unexpected universal non-termination in pure, monotonic Prolog programs—based on the concept of the failure-slice.
As introduced in
the paper "Localizing and explaining reasons for nonterminating logic programs with failure slices", goals false/0 are added at a number of program points in an effort to reduce the program fragment sizes of explanation candidates (while still preserving non-termination).
So far, so good... So here comes my question1:
Why are there N+1 program points in a clause having N goals?
Or, more precisely:
How come that N points do not suffice? Do we ever need the (N+1)-th program point?
Couldn't we move that false to each use of the predicate of concern instead?
Also, we know that the program fragment is only used for queries like ?- G, false.
Footnote 1: We assume each fact foo(bar,baz). is regarded as a rule foo(bar,baz) :- true..
Why are there N+1 program points in a clause having N goals? How come that N points do not suffice?
In many examples, not all points are actually useful. The point after the head in a predicate with a single clause is such an example. But the program points are here to be used in any program.
Let's try out some examples.
N = 0
A fact is a clause with zero goals. Now even a fact may or may not contribute to non-termination. As in:
?- p.
p :-
q(1).
p.
q(1).
q(2).
We do need a program point for each fact of q/1, even if it has no goal at all, since the minimal failure slice is:
?- p, false.
p :-
q(1),
p, false.
q(1).
q(2) :- false.
N = 1
p :-
q,
p.
p :-
p.
q :-
s.
s.
s :-
s.
So here the question is: Do we need two program points in q/0? Well yes, there are different independent failure slices. Sometimes with false in the beginning, and sometimes at the end.
What is a bit confusing is that the first program point (that is the one in the query) is always true, and the last is always false. So one could remove them, but I think it is clearer to leave them, as a false at the end is what you have to enter into Prolog anyway. See the example in the Appendix. There, P0 = 1, P8 = 0 is hard coded.

getting prolog not to repeat answers

bigger(whale,shark).
bigger(shark,tiger).
bigger(tiger,dog).
bigger(dog,rat).
bigger(rat,ant).
bigger(rat,mouse).
bigger(cat,rat).
bigger(dog,cat).
smaller(X,Y) :- bigger(Y,X).
smaller(X,Y) :- bigger(Z,X),smaller(Z,Y).
When I ask prolog smaller(X,whale) it spits out all the correct animals but repeats several of them. can anyone tell me why and if there's a way to stop it repeating?
Some remarks first:
What kind of relation does the predicate bigger/2 describe, really?
Because of the name, we assume it is transitive: bigger(A, B) and bigger(B, C) ==> bigger(A, C)
We also can safely assume it is strict (and not reflexive): bigger(A, A) can never be true
And assymetric (not symmetric): bigger(A, B) ==> bigger(B, A) is not true
What we cannot know from the program as it stands, is if the relation describes either a total ordering, or a weak ordering: we don't know whether (a) bigger(mouse, ant), or (b) not bigger(mouse, ant), or (c) mouse and ant are equivalent (we assume they are definitely not equal)
All this just to say that you don't have a linear ordering for all the elements for which the bigger relation is defined. If you did, you could sort all animals (say bigger to smaller) and do something like:
animal_bigger(A, Bigger) :-
animal_list(Animals),
append(Bigger, [A|_Smaller], Animals),
member(A, Bigger).
Since you do not have a linear ordering, it is not possible to sort all elements and simplify the questions "what is smaller/bigger" to "what comes before/after". Instead, we need to traverse the graph described by bigger/2. At least we can safely assume that it is a directed, acyclic graph. I leave it as an exercise how to traverse a graph. To solve this problem, we can instead use library(ugraphs) (you can see the source here), and to answer, "which animals are smaller than X", we can instead ask, "which nodes are reachable from X":
Here is the complete program:
bigger(whale,shark).
bigger(shark,tiger).
bigger(tiger,dog).
bigger(dog,rat).
bigger(rat,ant).
bigger(rat,mouse).
bigger(cat,rat).
bigger(dog,cat).
:- use_module(library(ugraphs)).
animal_graph(G) :-
findall(A-B, bigger(A, B), Edges),
vertices_edges_to_ugraph([], Edges, G).
animal_smaller(A, B) :-
animal_graph(G),
reachable(A, G, R),
select(A, R, Smaller),
member(B, Smaller).
You can transpose the graph and look for reachable nodes if you want to find all elements that are bigger instead.
I hope you take the time to read this answer...
EDIT
At the end, the message is:
Your bigger/2 does not describe a list (it is not a linear ordering), and it does not describe a tree (you have more than one path to the same node). So, an algorithm that would work on a list does not work here, and an algorithm that would work on a tree does not work, either. So you either have to implement your smaller/2 to work with a graph, or use a library that can deal with graphs.
Using library solution_sequences
In recent versions of the SWI-Prolog development branch this has been made particularly easy:
?- use_module(library(solution_sequences)).
true.
?- distinct(X, smaller(X, whale)).
X = shark ;
X = tiger ;
X = dog ;
X = rat ;
X = ant ;
X = mouse ;
X = cat ;
false.
The library that allows this is documented over here.
Using library aggregate
Another way in which this can be done (also supported in older versions of SWI-Prolog):
?- aggregate_all(set(X), smaller(X, whale), Xs), member(X, Xs).
a possible standard Prolog usage:
?- X=whale,setof(Y,smaller(Y,X),L).
X = whale,
L = [ant, cat, dog, mouse, rat, shark, tiger].
I've attempted to evidence the 'functional dependencies' with the choice of symbols. When you have a list, you can use member/2 to enumerate elements.

Printing path in Prolog

I want to print the path of nodes in a directed graph.
This code works properly for an edge but didn't work for the whole path.
It returns false when it comes to path.
Here is my code but it is only running for just an edge and not for the whole path.
Kindly help me out.
Here is my code:
path(Node1, Node2, X) :-
edge(Node1, Node2),
append([Node1], [Node2], X).
path(Node1, Node2, X, N) :-
edge(Node1, SomeNode),
append([Node1], [SomeNode], X),
path(SomeNode, Node2, X, N),
append([], [Node2], X).
X is a list.
While #WouterBeek already pinpointed your problems, Wouter's statement
Without running this code you can already observe that the second clause will always fail, since a list of length 2 cannot be unified with a list of length 1
merits some elaboration. For an experienced Prolog programmer it is easy to spot such problems. But what can beginners do? They can apply the following technique: Generalize your program and if the generalized program is still too specialized, there must be an error in the remaining part.
Generalizing a pure Prolog program
There are several ways to generalize a pure Prolog program: Either remove goals, or remove subterms in arguments of the head or a goal. To remove goals, I will add a * in front of a goal, using:
:- op(950,fy, *).
*_.
path(Node1, Node2, X) :-
* edge(Node1, Node2),
append([Node1], [Node2], X).
path(Node1, Node2, X) :-
* edge(Node1, SomeNode),
append([Node1], [SomeNode], X),
* path(SomeNode, Node2, X),
append([], [Node2], X).
Now we can ask the most general query of this new predicate:
?- path(N1, N2, P).
P = [N1,N2]
; false.
Therefore: Although this definition is now an (over-) generalization, it still admits only paths of length 2. The problem is completely independent of the definition of edge/3, only the remaining part is responsible. So look at the remaining part to fix the problem!
In your second clause you have the following two statements:
append([Node1], [SomeNode], X),
append([], [Node2], X).
Notice that variable X occurs in both statements, and this must be instantiated to the same list. This means that [Node1]+[SomeNode] = []+[Node2] or [Node1,SomeNode]=[Node2].
Without running this code you can already observe that the second clause will always fail, since a list of length 2 cannot be unified with as a list of length 1.
Another point: the two clauses do not belong to the same predicate, since the former has arity 3 while the latter has arity 4. Typically, for calculating paths or arbitrary depth, you need a predicate that consists of two clauses that belong together: a base case and a recursive case. For the recursive case it is a common practice to use the head/tail notation to construct the path: [FromNode,ToNode|RestOfPath].
Hope this helps!

Resources