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!
Related
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).
Hey so this is my code so far. I am only a begginer in prolog but i need it for school
firstElement([_|_], [Elem1|List1], [Elem2|List2]):-
Elem1 =< Elem2, merge([Elem1] , List1, [Elem2|List2]);
merge([], [Elem2], List2).
merge([Head|Tail], [Elem1|List1], [Elem2|List2]):-
Elem1 =< Elem2,!, add(Elem1,[Head|Tail],[Head|Tail1]),
merge([Head|Tail1], List1, [Elem2|List2]);
add(Elem2,[Head|Tail],[Head|Tail1]),
merge([Head|Tail1], [Elem1|List1], List2).
merge([Head|Tail], [], [Elem2|List2]):-
add(Elem2,[Head|Tail],[Head|Tail1]).
merge([Head|Tail], [Elem1|List1], []):-
add(Elem1,[Head|Tail],[Head|Tail1]).
merge([Head|Tail], [], []).
add(X,[],[X]).
add(X,[Y|Tail],[Y|Tail1]):-
add(X,Tail,Tail1).
I found out that everytime it gets out of a merge it keeps forgetting the last number so it gets back to nothing in the end.
I think you’ve gotten very mixed up here with your code. A complete solution can be had without helpers and with only a few clauses.
First let us discuss the two base cases involving empty lists:
merge(X, [], X).
merge([], X, X).
You don’t quite have these, but I see some sort of recognition that you need to handle empty lists specially in your second and third clauses, but I think you got confused and overcomplicated them. There’s really three scenarios covered by these two clauses. The case where both lists are empty is a freebie covered by both of them, but since that case would work out to merge([], [], []), it’s covered. The big idea here is that if you exhaust either list, because they were sorted, what you have left in the other list is your result. Think about it.
This leaves the interesting case, which is one where we have some items in both lists. Essentially what you want to do is select the smaller of the two, and then recur on the entire other list and the remainder of the one you selected the smaller value from. This is one clause for that:
merge([L|Ls], [R|Rs], [L|Merged]) :-
L #< R,
merge(Ls, [R|Rs], Merged).
Here’s what you should note:
The “result” has L prepended to the recursively constructed remainder.
The recursive call to merge rebuilds the entire second list, using [R|Rs].
It should be possible to build the other clause by looking at this.
As an intermediate Prolog user, I would be naturally a bit suspicious of using two clauses to do this work, because it’s going to create unnecessary choice points. As a beginner, you will be tempted to erase those choice points using cuts, which will go badly for you. A more intermediate approach would be to subsume both of the necessary clauses into one using a conditional operator:
merge([L|Ls], [R|Rs], [N|Ns]) :-
( L #< R ->
N = L, merge(Ls, [R|Rs], Ns)
; —- other case goes here
).
An expert would probably build it using if_/3 instead:
#<(X,Y,true) :- X #< Y.
#<(X,Y,false) :- X #>= Y.
merge([L|Ls], [R|Rs], [N|Ns]) :-
if_(#<(L,R),
(N = L, merge(Ls, [R|Rs], Ns)),
( -- other case here )).
Anyway, I hope this helps illustrate the situation.
I am working through Seven Languages in Seven Weeks, but there is something I don't understand about prolog. I have the following program (based on their wallace and grommit program):
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- \+(X = Y), onTeam(X, Z), onTeam(Y, Z).
and load it like this
?- ['teams.pl'].
true.
but it doesn't give me any solutions to the following
?- teamMate(a, X).
false.
it can solve simpler stuff (which is shown in the book):
?- onTeam(b, X).
X = aTeam ;
X = superTeam.
and there are solutions:
?- teamMate(a, b).
true ;
false.
What am I missing? I have tried with both gnu prolog and swipl.
...AND THERE IS MORE...
when you move the "can't be your own teammate" restriction to then end:
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- onTeam(X, Z), onTeam(Y, Z), \+(X = Y).
it gives me the solutions I would expect:
?- ['teams.pl'].
true.
?- teamMate(a, X).
X = b.
?- teamMate(b, X).
X = a ;
X = c.
What gives?
You have made a very good observation! In fact, the situation is even worse, because even the most general query fails:
?- teamMate(X, Y).
false.
Declaratively, this means "there are no solutions whatsoever", which is obviously wrong and not how we expect relations to behave: If there are solutions, then more general queries must not fail.
The reason you get this strange and logically incorrect behaviour is that (\+)/1 is only sound if its arguments are sufficiently instantiated.
To express disequality of terms in a more general way, which works correctly no matter if the arguments are instantiated or not, use dif/2, or, if your Prolog system does not provide it, the safe approximation iso_dif/2 which you can find in the prolog-dif tag.
For example, in your case (note_that_I_am_using_underscores_for_readability instead of tuckingTheNamesTogetherWhichMakesThemHarderToRead):
team_mate(X, Y) :- dif(X, Y), on_team(X, Z), on_team(Y, Z).
Your query now works exactly as expected:
?- team_mate(a, X).
X = b.
The most general query of course also works correctly:
?- team_mate(X, Y).
X = a,
Y = b ;
X = b,
Y = a ;
X = b,
Y = c ;
etc.
Thus, using dif/2 to express disequality preserves logical-purity of your relations: The system now no longer simply says false even though there are solutions. Instead, you get the answer you expect! Note that, in contrast to before, this also works no matter where you place the call!
The answer by mat gives you some high-level considerations and a solution. My answer is a more about the underlying reasons, which might or might not be interesting to you.
(By the way, while learning Prolog, I asked pretty much the same question and got a very similar answer by the same user. Great.)
The proof tree
You have a question:
Are two players team mates?
To get an answer from Prolog, you formulate a query:
?- team_mate(X, Y).
where both X and Y can be free variables or bound.
Based on your database of predicates (facts and rules), Prolog tries to find a proof and gives you solutions. Prolog searches for a proof by doing a depth-first traversal of a proof tree.
In your first implementation, \+ (X = Y) comes before anything else, so it at the root node of the tree, and will be evaluated before the following goals. And if either X or Y is a free variable, X = Y must succeed, which means that \+ (X = Y) must fail. So the query must fail.
On the other hand, if either X or Y is a free variable, dif(X, Y) will succeed, but a later attempt to unify them with each other must fail. At that point, Prolog will have to look for a proof down another branch of the proof tree, if there are any left.
(With the proof tree in mind, try to figure out a way of implementing dif/2: do you think it is possible without either a) adding some kind of state to the arguments of dif/2 or b) changing the resolution strategy?)
And finally, if you put \+ (X = Y) at the very end, and take care that both X and Y are ground by the time it is evaluated, then the unification becomes more like a simple comparison, and it can fail, so that the negation can succeed.
How do I define a binary operation on a list in prolog and then check its properties such as closure , associative, transitive , identity etc. ? I am new to prolog.. I don't know whether it is the place to ask but I tried and I didn't come across anything somewhere.
In Prolog you define predicates, i.e. relations among a symbol (called functor) and its arguments.
A predicate doesn't have a 'return value', just a 'truth value', depending of whether it can be evaluated WRT its arguments. Then your question it's not easy to answer.
Associativity, transitivity, identity, are of little help when it come down to speaking about predicates. The first and most common property we wish to evaluate is termination, because Prolog control flow it's a bit unusual and can easily lead to infinite recursion.
Anyway, the simpler binary relation on a list is member/2, that holds when its first argument it's an element of the second argument (the list).
member(X, [X|_]).
member(X, [_|T]) :- member(X,T).
I can't see any benefit in assessing that it's not associative, neither transitive (its arguments are of different types !).
Common operations like intersection, union, etc typically needs 3 arguments, where the last is the result of the operation performed between 2 lists.
Identity in Prolog (that is an implementation of first order logic) deserves a special role. Indeed, the usual programming symbol = used to assess identity, really performs a (potentially) complex operation, called unification. You can see from the (succint) documentation page that it's 'just' a matching between arbitrary terms.
You could do something like this:
% Define sets I want to try
set7([0,1,2,3,4,5,6]).
% Define operations
% Sum modulo 7
sum7(X, Y, R) :-
R is (X+Y) mod 7.
% Normal sum
nsum(X, Y, R) :-
R is X + Y.
% A given set is closed if there is not a single case which
% indicates that it is not closed
closed(S, Operator) :-
\+ n_closed(S, Operator, _), !.
% This predicate will succeed if it finds one pair of elements
% from S which, when operated upon, will give a result R which
% is outside of the set
n_closed(S, Operator, R) :-
member(X, S),
member(Y, S),
Operation =.. [Operator, X, Y, R],
Operation,
\+ member(R, S).
When you execute it, you get these results:
| ?- set7(S), closed(S, sum7).
(1 ms) yes
| ?- set7(S), closed(S, nsum).
no
I'm not convinced my closure check is optimal, but it gives some ideas for how to play with it.
How to implement rule1 that succeeds iff rule2 returns two or more results?
rule1(X) :-
rule2(X, _).
How can I count the results, and then set a minimum for when to succeed?
How can I count the results, and then set a minimum for when it's true?
It is not clear what you mean by results. So I will make some guesses. A result might be:
A solution. For example, the goal member(X,[1,2,1]) has two solutions. Not three. In this case consider using either setof/3 or a similar predicate. In any case, you should first understand setof/3 before addressing the problem you have.
An answer. The goal member(X,[1,2,1]) has three answers. The goal member(X,[Y,Z]) has two answers, but infinitely many solutions.
So if you want to ensure that there are at least a certain number of answers, define:
at_least(Goal, N) :-
\+ \+ call_nth(Goal, N).
with call_nth/2 defined in another SO-answer.
Note that the other SO-answers are not correct: They either do not terminate or produce unexpected instantiations.
you can use library(aggregate) to count solutions
:- use_module(library(aggregate)).
% it's useful to declare this for modularization
:- meta_predicate at_least(0, +).
at_least(Predicate, Minimum) :-
aggregate_all(count, Predicate, N),
N >= Minimum.
example:
?- at_least(member(_,[1,2,3]),3).
true.
?- at_least(member(_,[1,2,3]),4).
false.
edit here is a more efficient way, using SWI-Prolog facilities for global variables
at_least(P, N) :-
nb_setval(at_least, 0),
P,
nb_getval(at_least, C),
S is C + 1,
( S >= N, ! ; nb_setval(at_least, S), fail ).
with this definition, P is called just N times. (I introduce a service predicate m/2 that displays what it returns)
m(X, L) :- member(X, L), writeln(x:X).
?- at_least(m(X,[1,2,3]),2).
x:1
x:2
X = 2.
edit accounting for #false comment, I tried
?- call_nth(m(X,[1,2,3]),2).
x:1
x:2
X = 2 ;
x:3
false.
with call_nth from here.
From the practical point of view, I think nb_setval (vs nb_setarg) suffers the usual tradeoffs between global and local variables. I.e. for some task could be handly to know what's the limit hit to accept the condition. If this is not required, nb_setarg it's more clean.
Bottom line: the better way to do would clearly be using call_nth, with the 'trick' of double negation solving the undue variable instantiation.