Prolog definition which detects a path - prolog

Context, first. I have the following bi-directional graph.
Represented in Prolog like this:
relation(a,c).
relation(b,d).
relation(c,d).
relation(d,e).
relation(e,f).
connection(X,Y) :- relation(X,Y).
connection(X,Y) :- relation(Y,X).
So I have the relation between the nodes, and then the connections between the nodes related, as I said before, in both directions.
What I am looking to do is a prolog definition path(X,Y) capable to tell if there's a path in the graph between two nodes (giving true if, at least, one path exists between both nodes, and false if there's no existing paths between both nodes).
So, the goal output in this model should look like this:
?- path(a,d).
true.
?- path(b,a).
true.
?- path(f,b).
true
? path(a,g). % The node g doesn't exist
false.
I know this involves using a visited list, and I had seen examples of this, but giving all the posible paths between two nodes. However, this isn't what I'm looking for. What I'm looking is a definition which detects if there is a path between two nodes, not to give all the posible paths between two nodes.
Edit: So, thanks to #mbratch, I can now adapt the suggested problem to a solution:
relation(a,c).
relation(b,d).
relation(c,d).
relation(d,e).
relation(e,f).
connection(X,Y) :- relation(X,Y).
connection(X,Y) :- relation(Y,X).
path_exists(X,Y) :- path(X,Y,_), !.
path(A,B,Path) :-
travel(A,B,[A],Q),
reverse(Q,Path).
travel(A,B,P,[B|P]) :-
connection(A,B).
travel(A,B,Visited,Path) :-
connection(A,C),
C \== B,
\+member(C,Visited),
travel(C,B,[C|Visited],Path).

What you want to get is commonly called "transitive closure of a binary relation".
We can obtain the transitive-closure of connection/2 by using meta-predicate closure/3 like this:
% Q: Which `To` can be reached via `connection` starting at `From`?
?- closure(connection,From,To).
First, let's run the queries the OP gave:
?- closure(connection,a,d).
true % OK: succeeds non-deterministically
; false.
?- closure(connection,b,a).
true % OK: succeeds non-deterministically
; false.
?- closure(connection,f,b).
true % OK: succeeds non-deterministically
; false.
?- closure(connection,a,g).
false. % OK: finitely fails
Let's ask the most general query!
?- closure(connection,X,Y).
X = a, Y = c
; X = a, Y = d
; X = a, Y = e
; X = a, Y = f
; X = a, Y = b
; X = b, Y = d
; X = b, Y = e
; X = b, Y = f
; X = b, Y = c
; X = b, Y = a
; X = c, Y = d
; X = c, Y = e
; X = c, Y = f
; X = c, Y = b
; X = d, Y = e
; X = d, Y = f
; X = e, Y = f
; X = c, Y = a
; X = d, Y = b
; X = d, Y = c
; X = d, Y = a
; X = e, Y = d
; X = e, Y = b
; X = e, Y = c
; X = e, Y = a
; X = f, Y = e
; X = f, Y = d
; X = f, Y = b
; X = f, Y = c
; X = f, Y = a
false.

Related

Grounding in Prolog given a predicate and a list

Given a predicate and a list I want a list of all the possible ways of grounding. For example:
gounding(predicate(X), [a,b,c], Grounded).
Should return
[predicate(a), predicate(b), predicate(c)]
And I would also like it to work with more than one variable, for example:
grounding(predicate(X,Y), [a,b,c], Grounded).
Grounded = [predicate(a,a), predicate(a,b), predicate(a,c), predicate(b,a), predicate(b,b), predicate(b,c), predicate(c,a), predicate(c,b), predicate(c,c)]
The problem is given by the fact that the predicate is not always the same, so it needs to be passed as a variable. Like:
grounding(Predicate, Arity, [a,b,c], Grounded).
Is there something that already does this or should it be done manually?
I tried using atom_concat with the name of the predicate, the brackets and the elements of the list, but it returns the list with quotes like:
['predicate(a)', 'predicate(b)', 'predicate(c)']
Let's start with a simpler problem: Given a list of variables and a list of ground values, assign those ground values to the variables. For example:
?- variables_values([X], [a, b, c]).
X = a ;
X = b ;
X = c.
This can be implemented like this:
variables_values([], _Values).
variables_values([Variable | Variables], Values) :-
member(Variable, Values),
variables_values(Variables, Values).
A bigger example:
?- variables_values([X, Y], [a, b, c]).
X = Y, Y = a ;
X = a,
Y = b ;
X = a,
Y = c ;
X = b,
Y = a ;
X = Y, Y = b ;
X = b,
Y = c ;
X = c,
Y = a ;
X = c,
Y = b ;
X = Y, Y = c.
The term_variables/2 predicate gives you a list of all the variables in a term. You can combine this with the above predicate:
?- Pattern = predicate(X, Y), term_variables(Pattern, Variables), variables_values(Variables, [a, b, c]).
Pattern = predicate(a, a),
X = Y, Y = a,
Variables = [a, a] ;
Pattern = predicate(a, b),
X = a,
Y = b,
Variables = [a, b] ;
Pattern = predicate(a, c),
X = a,
Y = c,
Variables = [a, c] ;
Pattern = predicate(b, a),
X = b,
Y = a,
Variables = [b, a] . % etc.
Note that instantiating the variables in the list also instantiates them in the pattern -- the variables are shared.
Given this, the last piece of the puzzle is a predicate that computes a list of instantiations of a pattern, given some predicate that instantiates variables. findall/3 is the right tool for this job:
pattern_values_grounded(Pattern, Values, Grounded) :-
term_variables(Pattern, Variables),
findall(Pattern, variables_values(Variables, Values), Grounded).
This does what you seem to want:
?- pattern_values_grounded(predicate(X), [a, b, c], Grounded).
Grounded = [predicate(a), predicate(b), predicate(c)].
?- pattern_values_grounded(predicate(X, Y), [a, b, c], Grounded).
Grounded = [predicate(a, a), predicate(a, b), predicate(a, c), predicate(b, a), predicate(b, b), predicate(b, c), predicate(c, a), predicate(c, b), predicate(..., ...)].

GProlog reachable elements in a graph

I have an easy problem that I'm having trouble with although I think the answer is quite easy.
Here it goes:
Assume a weighted
directed graph is described by means of a
predicate edge/3, such that edge(X,Y,C)
is true is there is an edge from vertex X to
vertex Y of cost C. For instance, to the right
is a graph and its description using edge/3:
edge(a, c,1).
edge(a,d,3).
edge(b,d,2).
edge(c,e,5).
edge(e, c,2).
edge(e,f,2).
edge(d,f,10).
I have to . Define a predicate reachable/2 that computes the list of nodes that can be reached
from a given node. For instance, to the query reachable(a, L) Prolog should answer L=[c,e,d,f]
(in any order). (Remember findall.)
Here is what I wrote for the moment
path(X,Y):-edge(X,Y,_).
path(X,Y):-edge(X,Z,_),path(Z,Y).
reachable(X,L):-findall(Y,path(X,Y),L).
I can't see what is wrong but it's going in circles and stopping because of a memory issue.
Any ideas how to solve that?
Please that would creatly help!
If your graph has an edge, like c → e → c → e → …, then there is nothing that stops path from each time walking from e to c and back. Unless we add something to prevent this.
We can make use of a list that contains all the elements already visited, and prevent from visiting these another time:
path(X, Y) :-
path(X, Y, [X]).
path(X, Y, V) :-
edge(X, Y, _),
\+ member(Y, V).
path(X, Y, V) :-
edge(X,Z,_),
\+ member(Z, V),
path(Z, Y, [Z|V]).
we thus start with a list that contains only X. Each time when we take an edge, we check if the target (Y or Z) is not a member of V, and in case of recursion, we add Z to the list.
For the given graph:
this thus produces:
?- path(X, Y).
X = a,
Y = c ;
X = a,
Y = d ;
X = b,
Y = d ;
X = c,
Y = e ;
X = e,
Y = c ;
X = e,
Y = f ;
X = d,
Y = f ;
X = a,
Y = e ;
X = a,
Y = f ;
X = a,
Y = f ;
X = b,
Y = f ;
X = c,
Y = f ;
false.

define a predicate solution/3 which is true when its three arguments, all lists, has the third list containing all elements of the first two arguments

solution([ ], List, List).
solution([Head|Tail], List,[Head|Result]):-
solution(Tail, List,Result).
expected output
| ?- Solution(X,Y,[a,b,c]).
X = [a,b,c]
Y = [] ? ;
X = [a,b]
Y = [c] ? ;
X = [a,c]
Y = [b] ? ;
X = [a]
Y = [b,c] ? ;
X = [b,c]
Y = [a] ? ;
X = [b]
Y = [a,c] ? ;
X = [c]
Y = [a,b] ? ;
X = []
Y = [a,b,c] ? ;
actual output
X = []
Y = [a,b,c] ? ;
X = [a]
Y = [b,c] ? ;
X = [a,b]
Y = [c] ? ;
X = [a,b,c]
Y = [] ? ;
It is not going through all the possible solutions that can be made from the predicate defined. i am expecting the output to be as shown above containing all the solutions of combining 2 lists together
Any help?
Your predicate is missing some clauses. The first clause says that if the first list is exhausted, then the result is the second list.
The second clause specifies that if the first list is not exhausted, we simply take the first element of that list as a result. This thus means that you basically implemented an append/3 predicate [swi-doc].
Based on your sample output, there is however a decision whether to take from the first list, or the second list. We thus should implement a clause like:
solution([H1|T1], L2, [H1|R]) :-
solution(T1, L2, R).
solution(L1, [H1|T2], [H1|R]) :-
solution(L1, T2, R).
If both lists are exhausted, we can return an empty list, so we can define a base-clause like:
solution([], [], []).
and thus obtain as full solution:
solution([], [], []).
solution([H1|T1], L2, [H1|R]) :-
solution(T1, L2, R).
solution(L1, [H1|T2], [H1|R]) :-
solution(L1, T2, R).
This then gives us:
?- solution(X,Y,[a,b,c]).
X = [a, b, c],
Y = [] ;
X = [a, b],
Y = [c] ;
X = [a, c],
Y = [b] ;
X = [a],
Y = [b, c] ;
X = [b, c],
Y = [a] ;
X = [b],
Y = [a, c] ;
X = [c],
Y = [a, b] ;
X = [],
Y = [a, b, c].

In Prolog, can solutions be chosen in random order?

If I have the following:
a(X) :- X = 1; X = 2; X = 3; X = 4.
I can produce solutions in deterministic order:
?- a(X).
X = 1 ;
X = 2 ;
X = 3 ;
X = 4.
Is there any method of asking the system to produce solutions in non-deterministic, random order? For example:
?- a(X).
X = 4 ;
X = 1 ;
X = 3 ;
X = 2.
I'm aware that I can find all solutions then select one at random (findall(X, a(X), Y), random_member(Z, Y).) but this is too expensive in my case.
Possibly clearer example:
p(X,Y,Z) :-
(X = a; X = b; X = c; X = d), % (D1)
(Y = a; Y = b; Y = c), % (D2)
(Z = a; Z = b; Z = c; Z = d). % (D3)
When deterministic, generating the solution X = d, Y = c, Z = d using ?- p(X,Y,Z). will always go through the 47 previous solutions (4 * 3 * 4 = 48). However, if disjunctions are selected in non-deterministic order, the system might choose X = d at D1, Y = c at D2, Z = d at D3, generating it as the first solution.
This is being used for constrained AI-generated content, so there are many more variables in the real-world use-case.
From what you say in the comments, my impression is that a more important question for your use case is:
Can solutions be created in random order?
(This is because you say that you cannot create them all, and then choose a random one.)
To create them in a different order, Boris has hinted at a good way: Simply reorder the disjunctions!
For example, in the case you show:
p(X, Y, Z) :-
(X = a; X = b; X = c; X = d), % (D1)
(Y = a; Y = b; Y = c), % (D2)
(Z = a; Z = b; Z = c; Z = d). % (D3)
You could (automatically) create such declaratively equivalent versions of this snippet by exchanging the order if the disjunctions, such as: (X = c ; X = b ; etc.), and each of these snippets may yield the solutions in a different order.
However, it may be easier to first rewrite this to the equivalent version:
p(X, Y, Z) :-
member(X, [a,b,c,d]),
member(Y, [a,b,c]),
member(Z, [a,b,c,d]).
This way, it is easier to shuffle the lists and use the randomized lists to generate solutions.
For example, you can change this to:
p(X, Y, Z) :-
random_member(X, [a,b,c,d]),
random_member(Y, [a,b,c]),
random_member(Z, [a,b,c,d]).
random_member(X, Ls0) :-
random_permutation(Ls0, Ls),
member(X, Ls).
Now, you will get answers like:
?- p(X, Y, Z).
X = d,
Y = Z, Z = b ;
X = Z, Z = d,
Y = b ;
X = d,
Y = b,
Z = c ;
etc.
Note that this way to incorporate randomness to your code is impure: There is now implicit global state in your program, and you can no longer easily reproduce results that you need when describing test cases etc. for such programs. A solution preserving logical-purity has to make this state explicit, for example by carrying the random seed as one of the arguments, so that each run is completely reproducible.
Note that reordering conjunctions and/or goals like this works only for the pure and monotonic subset of Prolog, so make sure that you use declarative features like constraints to safely exchange goals, and to increase the generality of your code!

Learning prolog, some list functions

I am working on an assignment that deals with lists in prolog. The basic idea is that given a list, prolog should be able to determine if a value is repeated at all, repeated only once, or repeated only twice, etc. I thought the simplest solution would be to count the number of times a value occurs and then use that count to determine how many times it is repeated.
list_count([],X,0).
list_count([X|T],X,Y) :- list_count(T,X,Z), Y is 1 + Z.
list_count([X1|T],X,Z) :- X1 \= X, list_count(T,X,Z).
repeated_in(+E,+List) :- list_count(List,E,Num), Num >= 2.
No matter what I do though my first predicate always fails. Help?
list_count/3 does work. I think the only issue is the improper usage of prefix '+': try
% repeated_in(+E,+List)
repeated_in(E,List):- list_count(List,E,Num), Num >= 2.
note: prefixing arguments is used for documentation purpose, as a recap about mode usage
Here a logically pure implementation, based on
if_/3 and (=)/3 by #false.
atLeastOnceMember_of(E,[X|Xs]) :-
if_(E = X, true, atLeastOnceMember_of(E,Xs)).
atLeastTwiceMember_of(E,[X|Xs]) :-
if_(E = X, atLeastOnceMember_of(E,Xs), atLeastTwiceMember_of(E,Xs)).
First, let's look at the queries you suggested in your question:
?- atLeastTwiceMember_of(a,[a,b,a,b,a,c]).
true. % succeeds deterministically
?- atLeastTwiceMember_of(b,[a,b,a,b,a,c]).
true. % succeeds deterministically
?- atLeastTwiceMember_of(c,[a,b,a,b,a,c]).
false.
?- atLeastTwiceMember_of(x,[a,b,a,b,a,c]).
false.
The code is monotone, so we get logically sound answers for more general uses, too!
?- atLeastTwiceMember_of(X,[a,b,a,b,a,c]).
X = a ;
X = b ;
false.
At last, let us consider a generalization of above query:
?- atLeastTwiceMember_of(X,[A,B,C,D,E,F]).
X = A, A = B ;
X = A, A = C, dif(C,B) ;
X = A, A = D, dif(D,C), dif(D,B) ;
X = A, A = E, dif(E,D), dif(E,C), dif(E,B) ;
X = A, A = F, dif(F,E), dif(F,D), dif(F,C), dif(F,B) ;
X = B, B = C, dif(C,A) ;
X = B, B = D, dif(D,C), dif(D,A) ;
X = B, B = E, dif(E,D), dif(E,C), dif(E,A) ;
X = B, B = F, dif(F,E), dif(F,D), dif(F,C), dif(F,A) ;
X = C, C = D, dif(D,B), dif(D,A) ;
X = C, C = E, dif(E,D), dif(E,B), dif(E,A) ;
X = C, C = F, dif(F,E), dif(F,D), dif(F,B), dif(F,A) ;
X = D, D = E, dif(E,C), dif(E,B), dif(E,A) ;
X = D, D = F, dif(F,E), dif(F,C), dif(F,B), dif(F,A) ;
X = E, E = F, dif(F,D), dif(F,C), dif(F,B), dif(F,A) ;
false.

Resources