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.
Related
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(..., ...)].
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!
Consider the following simple program:
h(n0).
h(p(A,N)) :- (A=a, h(N)) ; (A=b , h(N)).
Query:
1 ?- h(p(A,N)).
A = a,
N = n0 ;
A = a,
N = p(a, n0) ;
A = a,
N = p(a, p(a, n0)) ;
A = a,
N = p(a, p(a, p(a, n0))) ;
A = a,
N = p(a, p(a, p(a, p(a, n0)))) ;
...
Since the first disjunct [(A=a, h(N))] produces infinite number of answers it cannot show the answers produced by the second disjunct [(A=b , h(N))].
The question is:
Is it possible to change the code so that on the query, it alternates between the solutions from the first disjunct and the second one?
To get a fair listing of the results of h/1 you can use an auxiliary predicate, say h2/2 that consists of two goals: 1) A predicate pairs/1 that is only describing the the structure of your solution without concrete values:
pairs(n0).
pairs(p(A,N)) :-
pairs(N).
And yields the following answers:
?- pairs(X).
X = n0 ? ;
X = p(_A,n0) ? ;
X = p(_A,p(_B,n0)) ? ;
X = p(_A,p(_B,p(_C,n0))) ?
...
2) Your predicate h/1 as the second goal that describes what the variables _A, _B, _C,... actually are:
h2(X) :-
pairs(X),
h(X).
If you query this predicate you get the desired results:
?- h2(X).
X = n0 ? ;
X = p(a,n0) ? ;
X = p(b,n0) ? ;
X = p(a,p(a,n0)) ? ;
X = p(a,p(b,n0)) ? ;
X = p(b,p(a,n0)) ? ;
X = p(b,p(b,n0)) ? ;
X = p(a,p(a,p(a,n0))) ? ;
...
Note, how the first goal pairs/2 is producing your nested pair-structure one pair at a time. Then the second goal, your original predicate, is producing all possible combinations of a's and b's for that very pair. Then h/2 is backtracking to the next pair produced by pairs/2. And so on.
I cannot figure out why the following query from the given Prolog code generates the error Out of local stack.
Prolog code:
likes(g,c).
likes(c,a).
likes(c,b).
likes(b,a).
likes(b,d).
likes(X,Z) :- likes(X,Y), likes(Y,Z).
the query
?- likes(g,X).
results in
X = c ;
X = a ;
X = b ;
ERROR: Out of local stack
Edit 1 This is the way I think that Prolog should deal with this query,
likes(g,c) is a fact, so X={c}
likes(g,b) <= likes(g,c) and likes(c,b), so X={c,b}
likes(g,a) <= likes(g,b) and likes(b,a), so X={c,b,a}
likes(g,d) <= likes(g,b) and likes(b,d), so X={c,b,a,d}
likes(g,a) and false, so nothing to add to X
likes(g,d) and false, so nothing to add to X
end of backtracking search.
Edit 2 I managed to get what I was looking for by the following modification of the code:
likes(g,c).
likes(c,a).
likes(c,b).
likes(b,a).
likes(b,d).
indirect_likes(A,B):- likes(A,B).
indirect_likes(A,C):- likes(B,C), indirect_likes(A,B).
the query
?- indirect_likes(g,Which).
results in
Which = c ;
Which = a ;
Which = b ;
Which = a ;
Which = d ;
false.
However, there is still something which I cannot figure out the rationale behind. If I change the last rule to be
indirect_likes(A,C):- indirect_likes(A,B), likes(B,C).
Then I get ERROR: Out of local stack! As far as I know, logical conjunction is commutative.
To get the transitive-closure of binary relation R_2, use meta-predicate closure/3 like so:
?- closure(R_2,From,To).
Let's run a sample query of closure/3 together with likes/2!
?- closure(likes,X,Y).
X = g, Y = c
; X = g, Y = a
; X = g, Y = b
; X = g, Y = a % redundant
; X = g, Y = d
; X = c, Y = a
; X = c, Y = b
; X = c, Y = a % redundant
; X = c, Y = d
; X = b, Y = a
; X = b, Y = d
; false. % query terminates universally
We get the same answers when we use indirect_likes/2, but in a different order:
?- indirect_likes(X,Y).
X = g, Y = c
; X = c, Y = a
; X = c, Y = b
; X = b, Y = a
; X = b, Y = d
; X = g, Y = a
; X = g, Y = b
; X = c, Y = a % redundant
; X = g, Y = a % redundant
; X = c, Y = d
; X = g, Y = d
; false. % query terminates universally
As you stated in your comments to #C.B.'s answer, binary relations are not necessarily reflexive and/or symmetric. With the definition you gave, likes/2 is neither:
?- likes(X,X).
false. % not reflexive (not even close)
?- likes(X,Y), likes(Y,X).
false. % not symmetric (not even close)
So far, so good!
Let's tentatively add the following additional fact to your database:
likes(b,b).
With this expanded definition, indirect_likes/2 behaves erratically:
?- indirect_likes(b,b).
true
; true
; true
... % does not terminate universally
?- indirect_likes(X,Y), false. % do we get finite failure?
... % no! query does not terminate universally
What can we do? Let's use meta-predicate closure/3 with the expanded version of likes/2!
?- closure(likes,b,b).
true % succeeds non-deterministically
; false. % query terminates universally
?- closure(likes,X,Y), false. % do we get finite failure?
false. % yes! query terminates universally
The bottom line?
In pure Prolog, conjunction is commutative, as far as the logical meaning is concerned.
Due to Prolog's SLD resolution, the goal false,repeat finitely fails, but repeat,false does not.
The programmer needs to take care of termination, but usually this is a small price to pay for the raw performance and control that Prolog offers.
In this answer I passed "termination worries" on to the implementor of meta-predicate closure/3 :)
You spin off into infinite recursion.
Once you get to likes(b,a), you call likes(a,_G4382), which has no fact defined so it switches to the rule likes(X,Z) :- likes(X,Y), likes(Y,Z). So it calls likes(a,_G4383) which calls likes(X,Z) :- likes(X,Y), likes(Y,Z). over and over and over.
You might want to define and auxillary predicate aux_likes/2 that hosts all your facts. This will only work if there are no circular relationships, i.e. aux_likes(b,c) and aux_likes(c,b). You would also need to define likes(X,X). This is essentially a graph problem and in graph theory a node has to be connected to itself. If you use it as a generator, it will go off into into infinite recursion (if you have cycles) unless you add cuts which are not ideal.
If using swi-prolog, feel free to enter the debug or spy query to see what's going on.
Code:
aux_likes(g,c).
aux_likes(c,a).
aux_likes(c,b).
aux_likes(b,a).
aux_likes(b,d).
likes(X,Z) :- aux_likes(X,Y), likes(Y,Z).
likes(X,X).
Output with new predicate:
?- likes(g,X),print(X),nl,fail.
a
a
d
b
c
g
false.
This says g can like a through c or through b. It likes d through b, it likes b through c and it likes c directly. It also must like itself inorder to query like this. If you would rather have the usage mode (+,+) meaning you supply it with both terms and no variables (as a checker) you can do
?- likes(g,c).
true .
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.