How to find kth generation of a family tree in Prolog? - prolog

I am trying to find a list of all the family members for the kth generation of a given family. We are given the first members of the family and the family tree as well. Below is my KB for the same and also the implementation. I am not able to figure how I can get the kth generation for this family tree? Lets say k = 4. One way of doing it is that I can find 4 times the relation like this:
4thGen(X,Y) :- parent(X,A),parent(A,B),parent(B,C),parent(C,Y)
but this is not the correct way for this I believe.
male(alex).
male(romeo).
male(oscar).
male(peter).
male(bruno).
male(georg).
male(otto).
male(pascal).
male(jean).
female(lina).
female(julia).
female(rosa).
female(eva).
female(ruth).
female(silvia).
female(ida).
female(irma).
female(olga).
female(marie).
female(tina).
parent(alex,julia).
parent(alex,rosa).
parent(lina,julia).
parent(lina,rosa).
parent(romeo,peter).
parent(julia,peter).
parent(rosa,silvia).
parent(oscar,ida).
parent(eva,ida).
parent(eva,bruno).
parent(peter,bruno).
parent(peter,georg).
parent(peter,irma).
parent(ruth,georg).
parent(ruth,irma).
parent(silvia,otto).
parent(silvia,pascal).
parent(irma,olga).
parent(irma,jean).
parent(otto,olga).
parent(otto,jean).
parent(jean,tina).
parent(marie,tina).
father(X,Y):-parent(X,Y),male(X).
grandfather(X,Y):-father(X,Z),parent(Z,Y).

In order to make more general predicates you can use recursion:
kthGen(X,Y,1):-parent(X,Y).
kthGen(X,Y,K) :- parent(X,A),K1 is K-1,kthGen(A,Y,K1).
Here are some queries:
?- kthGen(alex,julia,1).
true ;
false.
?- kthGen(alex,peter,2).
true ;
false.
?- kthGen(alex,bruno,2).
false.
?- kthGen(alex,bruno,3).
true ;
false.
Two important things to notice here:
Firstly your graph is directed (e.g if parent(A,B) you can't have parent(B,A) ), this matters because if it was undirected you could fall into cycles (e.g kthGen(alex,julia,4). would succeed due to the path alex->julia->alex->julia ,you could solve that by adding another list that keeps track persons you've visited).
Secondly if you try:
?- kthGen(alex,bruno,K).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [8] kthGen(alex,bruno,_7630)
ERROR: [7] <user>
So the predicate kthGen/3 does not have relational behavior. You could use library CLPFD:
:- use_module(library(clpfd)).
kthGen(X,Y,1):-parent(X,Y).
kthGen(X,Y,K) :- parent(X,A),K1 #= K-1,kthGen(A,Y,K1).
Now if you try:
?- kthGen(alex,bruno,K).
K = 3 ;
false
much better !!.
UPDATE
In order to find kth generation persons from a person X you could modify accordingly:
:- use_module(library(clpfd)).
kthGen(Y,1,[Y]).
kthGen(X,K,[X|T]) :- parent(X,A),K1 #= K-1,kthGen(A,K1,T).
Example:
?- kthGen(alex,4,L).
L = [alex, julia, peter, bruno] ;
L = [alex, julia, peter, georg] ;
L = [alex, julia, peter, irma] ;
L = [alex, rosa, silvia, otto] ;
L = [alex, rosa, silvia, pascal] ;
false.
This gives all the possible 4th generations from alex. If you want to find more complex e.g 4th gen from alex or lina you could find it separately an write another predicate that concatenates the results...
UPDATE 2
In last update I keep track of all persons until 4th generation. If you want just 4th gen simply modify like:
kthGen(Y,1,[Y]).
kthGen(X,K,L) :- parent(X,A),K1 #= K-1,kthGen(A,K1,L).
Examlpe:
?- kthGen(alex,4,L).
L = [bruno] ;
L = [georg] ;
L = [irma] ;
L = [otto] ;
L = [pascal] ;
false.
Now if you want all results in one list:
?- findall(X,kthGen(alex,4,[X]),L).
L = [bruno, georg, irma, otto, pascal].

Related

CLPFD ins operator yields not sufficiently instantiated error

So, my goal is to make a map colourer in Prolog. Here's the map I'm using:
And this are my colouring constraints:
colouring([A,B,C,D,E,F]) :-
maplist( #\=(A), [B,C,D,E] ),
maplist( #\=(B), [C,D,F]),
C #\= D,
maplist( #\=(D), [E,F]),
E #\= F.
Where [A,B,C,D,E,F] is a list of numbers(colors) from 1 to n.
So I want my solver to, given a List of 6 colors and a natural number N, determine the colors and N constraints both ways, in a way that even the most general query could yield results:
regions_ncolors(L,N) :- colouring(L), L ins 1..N, label(L).
Where the most general query is regions_ncolors(L,N).
However, the operator ins doesn't seem to accept a variable N, it instead yields an argument not sufficiently instantiated error. I've tried using this solution instead:
int_cset_(N,Acc,Acc) :- N #= 0.
int_cset_(N,Acc,Cs) :- N_1 #= N-1, int_cset_(N_1,[N|Acc],Cs).
int_cset(N,Cs) :- int_cset_(N,[],Cs).
% most general solver
regions_ncolors(L,N) :- colouring(L), int_cset(N,Cs), subset(L,Cs), label(L).
Where the arguments in int_cset(N,Cs) is a natural number(N) and the counting set Sn = {1,2,...,N}
But this solution is buggy as regions_ncolors(L,N). only returns the same(one) solution for all N, and when I try to add a constraint to N, it goes in an infinite loop.
So what can I do to make the most general query work both ways(for not-instantiated variables)?
Thanks in advance!
Btw, I added a swi-prolog tag in my last post although it was removed by moderation. I don't know if this question is specific to swi-prolog which is why I'm keeping the tag, just in case :)
Your colouring is too specific, you encode the topology of your map into it. Not a problem as is, but it defeats of the purpose of then having a "most general query" solution for just any list.
If you want to avoid the problem of having a free variable instead of a list, you could first instantiate the list with length/2. Compare:
?- L ins 1..3.
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [16] throw(error(instantiation_error,_86828))
ERROR: [10] clpfd:(_86858 ins 1..3) ...
Is that the same problem as you see?
If you first make a list and a corresponding set:
?- length(L, N), L ins 1..N.
L = [],
N = 0 ;
L = [1],
N = 1 ;
L = [_A, _B],
N = 2,
_A in 1..2,
_B in 1..2 ;
L = [_A, _B, _C],
N = 3,
_A in 1..3,
_B in 1..3,
_C in 1..3 .
If you use length/2 like this you will enumerate the possible lists and integer sets completely outside of the CLP(FD) labeling. You can then add more constraints on the variables on the list and if necessary, use labeling.
Does that help you get any further with your problem? I am not sure how it helps for the colouring problem. You would need a different representation of the map topology so that you don't have to manually define it within a predicate like your colouring/1 you have in your question.
There are several issues in your program.
subset/2 is impure
SWI's (by default) built-in predicate subset/2 is not the pure relation you are hoping for. Instead, it expects that both arguments are already sufficiently instantiated. And if not, it takes a guess and sticks to it:
?- colouring(L), subset(L,[1,2,3,4,5]).
L = [1,2,3,4,2,1].
?- colouring(L), subset(L,[1,2,3,4,5]), L = [2|_].
false.
?- L = [2|_], colouring(L), subset(L,[1,2,3,4,5]), L = [2|_].
L = [2,1,3,4,1,2].
With a pure definition it is impossible that adding a further goal as L = [2|_] in the third query makes a failing query succeed.
In general it is a good idea to not interfere with labeling/2 except for the order of variables and the options argument. The internal implementation is often much faster than manual instantiations.
Also, your map is far too simple to expose subset/2s weakness. Not sure what the minimal failing graph is, but here is one such example from
R. Janczewski et al. The smallest hard-to-color graph for algorithm DSATUR, Discrete Mathematics 236 (2001) p.164.
colouring_m13([K1,K2,K3,K6,K5,K7,K4]):-
maplist(#\=(K1), [K2,K3,K4,K7]),
maplist(#\=(K2), [K3,K5,K6]),
maplist(#\=(K3), [K4,K5]),
maplist(#\=(K4), [K5,K7]),
maplist(#\=(K5), [K6,K7]),
maplist(#\=(K6), [K7]).
?- colouring_m13(L), subset(L,[1,2,3,4]).
false. % incomplete
?- L = [3|_], colouring_m13(L), subset(L,[1,2,3,4]).
L = [3,1,2,2,3,1,4].
int_cset/2 never terminates
... (except for some error cases like int_cset(non_integer, _).). As an example consider:
?- int_cset(1,Cs).
Cs = [1]
; loops.
And don't get fooled by the fact that an actual solution was found! It still does not terminate.
#Luis: But how come? I'm getting baffled by this, the same thing is happening on ...
To see this, you need the notion of a failure-slice which helps to identify the responsible part in your program. With some falsework consisting of goals false the responsible part is exposed.
All unnecessary parts have been removed by false. What remains has to be changed somehow.
int_cset_(N,Acc,Acc) :- false, N #= 0.
int_cset_(N,Acc,Cs) :- N1 #= N-1, int_cset_(N1,[N|Acc],Cs), false.
int_cset(N,Cs) :- int_cset_(N,[],Cs), false.
?- int_cset(1, Cs), false.
loops.
Adding the redundant goal N1 #> 0
will avoid unnecessary non-termination.
This alone will not solve your problem since if N is not given, you will still encounter non-termination due to the following failure slice:
regions_ncolors(L,N) :-
colouring(L),
int_cset(N,Cs), false,
subset(L,Cs),
label(L).
In int_cset(N,Cs), Cs occurs for the first time and thus cannot influence termination (there is another reason too, its definition would ignore it as well..) and therefore only N has a chance to induce termination.
The actual solution has been already suggested by #TA_intern using length/2 which liberates one of such mode-infested chores.

Finding most occurrences in set of prolog rules

I can't seem to wrap my head around how Prolog actually works. I'm very used to other programming languages like Java and Python but Prolog seems to be very different since it is based on a set of logical statements.
If someone can explain to me how I would approach a situation where I am given a set of rules such as
likes(john,mary).
likes(mary,adam).
likes(adam,mary).
likes(jack,destiny).
likes(destiny,adam).
likes(brianna,adam).
and I want to find out how to see who is the most liked person (in this case adam = 3), how would I do this?
Maybe it's easier if you think of Prolog as a special database retrieval language that can morph into functional programming in the same line.
Here we we have a relation likes/2 over which we want to run statistics.
One could use predicates from library(aggregate) or similar, but let's not
Suggestion is to chain three operations:
Create a nicer structure to run stats
Run stats over nicer structure
Find the best
Create nicer structure to run stats
Collect
the vector (in the form or a Prolog list) of persons that occur as second argument in predicate likes/2 (so that we have something to count), and
the set of persons (also in the form of a Prolog list) so that we can iterate over something.
The key are the collection predicates findall/3 and setof/3
findall/3 is used to collect all the Person that appear on second argument position of likes/2,
setof/3 is used to collect the set of all Person that appear on first or second argument position of likes/2.
To make that work, setof/3 needs to be told that the argument on the other position is unimportant by
"existentially quantifying" it with X^.
person_occurrences(PersonVec) :-
findall(Person,likes(_,Person),PersonVec).
person_set(PersonSet) :-
setof(Person,X^(likes(Person,X);likes(X,Person)),PersonSet).
Alternativey for person_set/2, more comprehensible:
person(Person) :- likes(Person,_).
person(Person) :- likes(X,Person).
person_set(PersonSet) :- setof(Person,person(Person),PersonSet).
Trying this on the "Prolog Toplevel" shows we are on the right track:
?- person_occurrences(PersonSet).
PersonSet = [mary, adam, mary, destiny, adam, adam].
?- person_set(PersonSet).
PersonSet = [adam, brianna, destiny, jack, john, mary].
We can easily count how often a person occurs in the vector of persons,
by using findall/3 to create an arbitrary list of x (for example),
one x for each occurrence, then determining the length of that list:
count(Person,PersonVec,Count) :-
findall(x,member(Person,PersonVec),Xs),length(Xs,Count).
Trying this on the "Prolog Toplevel" shows we are on the right track:
?- person_occurrences(PersonVec),count(mary,PersonVec,Count).
PersonVec = [mary, adam, mary, destiny, adam, adam],
Count = 2.
We now have the "nicer structure" that we can use to do stats, namely the
"vector of persons" and the "set of persons".
Run stats over nicer structure
The result here, called Stats shall be a list (it's always lists) of
pairs -(NumberOfOccurrencesOfPersonInPersonVector,Person),
which can be more easily written "infix": Count-Person, for example 2-mary.
This is a recursive definition (or an inductive definition) whereby we "count"
for each person element in PersonSet until the PersonSet is the empty set
(or rather, the empty list), upon which we are done and succeed. The result
is constructed in the third argument:
% stats(PersonVec,PersonSet,Stats)
stats(_,[],[]).
stats(PersonVec,[Person|MorePersons],[Count-Person|MoreStats]) :-
count(Person,PersonVec,Count), % count them
stats(PersonVec,MorePersons,MoreStats). % recursion
Trying this on the "Prolog Toplevel" shows we are on the right track:
?- person_occurrences(PersonVec),stats(PersonVec,[mary],Stats).
PersonVec = [mary, adam, mary, destiny, adam, adam],
Stats = [2-mary] ; % Maybe more solutions?
false. % Nope.
New we can build the whole of the stats list:
stats(Stats) :-
person_occurrences(PersonVec),
person_set(PersonSet),
stats(PersonVec,PersonSet,Stats).
Trying this on the "Prolog Toplevel" shows we are on the right track:
?- stats(Stats).
Stats = [3-adam, 0-brianna, 1-destiny, 0-jack, 0-john, 2-mary] ;
false.
Find the best
Given Stats, we can find a BestPerson by maximizing over the list of pairs.
This can be done directly by selecting the pair which is "largest"
according to "the standard order of term": the numeric count comes first
so a term with a larger numeric count is "larger" than one with a
smaller numeric count, which is what we want. The predicate
max_member/2
does what we want:
best(Stats,BestPerson,BestCount) :-
max_member(BestCount-BestPerson,Statss).
Alternatively, we can program-out the max_member/2 (and keep
it to numeric comparison of the first argument, AND get several
answers in case there are several persons with the same "likes"
count), like so:
% start the maximization over Stats with a dummy "(-1)-nobody"
best(Stats,BestPerson,BestCount) :-
best2(Stats, (-1)-nobody, BestCount-BestPerson).
% best2(Stats,BestCountSoFar-BestPersonSoFar,Result).
best2([],BestCountSoFar-BestPersonSoFar,BestCountSoFar-BestPersonSoFar).
best2([Count-_|MoreStats],BestCountSoFar-BestPersonSoFar,Result) :-
Count < BestCountSoFar,
best2(MoreStats,BestCountSoFar-BestPersonSoFar,Result). % keep best
best2([Count-_|MoreStats],BestCountSoFar-BestPersonSoFar,Result) :-
Count == BestCountSoFar,
best2(MoreStats,BestCountSoFar-BestPersonSoFar,Result). % keep best (2nd possibility below)
best2([Count-Person|MoreStats],BestCountSoFar-_,Result) :-
Count >= BestCountSoFar,
best2(MoreStats,Count-Person,Result). % take new, better, pair
Conclude
We run it together:
?- stats(Stats),best(Stats,BestPerson,BestCount).
Stats = [3-adam, 0-brianna, 1-destiny, 0-jack, 0-john, 2-mary],
BestPerson = adam, BestCount = 3 ; % maybe more solutions?
false. % no
Complete code
likes(john,mary).
likes(mary,adam).
likes(adam,mary).
likes(jack,destiny).
likes(destiny,adam).
likes(brianna,adam).
person_occurrences(PersonVec) :-
findall(Person,likes(_,Person),PersonVec).
person_set(PersonSet) :-
setof(Person,X^(likes(Person,X);likes(X,Person)),PersonSet).
count(Person,PersonVec,Count) :-
findall(x,member(Person,PersonVec),Xs),length(Xs,Count).
% stats(PersonVec,PersonSet,Stats)
stats(_,[],[]).
stats(PersonVec,[Person|MorePersons],[Count-Person|MoreStats]) :-
count(Person,PersonVec,Count), % count them
stats(PersonVec,MorePersons,MoreStats). % recursion
stats(Stats) :-
person_occurrences(PersonVec),
person_set(PersonSet),
stats(PersonVec,PersonSet,Stats).
% start the maximization over Stats with a dummy "(-1)-nobody"
best(Stats,BestPerson,BestCount) :-
best2(Stats, (-1)-nobody, BestCount-BestPerson).
% best2(Stats,BestCountSoFar-BestPersonSoFar,Result).
best2([],BestCountSoFar-BestPersonSoFar,BestCountSoFar-BestPersonSoFar).
best2([Count-_|MoreStats],BestCountSoFar-BestPersonSoFar,Result) :-
Count < BestCountSoFar,
best2(MoreStats,BestCountSoFar-BestPersonSoFar,Result). % keep best
best2([Count-_|MoreStats],BestCountSoFar-BestPersonSoFar,Result) :-
Count == BestCountSoFar,
best2(MoreStats,BestCountSoFar-BestPersonSoFar,Result). % keep best (2nd possibility below)
best2([Count-Person|MoreStats],BestCountSoFar-_,Result) :-
Count >= BestCountSoFar,
best2(MoreStats,Count-Person,Result). % take new, better, pair
Consider the set of facts:
likes(john,mary).
likes(mary,adam).
likes(adam,mary).
likes(jack,destiny).
likes(destiny,adam).
likes(brianna,adam).
Another possible solution is as follows:
You can use setof/3 to get the list of persons that like someone:
?- setof(Person, likes(Person,Someone), ListOfPersons).
Someone = adam,
ListOfPersons = [brianna, destiny, mary] ;
Someone = destiny,
ListOfPersons = [jack] ;
Someone = mary,
ListOfPersons = [adam, john].
Then, you can combine setof/3 with findall/3 to get a list of pairs of the form Someone-ListOfPersons:
?- findall(Someone-ListOfPersons, setof(Person, likes(Person,Someone), ListOfPersons), Pairs).
Pairs = [adam-[brianna, destiny, mary], destiny-[jack], mary-[adam, john]].
After that, you can use maplist/3 to map pairs of the form Someone-ListOfPersons into corresponding pairs of the form Someone-NumberOfPersons:
?- findall(Someone-ListOfPersons, setof(Person, likes(Person,Someone), ListOfPersons), Pairs),
maplist([Someone-ListOfPersons, Someone-NumberOfPersons]>>length(ListOfPersons,NumberOfPersons), Pairs, NewPairs).
Pairs = [adam-[brianna, destiny, mary], destiny-[jack], mary-[adam, john]],
NewPairs = [adam-3, destiny-1, mary-2].
Finally, you can use sort/4 to get the most liked person:
?- findall(Someone-ListOfPersons, setof(Person, likes(Person,Someone), ListOfPersons), Pairs),
maplist([Someone-ListOfPersons, Someone-NumberOfPersons]>>length(ListOfPersons,NumberOfPersons), Pairs, NewPairs),
sort(2,>=,NewPairs, SortedPairs).
Pairs = [adam-[brianna, destiny, mary], destiny-[jack], mary-[adam, john]],
NewPairs = [adam-3, destiny-1, mary-2],
SortedPairs = [adam-3, mary-2, destiny-1].
Thus, the final solution is:
most_liked(Person) :-
findall(Someone-ListOfPersons,
setof(Person, likes(Person,Someone), ListOfPersons),
Pairs),
maplist([Someone-ListOfPersons, Someone-NumberOfPersons]>>length(ListOfPersons, NumberOfPersons),
Pairs,
NewPairs),
sort(2, >=, NewPairs, [Person-_|_]).
Running example:
?- most_liked(Person).
Person = adam.
Another solution where we don't care about the admonition to "do things only once" and "let Prolog work for us" instead is simply this:
Determine how much an arbitrary person is "liked"
person_liked_count(Person,Count) :-
likes(_,Person), % Grab a Person
findall(x, % Create a list of 'x'
likes(_,Person), % one 'x' for each like of the Person
Xs), % and this will be list 'Xs'.
length(Xs,Count). % The number of likes is the length of the list
We now get multiple solutions for any person, but we don't care:
?- person_liked_count(Person,Count).
Person = mary, Count = 2 ;
Person = adam, Count = 3 ;
Person = mary, Count = 2 ;
Person = destiny, Count = 1 ;
Person = adam, Count = 3 ;
Person = adam, Count = 3.
Maximize by doing exactly what is demanded
Person with "likes count" Count is what we want if we have person_liked_count(Person,Count) and there is no other person that has higher count (there is no need to even check that _PersonOther is different from Person inside the negation-as-failure-marked-subgoal, although we can):
most_liked(Person,Count) :-
person_liked_count(Person,Count), % grab a Person and a Count
\+ (person_liked_count(_P,CountOther), % "where not exists" a person _P
CountOther > Count). % with a higher count
We now get several answers, but that is not a problem as they are all the same:
?- most_liked(Person,Count).
Person = adam, Count = 3 ;
Person = adam, Count = 3 ;
Person = adam, Count = 3.
We can always force determinism with once/1
?- once(most_liked(Person,Count)).
Person = adam, Count = 3.
Everything in one block
likes(john,mary).
likes(mary,adam).
likes(adam,mary).
likes(jack,destiny).
likes(destiny,adam).
likes(brianna,adam).
person_liked_count(Person,Count) :-
likes(_,Person), % Grab a Person
findall(x, % Create a list of 'x'
likes(_,Person), % one 'x' for each like of the Person
Xs), % and this will be list 'Xs'.
length(Xs,Count). % The number of likes is the length of the list
most_liked(Person,Count) :-
person_liked_count(Person,Count), % grab a Person and a Count
\+ (person_liked_count(_P,CountOther), % "where not exists" a person _P
CountOther > Count). % with a higher count
solution(Person,Count) :- once(most_liked(Person,Count)).

Prolog internal variable names

I have a large numbers of facts that are already in my file (position(M,P)), M is the name and P is the position of the player , I am asked to do a player_list(L,N), L is the list of players and N is the size of this list. I did it and it works the problem is that it gives the list without the names it gives me numbers and not names
player_list([H|T],N):- L = [H|T],
position(H,P),
\+ member(H,L),
append(L,H),
player_list(T,N).
what I get is:
?- player_list(X,4).
X = [_9176, _9182, _9188, _9194] .
so what should I do ?
You could use an additional list as an argument to keep track of the players you already have. This list is empty at the beginning, so the calling predicate calls the predicate describing the actual relation with [] as an additional argument:
player_list(PLs,L) :-
pl_l_(PLs,L,[]). % <- actual relation
The definition you posted is missing a base case, that is, if you already have the desired amount of players, you can stop adding others. In this case the number of players to add is zero otherwise it is greater than zero. You also have to describe that the head of the list (PL) is a player (whose position you don't care about, so the variable is preceded by an underscore (_P), otherwise the goal is just like in your code) and is not in the accumulator yet (as opposed to your code, where you check if PL is not in L) but in the recursive call it is in the accumulator. You can achieve the latter by having [PL|Acc0] in the recursive goal, so you don't need append/2. Putting all this together, your code might look something like this:
pl_l_([],0,_). % base case
pl_l_([PL|PLs],L1,Acc0) :-
L1 > 0, % number of players yet to add
L0 is L1-1, % new number of players to add
position(PL,_P), % PL is a player and
\+ member(PL,Acc0), % not in the accumulator yet
pl_l_(PLs,L0,[PL|Acc0]). % the relation holds for PLs, L0 and [PL|Acc0] as well
With respect to your comment, I assume that your code contains the following four facts:
position(zlatan,center).
position(rooney,forward).
position(ronaldo,forward).
position(messi,forward).
Then your example query yields the desired results:
?- player_list(X,4).
X = [zlatan,rooney,ronaldo,messi] ? ;
X = [zlatan,rooney,messi,ronaldo] ? ;
...
If you intend to use the predicate the other way around as well, I suggest the use of CLP(FD). To see why, consider the most general query:
?- player_list(X,Y).
X = [],
Y = 0 ? ;
ERROR at clause 2 of user:pl_l_/3 !!
INSTANTIATION ERROR- =:=/2: expected bound value
You get this error because >/2 expects both arguments to be ground. You can modify the predicate pl_l_/3 to use CLP(FD) like so:
:- use_module(library(clpfd)).
pl_l_([],0,_).
pl_l_([PL|PLs],L1,Acc0) :-
L1 #> 0, % <- new
L0 #= L1-1, % <- new
position(PL,_P),
\+ member(PL,Acc0),
pl_l_(PLs,L0,[PL|Acc0]).
With these modifications the predicate is more versatile:
?- player_list([zlatan,messi,ronaldo],Y).
Y = 3
?- player_list(X,Y).
X = [],
Y = 0 ? ;
X = [zlatan],
Y = 1 ? ;
X = [zlatan,rooney],
Y = 2 ?
...

Comparing a list with lists in another list in Prolog

I have two lists:
L1 = [[a,b,c], [e,b,d], [f,g,a]]
L2 = [a,e]
I want to compare L2 with each list in L1 and find the number of common items. I am trying following code:
common([],L).
common([H|T], L, Out):-
intersection(H,L,Out), common(T, L, Out),
length(Out,Len).
However, it is not working:
?- common([[a,b,c], [e,b,d], [f,g,a]], [a,e], Outlist).
false.
The main list remains list in list (as seen after debugging with writeln statements):
L is:
[a,e]
H|T is:
[[f,g,a]]
Outlist = [] .
Where is the problem and how can I correct this?
I edited the code to debug and found that somehow it has started working:
common([],L,Out).
common([H|T], L, Out):-
writeln('------------in common--------------'),
writeln('L is:'), writeln(L),
writeln('H is:'), writeln(H),
intersection(L,H,Out2list),
writeln('Out2list is:'), writeln(Out2list),
common(T, L, Out2).
41 ?- common([[a,b,c], [e,b,d], [f,g,a]], [a,e], Outlist).
------------in common--------------
L is:
[a,e]
H is:
[a,b,c]
Out2list is:
[a]
------------in common--------------
L is:
[a,e]
H is:
[e,b,d]
Out2list is:
[e]
------------in common--------------
L is:
[a,e]
H is:
[f,g,a]
Out2list is:
[a]
true.
First let's observe that you have written a predicate common/2 and a predicate common/3. Reading your question, I assume you intend the former to be the base case for common/3. Thinking about the relation you want to describe, it would make sense to define that the intersection of the empty list and any other list is the empty list:
common([],_,[]).
However, it is not entirely clear what you expect the third argument to be. In your question you write that it should be the number of common items. The use of length/2 in your predicate common/3 supports this interpretation. In this case you want to have the lengths of the respective intersections in the third list:
common([],_,[]).
common([H|T], L, [Len|Out]):- % Len is in the 3rd list
intersection(H,L,I), % I is intersection of H and L
length(I,Len), % Len is length of I
common(T, L, Out). % the same for T, L and Out
With this version your example query yields:
?- common([[a,b,c], [e,b,d], [f,g,a]],[a,e],I).
I = [1,1,1]
In your first comment however, you write that you want Outlist to be [a]. That suggests that you want lists instead of numbers in the third argument. But looking at your example query [a] can not be the answer. On the one hand, if you mean that you want to see all the intersections of the elements of the first list with the second argument, you might like to write something like:
common2([],_,[]).
common2([H|T], L, [I|Out]):- % I is in the third list
intersection(H,L,I), % I is intersection of H and L
common2(T, L, Out). % the same for T, L and Out
This yields with your example:
?- common2([[a,b,c], [e,b,d], [f,g,a]],[a,e],I).
I = [[a],[e],[a]]
On the other hand, if you mean that you want to see the intersection of all the lists of the first argument with the second argument, you might like to go with something like this:
common3([],_,[]). % special case empty list
common3([H|T],L,I) :- % if 1st list not empty
common3_([H|T],L,I). % I is described in common3_/3
common3_([],I,I). % if the list is empty I = Outlist
common3_([H|T], L, O) :-
intersection(H,L,I), % I is intersection of H and L
common3_(T,I,O). % only the elements in I can be in O
With your example lists this yields
?- common3([[a,b,c], [e,b,d], [f,g,a]],[a,e],I).
I = []
since neither a nor e occur in all three lists. But if you add a to the second list:
?- common3([[a,b,c], [e,b,d,a], [f,g,a]],[a,e],I).
I = [a]

prolog function returning memory locations instead of values

just started programming with prolog and I'm having a few issues. The function I have is supposed to take a value X and copy it N number of times into M. My function returns a list of N number of memory locations. Here's the code, any ideas?
duple(N,_,M):- length(M,Q), N is Q.
duple(N,X,M):- append(X,M,Q), duple(N,X,Q).
Those are not memory adresses. Those are free variables. What you see is their internal names in your prolog system of choice. Then, as #chac pointed out (+1 btw), the third clause is not really making sense! Maybe you can try to tell us what you meant so that we can bring light about how to do it correctly.
I'm going to give you two implementations of your predicate to try to show you correct Prolog syntax:
duple1(N, X, L) :-
length(L, N),
maplist(=(X), L).
Here, in your duple1/3 predicate, we tell prolog that the length of the resulting list L is N, and then we tell it that each element of L should be unified with X for the predicate to hold.
Another to do that would be to build the resulting list "manually" through recursion:
duple2(0, _X, []).
duple2(N, X, [X|L]) :-
N > 0,
NewN is N - 1,
duple1(NewN, X, L).
Though, note that because we use >/2, is and -/2, ie arithmetic, we prevent prolog from using this predicate in several ways, such as:
?- duple1(X, Y, [xyz, xyz]).
X = 2,
Y = xyz.
This worked before, in our first predicate!
Hope this was of some help.
I suppose you call your predicate, for instance, in this way:
?- duple(3,xyz,L).
and you get
L = [_G289, _G292, _G295] ;
ERROR: Out of global stack
If you try
?- length(X,Y).
X = [],
Y = 0 ;
X = [_G299],
Y = 1 ;
X = [_G299, _G302],
Y = 2 ;
X = [_G299, _G302, _G305],
Y = 3 ;
X = [_G299, _G302, _G305, _G308],
Y = 4 .
...
you can see what's happening:
your query will match the specified *M*, displaying a list of M uninstantiated variables (memory locations), then continue backtracking and generating evee longer lists 'til there is stack space. Your second rule will never fire (and I don't really understand its purpose).
A generator is easier to write in this way:
duple(N,X,M) :- findall(X,between(1,N,_),M).
test:
?- duple(3,xyz,L).
L = [xyz, xyz, xyz].

Resources