Prolog Using findall/3 on a Matrix - matrix

I have the following matrix in my SWI prolog;
matrix(1,[ [*,*,*,*,*,*,*,*,*,*,*,*],
[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],
[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],
[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],
[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],
[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],
[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],
[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],
[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],
[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*]
[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],
[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]]).
I want to use a findall/3 predicate so that I can get a list of all the spot(X,Y) facts like >>>
findall(spots(X,Y),matrix(1,Map),X).
Which should return something like the following;
X = (spots(2,4), spots(2,5), spots(2,10), spots(2,11), spots(3,4) etc .... spots(12,10)).
However, I'm very confused in how to implement this, due to the matrix being composed of a list within a list. Would appreciate if someone could show me a configured predicate in order to achieve a list like stated.
Thanks for any help!!! - really appreciate it!
Edit - may be able to use this code found below and unable to see how I could implement this into a second findall/3 statement. Really stuck so appreciate any help on this.
at(Mat, Row, Col, Val) :- nth1(Row, Mat, ARow), nth1(Col, ARow, Val).

Just think what your predicate should describe: You want to find all terms of the form spots(_,_) in a list of lists that otherwise consists of atoms *.
:- use_module(library(lists)).
matrix_spots([],[]). % no spots in the empty matrix
matrix_spots([R|Rs],S) :-
row_spots(R,RSs), % RSs ... spots in row R
matrix_spots(Rs,S1), % S1 ... spots in the remaining rows
append(RSs,S1,S). % S ... RSs followed by S1
row_spots([],[]). % no spots in an empty row
row_spots([E|Es],[E|RSs]) :- % E is in the list of spots
E=spots(_,_), % if it is a spot
row_spots(Es,RSs). % RSs ... spots in rest of row
row_spots([*|Es],RSs) :- % * is not in the list of spots
row_spots(Es,RSs). % Rss ... spots in rest of row
Now you can query your matrix for all its spots:
?- matrix(1,M), matrix_spots(M,S).
M = [[*,*,*,*,*,*,*,*,*,*,*,*],[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*],[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]],
S = [spots(2,4),spots(2,5),spots(2,10),spots(2,11),spots(3,4),spots(3,5),spots(3,6),spots(3,7),spots(3,10),spots(3,11),spots(4,3),spots(4,4),spots(4,6),spots(4,7),spots(4,8),spots(4,9),spots(4,11),spots(4,12),spots(5,2),spots(5,3),spots(5,4),spots(5,5),spots(5,8),spots(5,9),spots(5,11),spots(5,12),spots(6,2),spots(6,3),spots(6,5),spots(6,6),spots(6,7),spots(6,8),spots(6,10),spots(6,11),spots(6,12),spots(7,3),spots(7,4),spots(7,6),spots(7,7),spots(7,8),spots(7,10),spots(7,11),spots(8,2),spots(8,3),spots(8,4),spots(8,6),spots(8,7),spots(8,8),spots(8,9),spots(8,11),spots(8,12),spots(9,2),spots(9,3),spots(9,5),spots(9,6),spots(9,9),spots(9,10),spots(9,11),spots(9,12),spots(10,2),spots(10,3),spots(10,5),spots(10,6),spots(10,7),spots(10,8),spots(10,10),spots(10,11),spots(11,3),spots(11,4),spots(11,7),spots(11,8),spots(11,9),spots(1ts(12,4),spots(12,9),spots(12,10)] ? ;
no
Note that you have a typo in your example matrix: at the end of the 10th list the comma is missing: ...spots(10,11),*],
Edit:
Here is a dcg version as suggested by #mat in the comments. It is indeed much easier readable:
matrix_spots(M,S) :-
phrase(rows(M),S).
rows([]) --> % no spots in the empty matrix
[].
rows([R|Rs]) -->
row(R), % all spots in row R
rows(Rs). % all spots in the remaining rows
row([]) --> % no spots in an empty row
[].
row([*|Xs]) --> % no spot at this position in the row
row(Xs). % but there might be in the remainder
row([spots(A,B)|Xs]) --> % spot at this position
[spots(A,B)], % is in the list
row(Xs). % and the spots in the rest of the row
The query above can be used one-to-one with this dcg-version.
Concerning your (#User15388472) findall/3 question in the comments: Imagine you had a predicate matrix_spot/2 that is matching one term of the form spots(A,B) as second argument instead of a list of all spots. That predicate could look something like that:
matrix_spot([R|Rs],S) :-
row_spot(R,S). % S is in row R
matrix_spot([R|Rs],S) :- % S is not in R but
matrix_spot(Rs,S). % in one of the other rows Rs
row_spot([spots(A,B)|Xs],spots(A,B)). % head of the list is the spot
row_spot([X|Xs],S) :-
row_spot(Xs,S). % S is in the tail of the list
If you query this predicate you get one spots(A,B) at a time as an answer:
?- matrix(1,M), matrix_spot(M,S).
M = [[*,*,*,*,*,*,*,*,*,*,*,*],[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*],[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]],
S = spots(2,4) ? ;
M = [[*,*,*,*,*,*,*,*,*,*,*,*],[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*],[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]],
S = spots(2,5) ? ;
...
In a scenario like this you can use findall/3 to find all terms spots(A,B) in the matrix:
?- matrix(1,M), findall(S,matrix_spot(M,S),Spots).
M = [[*,*,*,*,*,*,*,*,*,*,*,*],[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*],[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]],
Spots = [spots(2,4),spots(2,5),spots(2,10),spots(2,11),spots(3,4),spots(3,5),spots(3,6),spots(3,7),spots(3,10),spots(3,11),spots(4,3),spots(4,4),spots(4,6),spots(4,7),spots(4,8),spots(4,9),spots(4,11),spots(4,12),spots(5,2),spots(5,3),spots(5,4),spots(5,5),spots(5,8),spots(5,9),spots(5,11),spots(5,12),spots(6,2),spots(6,3),spots(6,5),spots(6,6),spots(6,7),spots(6,8),spots(6,10),spots(6,11),spots(6,12),spots(7,3),spots(7,4),spots(7,6),spots(7,7),spots(7,8),spots(7,10),spots(7,11),spots(8,2),spots(8,3),spots(8,4),spots(8,6),spots(8,7),spots(8,8),spots(8,9),spots(8,11),spots(8,12),spots(9,2),spots(9,3),spots(9,5),spots(9,6),spots(9,9),spots(9,10),spots(9,11),spots(9,12),spots(10,2),spots(10,3),spots(10,5),spots(10,6),spots(10,7),spots(10,8),spots(10,10),spots(10,11),spots(11,3),spots(11,4),spots(11,7),spots(11,8),spots(11,9),spots(11,10),spots(12,3),spots(12,4),spots(12,9),spots(12,10)]

Related

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

Prolog return a list which contains only elements which are equal to head of the list

Hello I would like to ask a doubt I have with the following code:
principio([],[]).
principio([H],[H]).
principio([H,_|_],[H]).
principio([H,H|C],P) :-
principio([H|C],R),P=[H|R].
I would like a way to get from:
?- principio([222,333,101,202,12,222,13,222],X).
X = [222,222,222]
But in this moment I get just the head:
X = [222]
So, to keep it clear I'd like: all successive occurrences of the first element as a list.
My doubt is what does this assignment P=[H|R] why not to put just:
principio([H,H|C],P) :-
principio([H|C],P)
Also, how would you try to modify this to get the result I asked for?
Thank you
Here is two ways how you can narrow down the problem. 1st, start from an unexpectedly failing query. 2nd, start from a query that should fail but rather succeeds.
1st Diagnose unexpected incompleteness
Determine a most specific failing query
?- principio([222,333,101,202,12,222,13,222],[222,222,222]).
false.
Generalize the query
... as much as possible. I could do this manually, or I could let Prolog do the work for me. Here I use library(diadem):
?- use_module(diadem).
true.
?- principio([222,333,101,202,12,222,13,222],[222,222,222]).? Gen.
Gen = principio([222, 333|_], [_, _|_])
; Gen = (dif(A100, B100), principio([A100, B100|_], [_, _|_]))
; ... .
In other words: Not only does your original query fail, but also this generalization fails! Here, we only insist that the first two elements are different, and that the resulting list contains at least two elements — no matter which!
?- dif(X, Y), principio([X,Y|_],[_,_|_]).
Generalize your program
:- op(950, fy, *).
* _P_0.
principio([], _/*[]*/).
principio([_H], _/*[H]*/).
principio([H,_|_],[H]).
principio([H,H|C],P) :-
* principio([H|C],R),
* P=[H|R].
The error must reside in the little remaining part of your program. No need to read any further!
The problem is that for a list starting with two different elements you only have the clause principio([H,_|_],[H]).. So this part has to be generalized somehow.
2nd Diagnose unexpected unsoundness
Another way of finding the error would be to start with the unexpected solution:
?- principio([222,333,101,202,12,222,13,222],[222]).
true. % incorrect !!
And then reduce the size of the query as much as possible.
?- principio([222,222],[222]).
true. % incorrect !!
Now, specialize your program inserting false as long as above query succeeds:
principio([],[]) : - false.
principio([H],[H]) :- false.
principio([H,_|_],[H]).
principio([H,H|C],P) :- false,
principio([H|C],R),
P=[H|R].
The remaining visible part is the culprit! We have to revise it. What it says is:
Any list starting with two elements corresponds to the list with the first element only.
principio([],[]).
principio([H],[H]).
principio([H,D|Xs], [H|Hs]) :-
dif(H,D),
principio([H|Xs],[H|Hs]).
principio([H,H|Xs],[H|Hs]) :-
principio([H|Xs],Hs).
In addition to the very nice answer provided by #false (+s(0)), I would point out the possibility to use DCGs for the task. They usually yield easily readable code when describing lists (see comments beside the grammar rules):
principio([H|T],Hs) :-
phrase(heads([H|T],H),Hs).
heads([],_H) --> % in the empty list
[]. % there's no element matching H
heads([H|Xs],H) --> % if the head of the list matches H
[H], % it's in the list
heads(Xs,H). % same for the tail
heads([X|Xs],H) --> % if the head of the list is
{dif(X,H)}, % different from H it's not in the list
heads(Xs,H). % same for the tail
Thus your example query yields the desired result:
?- principio([222,333,101,202,12,222,13,222],X).
X = [222,222,222] ? ;
no

Prolog - Using Bagof

I've been stuck on a past paper question while studying for my exams.
The question is:
https://gyazo.com/ee2fcd88d67068e8cf7d478a98f486a0
I figured I've got to use findall/bagof/setof because I need to collect a set of solutions. Furthermore, setof seems appropriate because the list needs to be presented in descending order.
My solution so far is:
teams(List) :-
setof((Team, A),
(Team^team(Team, _, Wins, Draws, _), A is Wins*3 + Draws*1),
List).
However the problem is I don't quite get the answers all in one list. I'm very likely using Team^ incorrectly. I'd really appreciate pointers on how I can get a list of ordered tuples in terms of points. The output it gives me is:
X = [(queenspark,43)] ? ;
X = [(stirling,26)] ? ;
X = [(clyde,25)] ? ;
X = [(peterhead,35)] ? ;
X = [(rangers,63)] ? ;
Also, it's not really apparent what kind of order, if any it's in, so I'm also lost as to how setof is ordering.
Whats the best way to approach this question using setof?
Thanks.
Firstly, I would suggest to change (Team,A) to a pair representation A-Team with the A being in front since this is the total score of the team and thus the key you want to use for sorting. Then you would like to prefix the variables that should not be in the list with a ^ in front of the query you want to aggregate. See the following example:
?- setof(A-Team, P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1), List).
List = [25-clyde,26-stirling,35-peterhead,43-queenspark,63-rangers]
Since you asked, consider the following query with the pair ordering flipped to Team-A for comparison reasons:
?- setof(Team-A,P^Wins^Draws^L^(team(Team,P,Wins,Draws,L), A is Wins*3 + Draws*1),List).
List = [clyde-25,peterhead-35,queenspark-43,rangers-63,stirling-26]
Now the resulting list is sorted with respect to the teamnames. So A-Team is the opportune choice. You could then use the predicate lists:reverse/2 to reverse the order to a descending list and then define an auxilary predicate pair_second/2 that you can use with apply:maplist/3 to get rid of the leading scores in the pairs:
:- use_module(library(lists)).
:- use_module(library(apply)).
% team(+Name, +Played, +Won, +Drawn, +Lost)
team(clyde,26,7,4,15).
team(peterhead,26,9,8,9).
team(queenspark,24,12,7,5).
team(rangers,26,19,6,1).
team(stirling,25,7,5,13).
pair_second(A-B,B). % 2nd argument is 2nd element of pair
teams(Results) :-
setof(A-Team,
P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1),
List),
reverse(List,RList),
maplist(pair_second,RList,Results). % apply pair_second/2 to RList
If you query the predicate now you get the desired results:
?- teams(T).
T = [rangers,queenspark,peterhead,stirling,clyde]
Concerning your question in the comments: Yes, of course that is possible. You can write a predicate that describes a relation between a list of pairs and a list than only consists of the second element of the pairs. Let's call it pairlist_namelist/2:
pairlist_namelist([],[]).
pairlist_namelist([S-N|SNs],[N|Ns]) :-
pairlist_namelist(SNs,Ns).
Then you can define teams/1 like so:
teams(Results) :-
setof(A-Team,
P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1),
List),
reverse(List,RList),
pairlist_namelist(RList,Results).
In this case, besides maplist/3, you don't need pair_second/2 either. Also you don't need to include :- use_module(library(apply)). The example query above yields the same result with this version.

Prolog recursivly build list based on dot product

Hi I have a prolog function/predicate? that takes the dot product of two list. and would like to use it to write a function that builds a list of dot products from a list and a list of list. So basically, the dot product will be called on each list in the list of list the function dot is below and it works.
dot([], [], 0).
dot([Head|Tail], [Head2|Tail2], Result) :-
Prod = Head * Head2,
dot(Tail, Tail2, Remaining),
Result is Prod + Remaining.
This is my attempt at the function that fails every-time I try to run it. Can any one help?
dotAll([], [[]], [0]).
dotAll(X, [[Head]|[Tail]], Result) :-
dotUnit(X, Head, Prod),
Result = [Prod|Result],
dotAll(X, Tail, Result).
To sum of my goal, if I passed in this dotAll([1,2,3],[[1,2,3],[4,5,6],[1,2,3]], What). I would like to get back, What is [15,32,15].
I know that is a mouth full but i hope some one can give me some pointers on where im going wrong. Im very new to prolog.
The dotAll predicate I believe (from the example) is defined to be:
dotAll(Vector, ListOfVectors, Results)
And says that Results is the list of dot product results obtained by taking the dot product of Vector with each vector in ListOfVectors.
Reviewing the dotAll predicate:
dotAll(X, [Head|Tail], [Prod|Result]) :- % dotAll of X with [Head|Tail]
% is [Prod|Result] if...
dot(X, Head, Prod), % Prod is the dot product of X w/Head
%Result = [Prod|Result], % This would always fail
dotAll(X, Tail, Result). % AND Result is the list of
% dot products of X with Tail
Notes about the recursive case:
The Result = [Prod|Result] would fail since this is saying, I have Result and it's the same thing as [Prod|Result] which cannot be true.
You can use the third argument in the clause, as shown, to express what the result list will look like in the recursive case ([Prod|Result])
Then the base case:
dotAll(_, [], []). % dot product of anything with
% an empty list of vectors is empty
Notes about the base case:
The first argument is not [] because your recursive predicate doesn't reduce the first argument down to an empty list. The first argument is always the vector you started with which is used to dot product with the elements in the vector list (second argument). Since we don't care what the vector is in the base case, we use _.
The second argument is [], the empty list since the base case is about what happens when we've exhausted the list of vectors, which is a list of lists. When you get to the end of a lists of lists, you have an empty list ([]).
The third argument is the empty list [] not [0] because it's logical: if you take the dot product of any vector with an empty vector list, you should get no results (an empty list []).
Using the above corrections:
| ?- dotAll([1,2,3],[[1,2,3],[4,5,6],[7,8,9]], R).
R = [14,32,50] ? ;
no

Prolog: DRY way of creating lists declaratively

I'm doing some experiments with Prolog and having difficulties with the following rule:
row(Row, Matrix, [R1,R2,R3,R4]) :-
cell(1, Row, Matrix, R1),
cell(2, Row, Matrix, R2),
cell(3, Row, Matrix, R3),
cell(4, Row, Matrix, R4).
This rule extracts one row from a matrix, given its row number. For example,
row(2, [1,2,3,4,5,6,7,8], X)
X = [5,6,7,8]
What nags me is that there is lots of repetition in that code. After finishing with 4x4 matrices, I will have to deal with 9x9 ones. And the code can get very non DRY.
Is there a way to extract that repetition out?
Thanks.
Edit: The complete code giving me trouble is here: https://github.com/kikito/7-languages-in-7-weeks/blob/master/3-prolog/day-3/sudoku-refactor.pl
After writing my first answer, I realized that you can also simplify your program using findall
row(Row, Matrix, L) :- findall(X,cell(_,Row,Matrix,X),L).
I would think about changing the representation to a list of lists rather than a flat list, then selecting a row becomes very easy. You can just use the built-in nth1/3:
:- use_module(library(lists)). % I use Sicstus Prolog
row(N,M,X) :- nth1(N,M,X).
cell(R,C,M,X) :- nth1(R,M,Y), nth1(C,Y,X).
column(N,M,X) :- findall(Y,(nth1(_,M,Z), nth1(N,Z,Y)),X).
m([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]).
example(Row,Cell,Column) :- m(M), row(2,M,Row), cell(2,3,M,Cell), column(2,M,Column).
%| ?- example(A,B,C).
%A = [5,6,7,8],
%B = 7,
%C = [2,6,10,14] ? ;
%no

Resources