How to check whether two vertices are connected or not in prolog? - prolog

Here my problem is I want to check whether two nodes are connected or not.
My Knowledge base is,
edge(a,b):-!.
edge(b,a):-!.
edge(a,e):-!.
edge(e,a):-!.
edge(b,c):-!.
edge(c,b):-!.
edge(b,d):-!.
edge(d,b):-!.
edge(c,e):-!.
edge(e,c):-!.
edge(d,e):-!.
edge(e,d):-!.
edge(a,f):-!.
edge(f,a):-!.
isConnected(X,X):-!.
isConnected(X,Y):-edge(X,Y),!.
isConnected(X,Z):-not(edge(X,Y)),edge(X,Y),isConnected(Y,Z),!.
isConnected(X,Z):not(edge(X,Y)),edge(X,Z),not(isConnected(Y,Z)),isConnected(Z,Y),!.

Whoa there. That's a lot of cuts. Cuts are sometimes helpful in Prolog for pruning unnecessary answers, but when you have a fact like this:
edge(a, b).
There is absolutely nothing to be gained by writing it as:
edge(a, b) :- !.
After all, there's no choice point there, because there are no variables there and no alternate solutions. So first, let's fix your facts by removing all those cuts.
Next let's look at what isConnected is saying. Let's read it aloud in English and see if it makes sense.
X is connected to X.
X is connected to Y if there is an edge from X to Y.
X is connected to Z if there is not an edge from X to Y, but there is an edge from X to Y and Y is connected to Z. (???)
X is connected to Z if there is not an edge from X to Y, but there is an edge from X to Z, and Y is not connected to Z but Z is connected to Y. (???)
The first two seem quite reasonable. The third one seems to contradict itself right away. How can not(edge(X, Y)) be true at the same time as edge(X, Y)? Keep in mind that the comma in Prolog means and, not just then. The rest of the clause is meaningless because these two conditions cannot ever both be true. Probably what you meant to say was something like this: X is connected to Z if there is an edge from X to Y and Y is connected to Z. That would look like this in Prolog:
isConnected(X, Z) :- edge(X, Y), isConnected(Y, Z).
Logically, this is certainly true, but for any kind of complex graph this is going to be monstrously expensive to calculate, because checking if X is connected to Z might imply checking if Y is connected to Z for all the same nodes.
Your fourth clause has a typo in that the : should be a :-. More importantly, it looks like you're trying to compensate here for the directionality of your edges. A better place to do this would have been around step 2, providing both cases:
isConnected(X, Y) :- edge(X, Y) ; edge(Y, X).
I'm not sure, based on your fact database, whether you actually mean this though; you've duplicated all your facts to account for both directions. If the fact database represents a directed graph, this is probably necessary and the rules should not try inverting the nodes. If it instead represents an undirected graph, your predicate should just account for it with a rule like this that checks both sides, and you should only list each edge once. Doing it both ways, you're telling Prolog to do a bunch of unnecessary work, as it first checks edge(a, b), then the rule inverts it to edge(b, a), then moves on to the next fact edge(b, a) and then the rule inverts it to edge(a, b), in effect checking everything twice.
The elephant in the room here is that even if you do successfully turn this into a logical solution to the problem it's going to be hideously inefficient. There are algorithms for determining if two things are connected that keep track of what has been seen and what has not, and I think you'd be much better off implementing one of those.

Related

Prolog - proof tree misses possibilities

I have the following Prolog Program:
p(f(X), Y) :- p(g(X), g(Y)).
p(g(X), Y) :- p(f(Y), f(X)).
p(f(a), g(b)).
The prolog proof tree has to be drawn for the predicate p(X, Y).
Question:
Why is Y matched to Y1/Y and not to Y/Y1 and why is Y used further on?
if I match a predicate (e.g. p(X, Y)), I get a new predicate (e.g. p(g(X1), g(Y))) - why contains p(g(X1), g(Y)) just one subtree? I mean, shouldn't it have 3 because the knowledgebase contains 3 statements - instead of just 1?
And why is at each layer of the tree matched with something like X2/X1 and so on ? and not with the predicate before ?
Shouldn't it be g(X1)/fX5, g(Y1)/Y5 ?
Note: Maybe it seems that I have never done a tutorial or something. But I did.. I appreciate every help.
To be honest, I have rarely seen a worse method to explain Prolog than what you show here.
Yes, I expect the author meant Y/Y1 instead of Y1/Y in both cases, otherwise the notation would be quite inconsistent.
As to your other questions: You are facing the usual problems that arise when taking such an extremely operational view of Prolog. The core issue is that this method doesn't scale: You do not have the mental capacity to carry this approach through. Don't take this personal: Humans in general are bad at keeping all details of an execution tree that grows exponentially in mind. This makes the whole approach extremely cumbersome and error-prone. For comparison, consider why human grandmasters have stopped competing against chess computers already many years ago. In this concrete case, note for example that the rightmost branch does not even arise in actual Prolog execution, but the graph wrongly suggests that it does!
Part of the problem here is a confusion in terminology: Please note that Prolog uses unification (not "matching", which is one-sided unification). When you unify a goal with a clause head and the unification succeeds, then you get bindings for variables. You continue with these bindings in place.
To make the whole approach remotely feasible, consider fragments of your program.
For example, suppose I only give you the following fact:
p(f(a), g(b)).
And you then query:
?- p(X, Y).
X = f(a),
Y = g(b).
This answers shows the bindings for X and Y. First make sure you understand this, and understand the difference between these bindings and a "new predicate" (which does not arise!).
Also, there are no "statements", but 3 clauses, which are logical alternatives.
Now, again to simplify the whole task, consider the following fragment of your program, in which I only look at the two rules:
p(f(X), Y) :- p(g(X), g(Y)).
p(g(X), Y) :- p(f(Y), f(X)).
Already with this program, we get:
?- p(X, Y).
nontermination
Adding a further pure clause cannot prevent this nontermination. Thus, I recommend you start with this reduced version of your program, and consider it in more depth.
From there, you can add the remaining fact again, and consider the differences.
Very good questions!
Why is Y matched to Y1/Y and not to Y/Y1 and why is Y used further on?
The naming here seems a little arbitrary in that they could have used Y/Y1 but then would need to use Y1 further on. In this case, they chose Y1/Y and use Y further on. Although the author of this expression tree was inconsistent in their convention, I wouldn't be too concerned about the naming as much as whether they follow the variable correctly down the tree.
if I match a predicate (e.g. p(X, Y)), I get a new predicate (e.g. p(g(X1), g(Y))) - why contains p(g(X1), g(Y)) just one subtree? I mean, should'nt it have 3 because the knowledgebase contains 3 statements - instead of just 1?
First a word on term versus predicate. A term is only a predicate in the context of Head :- Body in which case Head is a term that forms the head of a predicate clause. If a term is an argument to a predicate (for example, p(g(X1), g(Y)), the g(X1) and g(Y) are not predicates. They are just terms.
More specifically in this case, the term p(g(X1), g(Y)) only has one subtree because it only matches the head of one of the 3 predicate clauses which is the one with the head p(g(X), Y) (it matches with X = X1 and Y = g(Y)). The other two can't match since they're of the form p(f(...), ...) and the f(...) term cannot match the g(X1) term.
And why is at each layer of the tree matched with something like X2/X1 and so on ? and not with the predicate before ?
Shouldn't it be g(X1)/fX5, g(Y1)/Y5 ?
I'm not sure I'm following this question, but the principle to follow is that the tree is attempting to use the same variable name if it applies to the same variable in memory, whereas a different variable name (e.g., X1 versus X) is used if it's a different X. For example, if I have foo(X, Y) :- <some code>, bar(f(X), Y). and I have bar(X, Y) :- blah(X), ... then the X referred to in the bar predicate is different than the X referred to in the foo predicate. So we might say, in the call to foo(X, Y) we're calling bar(f(X), Y), or alternatively, bar(X1, Y) where X1 = f(X).

Using And/Or in 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
| ?-

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.

Write a Prolog program to model a gorilla moving across a grid

I have done very little programming in Prolog and find it quite difficult so far.
I was given the question: A gorilla moves along an 8x8 grid and can only move right or up. it has to remain within the grid and must finish at (8,8) starting at any arbitrary location.
Write a move predicate that describes all the possible moves.
My attempt:
move(X,Y,X+1,Y).
move(X,Y,X,Y+1).
Write a path predicate that uses the move predicate to determine the path thte robot shuld take.
My attempt:
path('right'):-
move(X,Y,X+1,Y).
path('up'):-
move(X,Y,X,Y+1).
Write prolog predicates that model blockages at (1,2), (4,2), and (4,1).
So far, from what I have found it seems I need to set up a list that would give all possible positions.
I have written a list of the possible positions but do not understand how to implement it:
[(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),
(2,1),(2,2),(2,3),(2,4),(2,5),(2,6),(2,7),(2,8),
(3,1),(3,2),(3,3),(3,4),(3,5),(3,6),(3,7),(3,8),
(4,1),(4,2),(4,3),(4,4),(4,5),(4,6),(4,7),(4,8),
(5,1),(5,2),(5,3),(5,4),(5,5),(5,6),(5,7),(5,8),
(6,1),(6,2),(6,3),(6,4),(6,5),(6,6),(6,7),(6,8),
(7,1),(7,2),(7,3),(7,4),(7,5),(7,6),(7,7),(7,8),
(8,1),(8,2),(8,3),(8,4),(8,5),(8,6),(8,7),(8,8)]
This seems like it would be a simple program but I cannot seem to grasp the concepts or at least put them all together into a workable program.
Any help in direction would be greatly appreciated.
There are quite some issues with your code. Let's go through it one at a time.
1. Possible positions
Although your list of possible positions is OK, I wouldn't hard-code it like that. It's very easy to do a check if a position is on the grid:
grid_position(X, Y) :-
X >= 1,
X =< 8,
Y >= 1,
Y =< 8.
Do note that this can only be used to verify a given position. If you want to be able to generate all possible positions, you can use in/2 from library(clpfd).
2. Allowed positions
If there is no simple logic as above for positions that are blocked, there is no other way than to enumerate them yourself.
blocked(1, 2).
blocked(4, 2).
blocked(4, 1).
Using this, we can determine which are the allowed positions for our gorilla: any position that is on the grid, but is not blocked.
allowed_position(X, Y) :-
grid_position(X, Y),
\+blocked(X, Y).
3. move
The main problem here is that writing X+1 in the head of the clause doesn't do what you think it does. To evaluate arithmetic expressions, you need to use the is predicate.
Additionally, I would only allow a move if the next location is allowed. Since the gorilla is already at the current location, I don't include a check to see if this location is actually allowed.
move(X, Y, X2, Y) :-
X2 is X + 1,
allowed_position(X2, Y).
move(X, Y, X, Y2) :-
Y2 is Y + 1,
allowed_position(X, Y2).
4. path
Here's how I interpret the requirement: given a start position, return the list of moves used to reach the end position.
To do this, we're going to need 3 arguments: the X and Y positions, and the output. The output here will be a list of positions rather than a list of moves, I'll leave it up to you to change that if needed.
So what makes up our path? Well, first you make one move, and then you find the rest of the path from the next position.
path(X, Y, [(X,Y)|Ps]) :-
move(X, Y, X2, Y2),
path(X1, Y1, Ps).
Of course we have to make sure this ends at the target position, so for base case we can use:
path(8, 8, (8, 8)).
You may also want to verify that the initial position is an allowed position, which I have left out.
Combine everything, and you get output such as below.
?- path(5,6,L).
L = [(5,6),(6,6),(7,6),(8,6),(8,7)|(8,8)] ? ;
L = [(5,6),(6,6),(7,6),(7,7),(8,7)|(8,8)] ? ;
L = [(5,6),(6,6),(7,6),(7,7),(7,8)|(8,8)] ? ;
...
This may not be exactly what you're looking for, but I hope it helps you well on the way.
So you might want to say where you are moving while you're doing that. So I'll suggest a predicate move/3 like this:
% move(From_Position, To_Position, Direction).
move((X,Y),(X,Y1), up) :-
grid(G),
member((X,Y1),G),
Y1 is Y + 1.
move((X,Y),(X1,Y), rigth):-
grid(G),
member((X1,Y),G),
X1 is X + 1.
The grid calls are there to ensure that you'll always stay on the grid. you also could use a smarter predicate in_grid and avoid the member call (which is quite time consuming).
grid([(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),
(2,1),(2,2),(2,3),(2,4),(2,5),(2,6),(2,7),(2,8),
(3,1),(3,2),(3,3),(3,4),(3,5),(3,6),(3,7),(3,8),
(4,1),(4,2),(4,3),(4,4),(4,5),(4,6),(4,7),(4,8),
(5,1),(5,2),(5,3),(5,4),(5,5),(5,6),(5,7),(5,8),
(6,1),(6,2),(6,3),(6,4),(6,5),(6,6),(6,7),(6,8),
(7,1),(7,2),(7,3),(7,4),(7,5),(7,6),(7,7),(7,8),
(8,1),(8,2),(8,3),(8,4),(8,5),(8,6),(8,7),(8,8)]).
A path should probably be a list of directions:
path((8,8), []).
path(Position, [Direction| Before]):-
\+ Position = (8,8),
move(Position, NewPosition, Direction),
path(NewPosition,Before).
To Accumulate, you can use bagof or setof
all_paths(Position,Paths):-
setof(Path,path(Position,Path),Paths).

Resources