Prolog findall list of predicates - prolog

I've been searching but I can't find the right answer for my question.
The problem is:
a predicate
initial_estates([rb(1,1),rb(2,2),rb(3,5)]).
I want to use findall to get me a list of all the second term of rb's.
Like in this example [1,2,5]
Anyone can help

You can use lists:member/2 to interactively find all values of the pairs rb/2 in your list:
?- initial_estates(L),member(rb(X,Y),L).
L = [rb(1,1),rb(2,2),rb(3,5)],
X = Y = 1 ? ;
L = [rb(1,1),rb(2,2),rb(3,5)],
X = Y = 2 ? ;
L = [rb(1,1),rb(2,2),rb(3,5)],
X = 3,
Y = 5 ? ;
no
And based on that findall to get all second elements (Y) in one list (Res):
?- findall(Y,(initial_estates(L),member(rb(X,Y),L)),Res).
Res = [1,2,5]
Alternatively, you could also write a predicate, say rb_2nd/2, that describes the second argument to be the second element in the pair that is the first argument:
rb_2nd(rb(X,Y),Y).
And then use apply:maplist/3 to apply that relation to the list described by initial_estates/1:
?- initial_estates(L), maplist(rb_2nd,L,Res).
L = [rb(1,1),rb(2,2),rb(3,5)],
Res = [1,2,5]
I find the latter easier to read than the query using findall/3.

Related

Predicate arithmetic combination (only + or -) to find a result from a list of numbers

I'm trying to achieve an old exercice from my school and i can't figure it out how to solve it. Here is the result expected :
bC([1,12,34,23,11],23,Res).
Res = 1+11-12+23
So bC/3 is supposed to find every combination of addition or substract operation (the third argument) from a list of number (the first argument) to match a result (the second argument).
I can't find a way to start resolving this... If someone could give me a clue about this problem, i would really appreciate it.
UPDATE: Some elements of the list can be left out.
As a hint: you can aim to construct all expressions by exhautively searching over the expression space. Since X - (Y - Z) is just X - Y + Z, this is good news, since we can restrict us to left recursive expressions, like:
makepm([], ExpI, ExpI).
makepm([H|T], ExpI, ExpO) :-
makepm(T, +(ExpI, H), ExpO).
makepm([H|T], ExpI, ExpO) :-
makepm(T, -(ExpI, H), ExpO).
If as first element we take 1, and we inject the rest of the list in the makepm/3, we get:
?- makepm([12,34,23,11], 1, F).
F = 1+12+34+23+11 ;
F = 1+12+34+23-11 ;
F = 1+12+34-23+11 ;
F = 1+12+34-23-11 ;
F = 1+12-34+23+11 ;
F = 1+12-34+23-11 ;
F = 1+12-34-23+11 ;
F = 1+12-34-23-11 ;
F = 1-12+34+23+11 ;
F = 1-12+34+23-11 ;
F = 1-12+34-23+11 ;
F = 1-12+34-23-11 ;
F = 1-12-34+23+11 ;
F = 1-12-34+23-11 ;
F = 1-12-34-23+11 ;
F = 1-12-34-23-11.
What still needs to be done: the question is not perfectly clear about the fact if numbers can be left out, if that is the case, then you should write a predicate that first selects a subset of numbers. Then we can exhaustively enumerate all expressions which we create with makepm/3, and then we need to verify, for example with the is/2 [swi-doc] predicate that the expression sums up to the requested value. If that is the case the predicate can succeed.

Prolog , return permutations with a max value

i have made predicate schedule(A,B,C) that returns possible permutations at lists A,B,C with backtracking
| ?- schedule(A,B,C).
A = [im204,im212,im217]
B = [im209,im214,im218]
C = [im210,im216] ? ;
A = [im204,im212,im218]
B = [im209,im214,im217]
C = [im210,im216] ? ;
A = [im204,im212,im216]
B = [im209,im214,im218]
C = [im210,im217] ?
I also have the predicate schedule_score(A,B,C,S) which returns score(dont mind what the score means) from lists A,B,C to S.
| ?- score_schedule([im204,im209,im212],[im210,im214,im216],[im217,im218],S).
S = 578
In my new predicate
all_schedule_scores(A,B,C,S):-
schedule(A,B,C),
score_schedule(A,B,C,S).
it returns possible permutations along with the score
| ?- all_schedule_scores(A,B,C,S).
A = [im204,im212,im217]
B = [im209,im214,im218]
C = [im210,im216]
S = 342 ? ;
A = [im204,im212,im218]
B = [im209,im214,im217]
C = [im210,im216]
S = 371 ? ;
A = [im204,im212,im216]
B = [im209,im214,im218]
C = [im210,im217]
S = 294 ?
I was wondering if there was a way i can return only the permutations with the max score(or not return any permutations whose score isnt max).
It's not clear what Prolog implementation you're using. Here's a solution that uses setof/3 (which orders its results low to high):
max_scored(MaxA, MaxB, MaxC, MaxS) :-
setof((S,A,B,C), all_scheduled_scores(A,B,C,S), AllScoresLowToHigh),
reverse(AllScoresLowToHigh, [(MaxS,MaxA,MaxB,MaxC)|_]).
Sorting uses a natural ordering, so (S1,A1,B1,C1) is considered greater than (S2,A2,B2,C2) if S1 is greater than S2.
This solution just finds a single maximum result. If you have multiple that are at the same maximum, I'll leave that as an exercise for you. You would just need to choose the first elements of the 2nd argument to reverse/2 that have the same score.
If your Prolog supports it, you could use library(aggregate):
max_scored_schedule(ScA,ScB,ScC,Score) :-
aggregate(max(S,[A,B,C]), (schedule(A,B,C),score_schedule(A,B,C,S)), max(Score,[ScA,ScB,ScC])).
Tested with hardcoded data you provided:
?- max_scored_schedule(A,B,C,S).
A = [im204, im209, im212],
B = [im210, im214, im216],
C = [im217, im218],
S = 578.
As you can see, it's just a matter to properly order arguments...
Edit:
library(solutionsequences) allows for a SQL like query, that should solve your problem
?- order_by([desc(S)], group_by(S, (A,B,C), (schedule(A,B,C),score_schedule(A,B,C,S)), G)).
but the straightforward answer by #lurker is neat (+1), and doesn't require you to port another library to your Prolog

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 ?
...

How can I assert facts about all List members in Prolog?

I'd like to assert facts about all members of a List in prolog, and have any resulting unification retained. As an example, I'd like to assert that each list member is equal to five, but none of the below constructs does this:
?- L=[X,Y,Z], forall(member(E,L), E=5).
L = [_h27057686,_h27057704,_h27057722]
X = _h27057686
Y = _h27057704
Z = _h27057722
yes
?- L=[X,Y,Z], foreach(member(E,L), E=5).
L = [_h27057686,_h27057704,_h27057722]
X = _h27057686
Y = _h27057704
Z = _h27057722
yes
I would like a way to pose the query such that X=5,Y=5, and Z=5.
There is a lot of terminology that you might be getting wrong, or I am misunderstanding you.
"Equal to" is not the same as "could unify", or "unify", but it depends how you mean it.
With SWI-Prolog, from the top level:
?- X == 5.
false. % the free variable X is not the integer 5
?- unifiable(X, 5, U).
U = [X=5]. % you could unify X with 5, then X will be 5
?- X = 5.
X = 5. % X unifies with 5 (and is now bound to the integer 5)
The comment by CapelliC already has the answer that you are most likely after: given a list of variables (either free or not), make so that each variable in the list is bound to the integer 5. This is best done by unification (the third query above). The maplist simply applies the unification to each element of the list.
PS. In case you are wondering how to read the maplist(=(5), L):
These three are equivalent:
maplist(=(5), [X,Y,Z])
maplist(=, [5,5,5], [X,Y,Z])
X=5, Y=5, Z=5
And of course X=5 is the same as =(X,5).

Creating concatenation predicate in prolog that works with only one input instantiation

Is it possible to create a predicate in Prolog that concatenates two lists and works in any case of these:
concat(X,Y,[1,2,3,4])
concat(X,[2,3,4],[1,2,3,4])
concat([1,2,3],X,[1,2,3,4])
The best I could make so far was this:
concat([],[],[]).
concat([],X,X).
concat(X,[],X).
concat([X|Y],[A|B],[X|Z]) :- add(Y,[A],K) , add(K,B,Z) .
with the following results:
works correctly:
concat([1,2,3],X,[1,2,3,4])
gives correct answer, then enters infinite loop:
concat(X,[2,3,4],[1,2,3,4])
gives some results (edit: all results, I believe), then enters infinite loop:
concat(X,Y,[1,2,3,4])
results given:
?- concat(X,Y,[1,2,3,4]).
X = [],
Y = [1,2,3,4] ? ;
X = [1,2,3,4],
Y = [] ? ;
X = [1],
Y = [2,3,4] ? ;
X = [1,2],
Y = [3,4] ? ;
X = [1,2,3],
Y = [4] ? ;
I'm trying to make this predicate to learn more about prolog.
As stated, you're just redefining append/3. However, as a learning experience you should notice that you can do this in a simpler and more Prolog-y way:
concat([],X,X).
concat([X|Y],A,[X|Z]) :-
concat(Y,A,Z).
As you see, the definitions for empty second list are needless because in the first definition Prolog copies (or more exactly, unifies) second list to the third (or vice versa) even if it is an empty one. You need to handle an empty list only in the first list to stop the recursion. Besides, using pattern matching you don't need extra predicates to move the head items from a list to another.

Resources