Related
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.
I have a task to do in Prolog. It seems to be easy, but I am really novice in this kind of language and I can't get use to it.
I have to write a function path_L(a,z,N) , where a,z - edges o a "road", N is the variable that I am looking for. So, there are many edges defining one-way direction: edge(a,b), edge(b,c), edge(b,d), edge(e,f), etc. The goal of the path_L function is to give a result that is the number of sections between (a,z) in the form of N=result. So if for example:
path_L(a,b,N). -> N=1
path_L(a,c,N). -> N=2
I have already defined another function defining if a path between (X,Y) exists:
path(X,Y):-edge(X,Y).
path(X,Y):-edge(X,Z),path(Z,Y).
Assuming, like #lurker said, that you meant your predicates for finding a path are:
path(X,Y):- edge(X,Y).
path(X,Y):- edge(X,Z), path(Z,Y).
And given a few clauses stating the existance of edges as:
edge(a,b).
edge(b,c).
edge(c,d).
You got the right idea that path_L should have an additional argument for the 'count' of edges between nodes. A simple version of what you want (with some caveats) is below:
path_L(X,Y,1):- edge(X,Y).
path_L(X,Y,R):- edge(X,Z), path_L(Z,Y,N), R is N+1.
Notice how that the first case simply unifies the third argument with '1', so an objective clause like path_L(a,b,2) ("Distance between a and b is 2") correctly fails, while path_L(a,b,R) (notice R is a variable) succeeds with R unifying with 1. It's a neat feature of the paradigm that the same definition is good for 'both ways'.
Another example is the objective path_L(a,B,2) (notice B is a variable), which succeeds with B unifying with c - because c is the node with a distance of 2 from a.
Finally, assume instead a graph given by:
edge(a,b).
edge(b,c).
edge(c,d).
edge(d,x).
edge(a,x).
An objective clause like path_L(a,x,R) should first succeed with R = 1, and then, if requested (pressing ; on your terminal) with R = 4. This is because there are two valid paths (with lenghts 1 and 4) from a to x. The order of the predicates matters - if you defined path_L as such:
path_L(X,Y,R):- edge(X,A), path_L(A,Y,N), R is N+1.
path_L(X,Y,1):- edge(X,Y).
That same query would result first in R=4, and then in R=1. This is because the order in which predicates are defined matter. In fact, the mechanisms through which Prolog choose which predicates to test and how clauses are chosen for 'solving the problem' are well defined; and you should definitely look it up if you get into logic programming.
Hope this helps.
P.S.: about those caveats - e.g., none of the above allow a path of zero-length from a node to itself. Depending on what you want, that could be the case or a mistake.
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.
We are given a graph with the following facts:
edge(a,b)
edge(a,c)
edge(b,a)
edge(c,d)
edge(d,d)
edge(d,e)
edge(e,f)
edge(f,g)
edge(g,e)
And we are asked to define a rule, cycle(X), that determines if there is a cycle starting from the node X.
I am really lost on how to do this, I tried attempting to traverse the nodes and checking if the next one would be the starting one again but I cannot seem to get it to work
Archie's idea is a good starting point, but it will create an infinite loop if it finds another cycle while searching for the path.
I also haven't used prolog for years, but you will need something like path(X,Y,Visited), where you keep track of the visited nodes, preventing the endless loops.
I used Depth First Search with visited node list if we encounter any visited node during traversal it returns true. I tested with small inputs it looks like working correctly.
cycle(X):- cycleh(X,[X]).
cycleh(X,Visited) :- edge(X,Y), (member(Y,Visited) -> !,true; cycleh(Y,[Y|Visited])).
This should do the trick:
cycle( X ) :-
cycle( X , [] ).
cycle( Curr , Visited ) :-
member( Curr, Visited ) ,
!.
cycle( Curr , Visited ) :-
edge( Curr , Next ) ,
cycle( Next , [Curr|Visited] ) .
Although it appears to be a similar solution to #Gökhan Uras -- great minds think alike! Or something B^)
The basic logic is that you have a cycle if the current node has already been visited (the first clause in the cycle/2 helper predicate. At that point, we cut(!) and declare success The reason for the cut (!) is that without it, backtracking would result in revisiting a node already visited and thus an infinite set of cycles.
If the current node has not been visited, we grab an edge anchored at the current node and visit that. Backtracking into the 2nd clause of cycle/2 visits the next edge, so once a particular path is exhausted, cycle/2 backtracks and tries another path.
I haven't been using Prolog for some time, but here is my approach to this problem.
You could make rule path(X,Y) that checks if there exists path from node X to Y. A path is a single edge or an edge leading to a path. Having this, it's easy to find cycle starting from node X -- it will be simply path(X,X). Here is my implementation (taken from the top of my head and not necessarily correct, but gives the idea):
path(X,Y) :- edge(X,Y).
path(X,Y) :- edge(X,Z), path(Z,Y).
cycle(X) :- path(X,X).
If your Prolog system has a forward chainer, you could use it to determine cycles. But watch out, it might eat quite some memory, since it will generate and keep the path/2 facts.
Here is how you would need to formulate the rules in a forward chainer that does not eliminate automatically duplicates. The \+ is there to explicitly eliminate the duplicates:
:- forward edge/2.
:- forward path/2.
path(X,Y) :- edge(X,Y), \+ path(X,Y).
path(X,Y) :- edge(X,Z), path(Z,Y), \+ path(X,Y).
cycle(X) :- path(X,X).
To make the example a little bit more interesting what concerns the result, I have dropped the edge(d,d). Here is a sample run:
?- postulate(edge(a,b)), postulate(edge(a,c)), postulate(edge(b,a)),
postulate(edge(c,d)), postulate(edge(d,e)), postulate(edge(e,f)),
postulate(edge(f,g)), postulate(edge(g,e)), cycle(X).
X = a ;
X = b ;
X = e ;
X = f ;
X = g
The postulate/1 predicate here posts an event and keeps the propagator of the forward chainer running. How to write your forward rules depends on the Prolog systems respective library you are using.
P.S.: There is still some research going on:
http://x10.sourceforge.net/documentation/papers/X10Workshop2011/elton_slides.pdf
It's been a while since I used Prolog, but perhaps this approach will work: A path is a sequence of edges where each edge starts on the node the previous edge ended on (e.g. a -> b, b -> c, c -> d). The trivial path is a single edge, and more complex paths can be formed by taking an existing path and adding an edge to it. A cycle is a path that starts and ends on the same node. Can you use these definitions to build your Prolog rules?