Prolog seemingly ending recursive call without going back up - prolog

I've got the following two edges defined:
edge(a,b).
edge(b,c).
add(X, L, [X | L]).
Now I'm trying to recursively build the path from a to c (a,b,c) using this:
path(FROM,TO,W):-
edge(FROM,TO),
add(TO, [], X),
add(FROM, X, W).
path(FROM,TO,W):-
edge(FROM,Y),
path(Y,TO, W),
add(FROM, W, _).
It seems to work fine in the base case as path(a,b,X) will output X = [a,b].
However, path(a,c,X) only outputs X = [b,c], as if it just gets to the base case and ends it there rather than going back up the recursive call.
Ultimately, I would like it to output X = [a,b,c] but I'm out of ideas.
FYI I'm using SWI-Prolog.

How can you identify the problem yourself? There is an easy way to do so. First, identify the cases you expect to be true and cases you expect it to fail. Here are some plus some auxiliary definitions to ease debugging
:- initialization(path(a,b,[a,b])).
:- initialization(path(a,c,[a,b,c])). % intended to be true, initially false
:- initialization(\+path(a,b,[a,_,c])).
:- initialization(\+path(a,d,_)). % no node d, thus no path
:- op(950, fy, *).
:- meta_predicate(*(0)).
*_G_0. % this permits us to remove goals by adding a * in front.
Now, save the program ..and say [program]. You will get a warning like
* user:user:path(a,c,[a,b,c]) - goal failed
So we know that we have not solved the problem.
Now, try to generalize the program by adding * in front of a goal. You will note that for each and every such generalization there will be more errors appearing (and in one case even non-termination). Except for the last goal where everything remains the same. So removing or replacing that goal seems to be a good idea.
Sooner or later you will encounter cycles. For acyclic paths, use path/4:
?- path(edge, Path, A, B).

Your code does not work correctly because it discards the result produced by the subgoal add(FROM, W, _), in the second clause of the predicate path/3. To solve the problem, you need to modify your code as following:
path(From, To, W):-
edge(From, To),
add(To, [], X),
add(From, X, W).
path(From, To, PATH):-
edge(From, Y),
path(Y,To, W),
add(From, W, PATH). % <== get PATH
An even better version of this code is as follows:
path(From, To, [From, To]) :-
edge(From, To).
path(From, To, [From|Path]) :-
edge(From, X),
path(X, To, Path).

Related

PROLOG, Is it possible to collect all result from a predicate to a list, without using built in predicates, such as bagof or findall

If for example, I have a Prolog predicate like
a(A, B).
Is it possible to collect, given a value of A, is it possible to collect all values of B that succeeds the predicate a, into a list, without using built in predicates such as bagof/3 or findall/3.
You have two obvious options (obvious to me; it seems there is more). One is to indeed use the database to save the state. This has at least one pitfall: depending on the name you decide to use for the temporary state, you might destroy some other state your program is keeping. This is the same old "global state"/"global variable" problem that all languages suffer from.
The other option would be to use a "local variable" and non-backtracking assignment to it to keep the temporary state. This is most probably going to be implementation dependent. For starters, you can look at nb_setarg/3 for SWI-Prolog.
However, both solutions are silly, given that you have findall, bagof, setof. You must motivate the need for something else to replace those. Just saying "is it possible" is not good enough since it is possible, but completely unnecessary, unless you know something else that you aren't telling us.
Here's a sketch of a stupid setof that uses other builtins, though not assert, and not exactly the ones listed by #false in a comment.
We'll use a list accumulator to collect solutions:
stupid_setof(Template, Goal, Set) :-
stupid_setof(Template, Goal, [], Set).
There are two cases to consider: Either the Goal can enumerate a solution we have not seen so far, or the only ones it can enumerate are already in our accumulator.
First, the case where there are no solutions we haven't seen. In this case we're done.
stupid_setof(Template, Goal, SolutionsSeen, Set) :-
\+ ( call(Goal),
\+ member(Template, SolutionsSeen) ),
!,
sort(SolutionsSeen, Set).
Now for the stupid part. Consider:
foo(a).
foo(b).
foo(c).
?- SolutionsSeen = [], foo(X), \+ member(X, SolutionsSeen), !.
SolutionsSeen = [],
X = a.
?- SolutionsSeen = [a], foo(X), \+ member(X, SolutionsSeen), !.
SolutionsSeen = [a],
X = b.
?- SolutionsSeen = [a, b], foo(X), \+ member(X, SolutionsSeen), !.
SolutionsSeen = [a, b],
X = c.
?- SolutionsSeen = [a, b, c], foo(X), \+ member(X, SolutionsSeen), !.
false.
So given a list of solutions we've seen before, we can force Goal to backtrack until it gives us one that we haven't seen before. Note that these queries are independent: In each one we have a completely fresh copy of the foo(X) goal that starts enumerating from a.
We can do the same thing programmatically by copying the original goal before calling it, forcing it to start a fresh enumeration from a fresh instance of the Goal. If this finds a new solution, we can add it to our solutions, then repeat with another fresh copy of the goal, forcing it to enumerate yet another new solution, and so on:
stupid_setof(Template, Goal, SolutionsSeen, Set) :-
copy_term(Goal-Template, GoalInstance-Solution),
call(GoalInstance),
\+ member(Solution, SolutionsSeen),
!,
stupid_setof(Template, Goal, [Solution | SolutionsSeen], Set).
If Goal has N answers, this will enumerate on the order of N**2 of them and do corresponding linear searches in the solutions list. It will also perform any side effects that Goal has multiple times.
But it "works":
?- stupid_setof(X, foo(X), Xs).
Xs = [a, b, c].
And, despite all of its stupidity, this is still less stupid than the standard setof/3 if Goal has no solutions:
:- dynamic bar/1. % no clauses
?- setof(X, bar(X), Set).
false.
?- stupid_setof(X, bar(X), Set).
Set = [].

Commutativity of Cut Operator in Prolog

I'm currently studying Prolog, and in one of the notes I'm reading an example is given of how to use the cut operator correctly. Consider the following function to remove all elements of a particular value from a list.
rm(_,[],[]).
rm(A,[A|L],R) :- rm(A,L,R).
rm(A,[B|L],[B|R]) :- rm(A,L,R).
Due to backtracking, this is not a correct definition of the function, and the function will return all sublists of the list obtained from removing some elements of a particular value, but not necessarily all of them. The notes I'm reading say that a correct way to fix this is to replace the second line by the line
rm(A,[A|L],R) :- !, rm(A,L,R)
But that replacing the line by
rm(A,[A|L],R) :- rm(A,L,R), !
is not correct. I'm not sure why the second example is an incorrect way to fix the function. In swipl, replacing the second term by these fixes seems to always return the same answer on the test cases I consider. What am I missing here?
Your example is a perfect example to illustrate why using the cut here is never a good idea.
Using rm(A,[A|L],R) :- !, rm(A,L,R). makes only sense if both the first and second argument are sufficiently instantiated. But if they are insufficiently instantiated, you get an incomplete answer like:
?- rm(X, [a], R).
X = a, R = []. % incomplete
This clearly misses an answer, as it constrains X to be a only. But if X is anything else, we get a different result, namely:
?- X = b, rm(X,[a],R).
R = [a].
Using the cut at the end as in rm(A,[A|L],R) :- rm(A,L,R), !. is even worse: First, all our assumptions so far must hold, and then additionally the third argument must not be instantiated. Otherwise we get additional incorrect solutions.
?- rm(a,[a],R).
R = [].
?- rm(a,[a],[a]).
true, unexpected. % incorrect
Just recall what we are asking here:
User: When removing a from the list [a] what do we get?
Prolog: Nothing, nil, nada.
User: But can't I have instead of nothing just [a]? Please!
Prolog: OK, I give in.
That's not the way you want to implement an accounting system.
So both uses of cuts are bad. But the second one is clearly worse for it has many more preconditions to remember and is also inefficient.
On the other hand there are some cases where you can use these predicates. But typically it is quite difficult to remember when this is safe. Thus such cuts are a permanent source of errors.
Is there any hope to get rid of all this fine print? Fortunately, there is a way out using if_/3 from library(reif) for SICStus|SWI. Download it and say:
:- use_module(reif).
rm(_,[],[]).
rm(A,[X|Xs], Ys0) :-
if_(A = X, Ys0 = Ys, Ys0 = [X|Ys]),
rm(A, Xs, Ys).
This program is comparably efficient but does not have any of the aforementioned defects:
?- rm(X, [a], R).
X = a, R = []
; R = [a], dif(X, a).
Note the second new answer! It says that for all X that are different to a, the list remains unchanged.

Two different paths from X to Y in a graph

I am stuck with the following Prolog question:
Given the edges of a graph with no cycles as facts. e.g:
edge(a, b).
edge(b, c).
edge(c, d).
edge(c, e).
...
I have to write a predicate that tests whether there are two different paths between vertices X and Y. e.g the call two_paths(a, c). should return true if there are two different paths from node a to node c. I know how to check whether there is a path between two vertices:
path(X, Y) :- edge(X, Y).
path(X, Y) :- edge(X, Z), path(Z, Y).
But how should I do this to check for two distinct paths? Thank you very much for your help.
An idea might be to create a predicate path/3 that returns the constructed path, and then query for two paths that are different. Something like:
path(X,Y,[X,Y]) :- edge(X,Y).
path(X,Y,[X|T]) :- edge(X,Z), path(Z,Y,T).
Now path(a,c,T) will show you the path:
?- path(a,c,L).
L = [a, b, c] ;
false.
Now you could construct a predicate:
two_paths(X,Y) :-
path(X,Y,La),
path(X,Y,Lb),
dif(La,Lb).
In other words, you ask Prolog to construct for you a path La, next construct for you a path Lb and then check if they are not equal (dif(La,Lb)). The first constructed Lb will be equivalent to La, but due to Prologs backtracking mechanism, it will try to construct you another path for which the condition might succeed. This is a rather pure Prolog implementation (with no cut (!), once/1, etc.). More efficient approaches exists since here you will "redo" the work in your second call.
A more efficient approach could be to construct a predicate path_avoid/3 (or path_avoid/4) where you feed the first constructed path to the predicate and thus force your program to at least at some point perform a different step from the one presented. I leave this open as a potential exercise.

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!

run function with all possibilities resulted from other function

I have two predicates:
foo(Y,X)
bar(Y,Z)
After running foo, How can I run bar with all possibilities of Y ?
example:
foo(Y, key) % all possibilities of Y => chat
% faq
% about
% search
How can I run bar with these all possibilities ?
bar(chat, Z)
bar(faq, Z)
bar(about, Z)
bar(serach, Z)
And then store all the results of Z in a list Zs?
foo/2 and bar/2 are already in join, and after each run of foo/2 bar/2 will be tried.
Maybe you are looking for forall(foo(Y,X), bar(Y,Z)), that run all possibilities of foo/2, and then bar/2. I.e. is required that bar/2 doesn't fail.
To understand the behaviour of forall/2, as well as other all solutions builtins, like setof/3, can be useful test with very simple builtins, with well known behaviour:
?- forall(member(X,[f,o,o]),(member(Y,[b,a,r]),writeln(X-Y))).
f-b
o-b
o-b
true.
You can see that the complete solution search of forall applies to its first argument, not the second.
HTH
allZs(X, Zs) :-
setof(Y, foo(Y, X), Ys),
maplist(bar, Ys, Zs).
related SWI-Prolog man pages: Finding all Solutions to a Goal and library apply
Note: usually in Prolog the convention is to put intput arguments before output ones - in your first predicate that'd mean foo(X, Y) instead of foo(Y, X). Plus here it'd outline the transitivity: foo(X, Y), bar(Y, Z)..
I think you want something like this:
barOnList([], []).
barOnList([Y|Ys], [Z|Zs]) :- bar(Y, Z), barOnList(Ys, Zs).

Resources