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.
Related
I am learning prolog, what I am doing is writing a predicate to join two list. For example, if I query:
joinL([22,33,44],[1,2,3],L)
It will show L = [22,33,44,1,2,3].
To do it, I have tried to write predicate as followings:
joinL([],L2,L2).
joinL([H|T],L2,L):-joinL(T,L2,L),L = [H|L].
But when I query
joinL([22,33,44],[1,2,3],L)
It does not show desired result as i have just described above. Actually, it returns false.
What I want to ask is: "How did my code become wrong?", I do NOT ask "How to write predicate that join two list in prolog?" cause I can google it easily, and when compare with my code, I curiously want to know why i am wrong with my code. Can any one help me! Thank you all for reading and answering my question!
The problem is that you are using the = in the same way as one would use assignment:
L = [H|L]
In a state-changing language this means that whatever is stored in L (which is supposed to be a list) becomes a new list, made by tacking H to the front: [H|L]
In Prolog this states that what we know about L is that it is equal to [H|L]- equal to itself with H tacked to the front. This is not possible for any L though (actually, it is, if L is an infinite list containing only H but the proof engine of Prolog is not good enough to deal with that). Prolog's proof search fails at that hurdle and will return "false" - there are no solutions to the logic program you have entered.
(More after a coffee)
Here is how to think about this:
Ok, so I would like to state some logic facts about the problem of "list concatenation" so that, based on those logic facts, and given two completely-specified lists L1, L2, Prolog's proof search can determine enough about what the concatenated list LJ should look like to actually output it completely!
We decide to specify a predicate joinL(list1,list2,joinedlist) to express this.
First, we cover a special edge case:
joinL([],L2,LJ) :- LJ = L2.
So, it is stated that the 'joinL' relationship between the empty list '[]' and the joined list 'LJ' is such that 'LJ' is necessarily equal to 'L2'.
The logical reading is:
(LJ = L2) → joinL([],L2,LJ)
The operational reading is:
In order to prove joinL([],L2,LJ) you must prove LJ = L2 (which can either be verified if LJ and L2 are already known or can be added to the solution's known constraints if not.
There is also the reading of the SLD resolution, where you add the negation of joinL([],L2,LJ) to your set of logic facts, then try to prove ⊥ (the contradiction also know as the empty statement) using resolution, but I have not found that view to be particularly helpful.
Anyway, let's state more things about the edge cases:
joinL([],L2,LJ) :- LJ = L2.
joinL(L1,[],LJ) :- LJ = L1.
joinL([],[],LJ) :- LJ = [].
This will already enable the Prolog proof engine to determine LJ completely whenever any of the L1 and L2 is the empty list.
One commonly abbreviates to:
joinL([],L,L).
joinL(L,[],L).
joinL([],[],[]).
(The above abbreviation would not be possible in Picat for example)
And the third statement can be dropped because the other two "subsume it" - they cover that case more generally. Thus:
joinL([],L,L).
joinL(L,[],L).
Now for the case of non-empty lists. A fat part of logic programming is about inductive (or recursive) definitions of predicates (see this), so let's go:
joinL([H|T],L2,LJ) :- LJ = [H|LX], joinL(T,L2,LX).
Again, this is just a specification, where we say that the concatenation of a nonempty list [H|T] and any list L2 is a list LJ such that LJ is composed of H and a list LX and LX is the concatenation of T and L2.
This is useful to the Prolog proof engine because it gives more information about LJ (in fact, it specifies what the first element of LJ is) and reduces the problem to finding out more using the same predicate but a problem that is a little nearer to the base case with the empty list: joinL(T,L2,LX). If the proof goes down that route it will eventually hit joinL([],L2,LX), find out that L2 = LX and be able to successfully return from its descent.
joinL([H|T],L2,LJ) :- LJ = [H|LX], joinL(T,L2,LX).
is commonly abbreviated to
joinL([H|T],L2,[H|LX]) :- joinL(T,L2,LX).
Looks like we have covered everything with:
joinL([],L,L).
joinL(L,[],L).
joinL([H|T],L2,[H|LX]) :- joinL(T,L2,LX).
We can even drop the second statement, as it is covered by the recursive descent with L2 always equal to '[]'. It gives us a shorter program which burns cycles needlessly when L2 is '[]':
joinL([],L,L).
joinL([H|T],L2,[H|LX]) :- joinL(T,L2,LX).
Let's test this. One should use unit tests but I can't be bothered now and will just run these in SWISH. Let's see what Prolog can find out about X:
joinL([],[],X). % X = []
joinL([1,2],[],X). % X = [1,2]
joinL([],[1,2],X). % X = [1,2]
joinL([3,4],[1,2],X). % X = [3,4,1,2]
joinL([1,2],[3,4],X). % X = [1,2,3,4]
One can constrain the result completely, transforming Prolog into a checker:
joinL([3,4],[1,2],[3,4,1,2]). % true
joinL([3,4],[1,2],[1,1,1,1]). % false
Sometimes the predicate works backwards too, but often more careful design is needed. Not here:
joinL([3,4],L2,[3,4,1,2]). % L2 = [1, 2]
For this one, Prolog suggests a second solution might exist but there is none of course:
joinL(L1,[3,4],[1,2,3,4]). % L1 = [1, 2]
Find me something impossible:
joinL(L1,[3,4],[1,2,100,100]). % false
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
| ?-
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.
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.
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.