path finding in prolog - algorithm

I need to write a program in prolog for finding paths, for example, for the graph:
edge(a, b).
edge(a, c).
edge(c, b).
and the test case are:
/* test case 1 */
?- path(a, b, P).
P = [a, b] ;
P = [a, c, b] ;
false.
/* test case 2 */
?- path(c,b,[c,b]).
true.
and my code is
path(X,Y,[X,Y]):-
edge(X,Y).
path(X,Z,[X|P]):-
edge(X,Y),
path(Y,Z,P).
However, for the test case 2, my code will show
?- path(c,b,[c,b]).
true;
false.
I know that I should add a cut in my code to remove the false in case 2, but it will remove the false in case 1 too. How can I solve this problem?

Its because both of your functions are same and i think prolog checks both....in first case it fails because only one of the function satisfies it i.e. path(c,b,P) but in second case
path(c,b,[c,b]
It check both the functions
path(X,Y,[X|P] here X = c and P = b
and
path(X,Y,[X,Y]) here also X=c and Y = b
so as both the functions act same in the second case you need to modify one of your cases.
for eg: for 2 vertices only you could use
path(X,Y,[X|Y|[]]):- edge(X,Y).
instead of
path(X,Y,[X,Y]):-
edge(X,Y).
it will expect only two variables and i think this should solve your problem.

Related

Prolog: lexicographic comparison and split a list

Given atom x, I am trying to split a list into one with atoms smaller than x and one with atoms equal to or greater than x.
For example)
%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) should give me
%% AtomSmall = [a,b,c], AtomBig = [d,e,f]
Below is what I've tried so far. I get the concept.However my code includes the atom that is equivalent to x in AtomSmall list, not AtomBig, although I check the case with before predicate.
For example)
%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) gives me
%% AtomSmall = [a,b,c,d], AtomBig = [e,f]
before(X,Y):-atom_codes(X,A),atom_codes(Y,B),small(A,B).
small([],[]).
small([H1|T1],[H2|T2]):-H1<H2.
small([H1|T1],[H2|T2]):-H1=:=H2,small(T1,T2).
split(X,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-before(H1,X),split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):-not(before(H1,X)),split(X,T1,Small,Big).
Please help!
In SWI-Prolog, you can use partition/4 from library(lists) and the standard order comparison (#>)/2:
?- lists:partition(#>(d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].
Since the order of arguments in comparison is fixed passing the pivot in as first argument, a lambda expression (using library(yall), needs a recent version) can help to give a more intuitive reading:
?- partition([E]>>(E#<d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].
Anyway, your code could be patched like this:
split(_,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-H1#<X,split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):- \+ H1#<X,split(X,T1,Small,Big).
?- split(d,[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f] ;
false.
Your before/2 predicate succeeds if the arguments are lexicographically equivalent. For example, before(a, a) is true. That's because your 3rd clause allows equal values throughout the list until the base case finally succeeds with two empty lists.
In addition, something you haven't encountered yet evidently, is that before(X, Y) will fail if X and Y are different length atoms. For example, before(ab, abc) will fail. So your small/2 needs to take care of that case as well.
A refactoring of small/2 will fix that:
% 1st clause is fixed so unequal length atoms are handled properly
small([], _).
small([H1|_], [H2|_]) :- H1 < H2.
% 3rd clause is fixed so that equal atoms won't succeed here
small([H,H1|T1], [H,H2|T2]) :- small([H1|T1], [H2|T2]).
But... you don't need to go through all that with before/2. Prolog knows how to compare, in a sensible way, atoms (and general Prolog terms) using the #< and #> operators, as #CapelliC indicated in his answer. So your before/2 just becomes:
before(X, Y) :- X #< Y.
And you don't need small/2 at all. That's basically the second solution that #CapelliC showed in his answer.

Prolog Rules in example

I have a database in Prolog like this:
connection(a,b,bus)
connection(b,c,metro)
connection(b,d,taxi)
connection(d,e,bus)
What I want is the rules I need to apply so I can ask the question: "transport(a,c)" and it answers: "bus" and "metro"
Is that possible to define 1 or 2 rules so that the query "transport(a,c)" works ?
you should see the database like:
connection(Departure,Arrive,Transport).
so that... connection(D,A,T).
then the rules are:
connection(D,A,T):- traject(D,A,T).
connection(D,A,T):- traject(D,X,T1), traject(X,A,T2).
where...traject(Departure, X, Transport1) and traject(X, Arrival, Transport2)
and the query should be something like:
transport(a,c,T1). and
transport(a,c,T2).
and then the answer should come:
T1 = bus
T2 = metro
I would try this:
transport(A, B, [Method]) :- connection(A, B, Method).
transport(A, C, [Method|Others]) :-
connection(A, B, Method),
transport(B, C, Others).
The base case here is that you have a direct connection. The inductive case is to find a connection and then recur from the intermediate. Note that you will get an infinite regress if you try using transport/3 twice in the body instead of connection/3 and then transport/3! Try it and see!
This seems to work for the inputs I expect:
?- transport(a, c, M).
M = [bus, metro] ;
false.
?- transport(a, d, M).
M = [bus, taxi] ;
false.
?- transport(a, e, M).
M = [bus, taxi, bus] ;
false.
Hope this helps!

Split a list in separate lists

I have to define some more constraints for my list.
I want to split my list is separate lists.
Example:
List=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]]
I need three Lists which i get from the main list:
[[_,0],[_,0],[_,0]] and [[_,0]] and [[2,0],[4,0]]
SO I always need a group of lists between a term with [X,1].
It would be great if u could give me a tip. Don’t want the solution, only a tip how to solve this.
Jörg
This implementation tries to preserve logical-purity without restricting the list items to be [_,_], like
#false's answer does.
I can see that imposing above restriction does make a lot of sense... still I would like to lift it---and attack the more general problem.
The following is based on if_/3, splitlistIf/3 and reified predicate, marker_truth/2.
marker_truth(M,T) reifies the "marker"-ness of M into the truth value T (true or false).
is_marker([_,1]). % non-reified
marker_truth([_,1],true). % reified: variant #1
marker_truth(Xs,false) :-
dif(Xs,[_,1]).
Easy enough! Let's try splitlistIf/3 and marker_truth/2 together in a query:
?- Ls=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]],
splitlistIf(marker_truth,Ls,Pss).
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [ [[_A,0],[_B,0],[_C,0]], [[_D,0]], [[2,0],[4,0]]] ? ; % OK
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [ [[_A,0],[_B,0],[_C,0]], [[_D,0],[9,1],[2,0],[4,0]]],
prolog:dif([9,1],[_E,1]) ? ; % BAD
%% query aborted (6 other BAD answers omitted)
D'oh!
The second answer shown above is certainly not what we wanted.
Clearly, splitlistIf/3 should have split Ls at that point,
as the goal is_marker([9,1]) succeeds. It didn't. Instead, we got an answer with a frozen dif/2 goal that will never be woken up, because it is waiting for the instantiation of the anonymous variable _E.
Guess who's to blame! The second clause of marker_truth/2:
marker_truth(Xs,false) :- dif(Xs,[_,1]). % BAD
What can we do about it? Use our own inequality predicate that doesn't freeze on a variable which will never be instantiated:
marker_truth(Xs,Truth) :- % variant #2
freeze(Xs, marker_truth__1(Xs,Truth)).
marker_truth__1(Xs,Truth) :-
( Xs = [_|Xs0]
-> freeze(Xs0, marker_truth__2(Xs0,Truth))
; Truth = false
).
marker_truth__2(Xs,Truth) :-
( Xs = [X|Xs0]
-> when((nonvar(X);nonvar(Xs0)), marker_truth__3(X,Xs0,Truth))
; Truth = false
).
marker_truth__3(X,Xs0,Truth) :- % X or Xs0 have become nonvar
( nonvar(X)
-> ( X == 1
-> freeze(Xs0,(Xs0 == [] -> Truth = true ; Truth = false))
; Truth = false
)
; Xs0 == []
-> freeze(X,(X == 1 -> Truth = true ; Truth = false))
; Truth = false
).
All this code, for expressing the safe logical negation of is_marker([_,1])? UGLY!
Let's see if it (at least) helped above query (the one which gave so many useless answers)!
?- Ls=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]],
splitlistIf(marker_truth,Ls,Pss).
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [[ [_A,0],[_B,0],[_C,0]], [[_D,0]], [[2,0],[4,0]]] ? ;
no
It works! When considering the coding effort required, however, it is clear that either a code generation scheme or a
variant of dif/2 (which shows above behaviour) will have to be devised.
Edit 2015-05-25
Above implementation marker_truth/2 somewhat works, but leaves a lot to be desired. Consider:
?- marker_truth(M,Truth). % most general use
freeze(M, marker_truth__1(M, Truth)).
This answer is not what we would like to get. To see why not, let's look at the answers of a comparable use of integer_truth/2:
?- integer_truth(I,Truth). % most general use
Truth = true, freeze(I, integer(I)) ;
Truth = false, freeze(I, \+integer(I)).
Two answers in the most general case---that's how a reified predicate should behave like!
Let's recode marker_truth/2 accordingly:
marker_truth(Xs,Truth) :- subsumes_term([_,1],Xs), !, Truth = true.
marker_truth(Xs,Truth) :- Xs \= [_,1], !, Truth = false.
marker_truth([_,1],true).
marker_truth(Xs ,false) :- nonMarker__1(Xs).
nonMarker__1(T) :- var(T), !, freeze(T,nonMarker__1(T)).
nonMarker__1(T) :- T = [_|Arg], !, nonMarker__2(Arg).
nonMarker__1(_).
nonMarker__2(T) :- var(T), !, freeze(T,nonMarker__2(T)).
nonMarker__2(T) :- T = [_|_], !, dif(T,[1]).
nonMarker__2(_).
Let's re-run above query with the new implementation of marker_truth/2:
?- marker_truth(M,Truth). % most general use
Truth = true, M = [_A,1] ;
Truth = false, freeze(M, nonMarker__1(M)).
It is not clear what you mean by a "group of lists". In your example you start with [1,1] which fits your criterion of [_,1]. So shouldn't there be an empty list in the beginning? Or maybe you meant that it all starts with such a marker?
And what if there are further markers around?
First you need to define the criterion for a marker element. This for both cases: When it applies and when it does not apply and thus this is an element in between.
marker([_,1]).
nonmarker([_,C]) :-
dif(1, C).
Note that with these predicates we imply that every element has to be [_,_]. You did not state it, but it does make sense.
split(Xs, As, Bs, Cs) :-
phrase(three_seqs(As, Bs, Cs), Xs).
marker -->
[E],
{marker(E)}.
three_seqs(As, Bs, Cs) -->
marker,
all_seq(nonmarker, As),
marker,
all_seq(nonmarker, Bs),
marker,
all_seq(nonmarker, Cs).
For a definition of all_seq//2 see this
In place of marker, one could write all_seq(marker,[_])
You can use a predicate like append/3. For example, to split a list on the first occurence of the atom x in it, you would say:
?- L = [a,b,c,d,x,e,f,g,x,h,i,j], once(append(Before, [x|After], L)).
L = [a, b, c, d, x, e, f, g, x|...],
Before = [a, b, c, d],
After = [e, f, g, x, h, i, j].
As #false has pointed out, putting an extra requirement might change your result, but this is what is nice about using append/3:
"Split the list on x so that the second part starts with h:
?- L = [a,b,c,d,x,e,f,g,x,h,i,j], After = [h|_], append(Before, [x|After], L).
L = [a, b, c, d, x, e, f, g, x|...],
After = [h, i, j],
Before = [a, b, c, d, x, e, f, g].
This is just the tip.

Relying on rule order

To calculate the hamming distance between two lists of the same length, I use foldl(hamm, A, B, 0, R). with this definition of hamm/4:
hamm(A, A, V, V) :- !.
hamm(A, B, V0, V1) :- A \= B, V1 is V0 + 1.
The cut in the first rule prevents the unnecessary backtracking. The second rule, however, could have been written differently:
hamm2(A, A, V, V) :- !.
hamm2(_, _, V0, V1) :- V1 is V0 + 1.
and hamm2/4 will still be correct together with foldl/5 or for queries where both A and B are ground.
So is there a really good reason to prefer the one over the other? Or is there a reason to keep the rules in that order or switch them around?
I know that the query
hamm(a, B, 0, 1).
is false, while
hamm2(a, B, 0, 1).
is true, but I can't quite decide which one makes more sense . . .
The OP implemented two accumulator-style predicates for calculating the Hamming distance (hamm/4 and hamm2/4), but wasn't sure which one made more sense.
Let's read the query that puzzled the OP: "Is there an X such that distance(a,X) is 1?". Here are the "answers" Prolog gives:
?- hamm(a,X,0,1).
false. % wrong: should succeed conditionally
?- hamm2(a,X,0,1). % wrong: should succeed, but not unconditionally
true.
From a logical perspective, both implementations misbehave in above test. Let's do a few tests for steadfastness:
?- hamm(a,X,0,1),X=a. % right
false.
?- hamm(a,X,0,1),X=b. % wrong: should succeed as distance(a,b) is 1
false.
?- hamm2(a,X,0,1),X=a. % wrong: should fail as distance(a,a) is 0
X = a.
?- hamm2(a,X,0,1),X=b. % right
X = b.
Note that in previous queries hamm/4 rightly fails when hamm2/4 wrongly succeeded, and vice-versa.
So both are half-right/half-wrong, and neither one
is steadfast.
What can be done?
Based on if_/3 and (=)/3 presented by #false in this answer, I implemented the following pure code for predicate hamm3/4:
:- use_module(library(clpfd)).
hamm3(A,B,V0,V) :-
if_(A = B, V0 = V, V #= V0+1).
Now let's repeat above queries using hamm3/4:
?- hamm3(a,X,0,1).
dif(X,a).
?- hamm3(a,X,0,1),X=a.
false.
?- hamm3(a,X,0,1),X=b.
X = b.
It works! Finally, let's ask the most general query to see the entire solution set of hamm3/4:
?- hamm3(A,B,N0,N).
A = B, N0 = N ;
dif(A,B), N0+1 #= N.
You already spotted the differences between those definitions: efficiency apart, you should decide about your requirements. Are you going to accept variables in your data structures? Such programming style introduces some of advanced Prolog features (incomplete data structures).
Anyway, I think the first form is more accurate (not really sure about, I would say steadfast on 4° argument)
?- hamm(a, B, 0, 1).
false.
?- hamm(a, B, 0, 0).
B = a.
while hamm2 is
?- hamm2(a, B, 0, 1).
true.
?- hamm2(a, B, 0, 0).
B = a.

Passing the Results of a Prolog Predicate

How does one evaluate the result of a prolog predicate to pass as an argument?
I am trying to write code to reverse pairs of elements in a list:
swap([A,B,C,D,E,F],R).
I want the result:
[B,A,D,C,F,E]
but I get this result:
append(append(append([],[B,A],[D,C],[F,E])))
Here is my code:
swap(L,R) :- swapA(L,[],R).
swapA([],A,A).
swapA([H,H2|T],A,R) :- swapA(T, append(A,[H2,H]), R).
Thanks.
Several things:
a variable starts with a capital letter, if you want to differenciate an atom from a variable, wrap it between ': ['A','B','C','D','E','F']
you do not need append to successfully implement this predicate. The complexity is way worse when using append.
because you do not need append, you do not need 3 arguments either, 2 suffice
Here is a suggestion:
swapA([], []).
swapA([X, Y|T], [Y, X|R]) :- swapA(T, R).
And consider adding another base case if you want your predicate to hold when you have an odd number of elements in your list:
swapA([X], [X]).
You can't call a Prolog predicate like a function. It doesn't return anything. When you pass append(A,[H2,H]) to swap, it interprets it as data, not as code.
A Prolog clause creates a relation between N logic variables. That means in theory there is no concept of "input" and "output" in Prolog predicates, you can make a query with any combination of instantiated and non-instantiated variables, and the language will find the meaningful relation(s) for you:
1 ?- append([a],[b,c],[a,b,c]).
true.
2 ?- append([a],[b,c],Z).
Z = [a, b, c].
3 ?- append([a],Y,[a,b,c]).
Y = [b, c].
4 ?- append(X,[b,c],[a,b,c]).
X = [a] ;
false.
5 ?- append([a],Y,Z).
Z = [a|Y].
6 ?- append(X,[b,c],Z).
X = [],
Z = [b, c] ;
X = [_G383],
Z = [_G383, b, c] ;
X = [_G383, _G389],
Z = [_G383, _G389, b, c] . % etc
7 ?- append(X,Y,[a,b,c]).
X = [],
Y = [a, b, c] ;
X = [a],
Y = [b, c] ;
X = [a, b],
Y = [c] ;
X = [a, b, c],
Y = [] ;
false.
8 ?- append(X,Y,Z).
X = [],
Y = Z ;
X = [_G362],
Z = [_G362|Y] ;
X = [_G362, _G368],
Z = [_G362, _G368|Y] . % etc
9 ?-
In practice, not every predicate can be called with every combination, due to limitations in expressing the relation in a way that will not yield an infinite loop. Other cause may be extra-logic features, like arithmetic. When you see a predicate documented like:
pred(+Foo, -Bar, ?Baz)
That means it expects Foo to be instantiated (i.e. unified to another non-var), Bar to be a free variable and Baz can be anything. The same predicate can have more than one way to call it, too.
This is the reason you can't treat a Prolog relation as a function, in general. If you pass a compound as argument, the clauses will likely treat it just as a compound, unless it is specifically designed to handle it as code. One example is call/1, which executes its argument as code. is, =:=, < and other arithmetic operators do some interpretation too, in case you pass something like cos(X).

Resources