Prolog: list of n of n x n matrix - list

How to create n x n matrix in Prolog and inside the matrix is list of n to 1.
I can create the coding for generate list but do not know how to create a matrix n x n:
make_num_list(N, List) :-
make_list(N, List).
make_list(N, []) :-
N =< 0,
!.
make_list(N, [N|Rest]) :-
N > 0,
N2 is N - 1,
make_list(N2, Rest).

most Prolog out there have between/3, and surely will have findall/3
make_matrix(N, M) :- findall(Ns, (between(1,N,_), make_list(N,Ns)), M).

Reuse your code, and your ideas.
make_num_matrix(N, Matrix) :-
make_matrix(N, N, Matrix).
make_matrix(_, N, []) :-
N =< 0,
!.
make_matrix(M, N, [R|Rs]) :-
make_list(M, R),
N2 is N - 1,
make_matrix(M, N2, Rs).
make_list(N, []) :-
N =< 0,
!.
make_list(N, [N|Rest]) :-
N > 0,
N2 is N - 1,
make_list(N2, Rest).
?- make_num_matrix(4, M).
M = [[4, 3, 2, 1], [4, 3, 2, 1], [4, 3, 2, 1], [4, 3, 2, 1]].

Related

Arithmetic in Prolog - Multiples of a number

I want to create a function multiples(X, N, R) where R is a list containing all multiples of X from X to X * N.
An example would be: multiples(3, 4, [12, 9, 6, 3]), which should give out true.
My code so far:
multiples(X, N, R) :- X >= 1, N >= 1, Z is X*N, contains(Z, R).
contains(Z, [Z|_]).
contains(Z, [W|V]) :- contains(Z,V), L is Z-X, L >= X, contains(L, V).
The output of the console for multiples(3,4,X). is X = [12|_xxxx] and when I type ; an error occurs.
How do I manage to receive the list that I want?
(Maybe my idea is completely wrong).
I found 4 issues with your code. Here is the fixed code, explanation below:
multiples(X, N, R) :-
X >= 1,
N >= 1,
Z is X*N,
contains(X, Z, R).
contains(X, Z, [Z|V]) :-
L is Z-X,
L >= X,
contains(X, L, V).
contains(_, Z, [Z]).
?- multiples(3,4,X).
X = [12, 9, 6, 3] ;
X = [12, 9, 6] ;
X = [12, 9] ;
X = [12] ;
false.
At first in your contains predicate you access X and W and never state their values. Solve X by adding another attribute to the predicate. Solve W by replacing it with Z.
Another problem is the order of your rules. The larger contains rule should be the "main" rule, only if this one fails the other one should "fire". By placing the default rule on top you get the right result.
Also the rule contains(_, Z, [Z]). marks the end, therefore it the return list has only the element Z in it and does not contain any other (unknown) elements.
The last point is that you don't need two contains calls in the main contains rule.
The example works for the first answer. However you can improve this with a cut (!), which prevents going to the second rule after successfully visiting the first rule:
contains(X, Z, [Z|V]) :-
L is Z-X,
L >= X,
!,
contains(X, L, V).
contains(_, Z, [Z]).
?- multiples(3,4,X).
X = [12, 9, 6, 3].
A slight modification to your code. contains predicate will collect the numbers in a list, and N will keep getting decreased till it satisfies the base predicate.
multiples(X, N, R) :- X >= 1, N >= 1, contains(X,N, R),!.
contains(_,0,[]).
contains(X,N,[Z|List]):-
Z is X*N,
N1 is N-1,
contains(X,N1,List).
Example:
?- multiples(3,4,R).
R = [12, 9, 6, 3]
?- multiples(2,5,R).
R = [10, 8, 6, 4, 2]
?- multiples(25,5,R).
R = [125, 100, 75, 50, 25]

Create lists of permutations of size N from elements of another list

How do I, given a List = [(1,1),(1,2),(1,3),(1,4)], N = 2, create a list containing the multiple ordered permutations of List, size N:
permutations([(1,1),(1,2),(1,3),(1,4)],2,ListOut).
ListOut=[[(1,1),(1,2)],[(1,1),(1,3)],[(1,1),(1,4)],[(1,2),(1,3)],[(1,2),(1,4)],[(1,3),(1,4)]]
??
First let's solve the problem of finding one permutation:
perm(_, 0, []).
perm([X|Xs], N, [X|Ys]) :- N1 is N-1, perm(Xs,N1,Ys).
perm([_|Xs], N, Y) :- N>0, perm(Xs,N,Y).
There are two recursive rules: 1) X can be the first element of the output, and find the remaining permutation of N-1 for the rest of the list; 2) skip the first element, and find the permutation over the remaining elements of the input list.
Finding all permutations is just about using findall/3:
permutations(X, N, Y) :- findall(Z, perm(X, N, Z), Y).
Test:
?- permutations([(1,1),(1,2),(1,3),(1,4)], 2, X).
X = [[(1, 1), (1, 2)], [(1, 1), (1, 3)], [(1, 1), (1, 4)], [(1, 2), (1, 3)], [(1, 2), (1, 4)], [(1, 3), (1, 4)]].

Sum of even and odd numbers of a list in Prolog

What I need to do is to write a predicate that takes a list of numbers and returns a list consisting of two elements, the first one is the sum of the even numbers and the second one the sum of the odd numbers.
For example:
?- sum([5,4,9,8,1,7], L).
L = [12, 22].
So far I have written:
iseven(N) :-
0 is mod(N,2).
Since you've defined iseven/2 you could use it like:
sum([],[0,0]).
sum([H|T],[N1,N2]):-
sum(T,[N3,N4]),
( iseven(H)
-> N1 is N3+H, N2 is N4
; N2 is N4+H, N1 is N3
).
Example:
?-sum([5,4,9,8,1,7], L).
L = [12, 22].
A non if-then-else version using different clauses:
sum([],[0,0]).
sum([H|T],[N1,N2]):- sum(T,[N3,N2]), iseven(H), N1 is N3+H.
sum([H|T],[N1,N2]):- sum(T,[N1,N3]), \+ iseven(H), N2 is N3+H.
You could also write this predicate using accumulators and if_/3. Furthermore you can incorporate the single goal of iseven/1 into the predicate:
list_sums(L,S) :-
list_sums_(L,S,0-0).
list_sums_([],[E,O],E-O).
list_sums_([X|Xs],S,E0-O0) :-
M is X mod 2,
if_(M=0,(E1 is E0+X, O1 is O0),(E1 is E0, O1 is O0+X)),
list_sums_(Xs,S,E1-O1).
Note how the accumulators are written as a pair (E-O). If you are free to choose a representation for the two sums, this pair notation would be an alternative to a list with two elements. Your example query yields the desired result:
?- list_sums([5,4,9,8,1,7],L).
L = [12, 22].
And the example from the comments terminates considerably faster:
?- length(L,100),maplist(=(1),L),time(list_sums(L,[A,B])).
% 703 inferences, 0.000 CPU in 0.000 seconds (100% CPU, 3426895 Lips)
L = [1, 1, 1, 1, 1, 1, 1, 1, 1|...],
A = 0,
B = 100.
However, due to the use of is/2 this is only working in one direction. If you'd like to use the predicate in the other direction as well, you could opt to use CLP(FD). In that case include the line
:- use_module(library(clpfd)).
in your source file and replace all occurrences of is/2 in list_sums_/3
by #=/2:
list_sums_([],[E,O],E-O).
list_sums_([X|Xs],S,E0-O0) :-
M #= X mod 2,
if_(M=0,(E1 #= E0+X, O1 #= O0),(E1 #= E0, O1 #= O0+X)),
list_sums_(Xs,S,E1-O1).
Your example query still yields the same result and the example from the comments terminates in an acceptable time:
?- length(L,100),maplist(=(1),L),time(list_sums(L,[A,B])).
% 18,928 inferences, 0.004 CPU in 0.004 seconds (99% CPU, 4888152 Lips)
L = [1, 1, 1, 1, 1, 1, 1, 1, 1|...],
A = 0,
B = 100.
But the predicate works in both directions now. In some cases Prolog can find concrete answers without further ado:
?- list_sums([A,B],[2,1]).
A = 2,
B = 1 ;
A = 1,
B = 2 ;
false.
In other cases you get residual goals as an answer:
?- L=[A,B,C,D,E,F], list_sums(L,[12,22]).
L = [A, B, C, D, E, F],
A+B#=_G3306,
A mod 2#=0,
B mod 2#=0,
_G3306+C#=_G3342,
C mod 2#=0,
_G3342+D#=12,
D mod 2#=0,
E+F#=22,
E mod 2#=_G3402,
F mod 2#=_G3414,
_G3414 in 0..1,
dif(_G3414, 0),
_G3402 in 0..1,
dif(_G3402, 0) ;
...
In these cases you can restrict the elements of the list to some interval and use label/1 to get concrete numbers as solution. For example, you can ask for solutions with six numbers from zero to seven and Prolog will give you all 300 solutions:
?- length(L,6), L ins 0..7, list_sums(L,[12,22]), label(L).
L = [6, 6, 1, 7, 7, 7] ;
L = [6, 6, 3, 5, 7, 7] ;
...
You can use a functionnal way :
one_sum(X, [SE,SO], [SE1, SO1]) :-
( X mod 2 =:= 0 ->
SE1 is SE+X, SO1 = SO
; SE1 = SE, SO1 is SO+X).
sum(L, S) :-
foldl(one_sum, L, [0,0], S).

Rotate a matrix in Prolog

How can I rotate a 4 x 4 matrix about its center point in Prolog ? I can simply rearrange the elements in case of 4 x 4 matrix but how to do this for a general case like N x N ?
What you want is not quite matrix transposition... but almost!
:- use_module(library(clpfd)).
matrix_rotated(Xss, Zss) :-
transpose(Xss, Yss),
maplist(reverse, Yss, Zss).
Sample query:
?- matrix_rotated([[a1,a2,a3,a4],
[b1,b2,b3,b4],
[c1,c2,c3,c4]], Xss).
Xss = [[c1,b1,a1],
[c2,b2,a2],
[c3,b3,a3],
[c4,b4,a4]].
Someone is wrong on the internet, so duty calls.
We must obey Cunningham's Law, after all.
This answer makes good use of library(clpfd) as found in SWI-Prolog.
:- use_module(library(clpfd)).
rotate_clockwise(Matrix, N, Rotated) :-
N_mod_4 #= N mod 4,
rotate_clockwise_(N_mod_4, Matrix, Rotated).
rotate_clockwise_(0, M, M).
rotate_clockwise_(1, M, R) :-
transpose(M, R0),
maplist(reverse, R0, R).
rotate_clockwise_(2, M, R) :-
reverse(M, R0),
maplist(reverse, R0, R).
rotate_clockwise_(3, M, R) :-
transpose(M, R0),
reverse(R0, R).
You can rotate a rectangular matrix by flipping it twice (try it out with a book or something).
Depending on the two axes along which you flip, you get one of the 3 non-trivial rotations: if we agree that "one rotation" is 90 degrees clockwise, then you can rotate 0, 1, 2, or 3 times. In the code above:
flip along horizontal axis is reverse
flip along vertical axis is maplist(reverse)
flip along the top-left-lower-right axis is transpose
As to why not just define rotating once 90 degrees clockwise and then rotate multiple times: well, it is actually more code!
With the definition above, no matter what valid arguments we give to rotate_clockwise/3, it does the right rotation, doesn't do unnecessary flips, and keeps the caller code short.
?- rotate_clockwise([[a,b,c],[d,e,f]], -1, R). % once counter-clockwise
R = [[c, f], [b, e], [a, d]].
?- rotate_clockwise([[a,b,c],[d,e,f]], 2, R). % 180 degrees
R = [[f, e, d], [c, b, a]].
?- rotate_clockwise([[a,b,c],[d,e,f]], 168, R). % rotate once each hour, for a week
R = [[a, b, c], [d, e, f]].
?- rotate_clockwise([[a,b,c],[d,e,f]], N, R). % enumerate all possibilities
R = [[a, b, c], [d, e, f]],
N mod 4#=0 ;
R = [[d, a], [e, b], [f, c]],
N mod 4#=1 ;
R = [[f, e, d], [c, b, a]],
N mod 4#=2 ;
R = [[c, f], [b, e], [a, d]],
N mod 4#=3.
?- Matrix = [[a],[b]],
rotate_clockwise(Matrix, -1, R),
rotate_clockwise(Matrix, 3, R). % those two mean the same
Matrix = [[a], [b]],
R = [[a, b]].
as noted, transpose/2 isn't the right solution. I've coded something (maybe a bit too much general), that allows to specify the amount of rotation in term of number of cells to shift to right. Shift defaults to 1, but then I noted that to get 90° rotations, the shift is decreasing while passing to inner frames. Passing an anonymous variable to matrix_rotate/3 has the effect of using the current inner frame size. Then, it rotates 90° clockwise.
/** <module> matrix_rotate
*
* answer to http://stackoverflow.com/questions/35594027/rotate-a-matrix-in-prolog
* --------
*
* source file /home/carlo/prolog/matrix_rotate.pl
* created at mer feb 24 16:43:50 2016
*
* #author carlo
* #version 0.9.9
* #copyright carlo
* #license LGPL v2.1
*/
:- module(matrix_rotate,
[matrix_rotate/2
,matrix_rotate/3
,matrix_allocate/4
,matrix_row_col_element/4
,rowcol/3
]).
:- meta_predicate matrix_allocate(3, +,+,-).
matrix_allocate(Pred, NRows, NCols, Mat) :-
bagof(Vs, Row^(
between(1, NRows, Row),
bagof(C, Col^(between(1, NCols, Col), call(Pred, Row, Col, C)), Vs)
), Mat).
empty(_R,_C,_).
rowcol(R, C, (R,C)).
matrix_rotate(Mat, Rot) :-
matrix_rotate(Mat, 1, Rot).
matrix_rotate(Mat, Shift, Rot) :-
matrix_is_square(Mat, Size),
matrix_allocate(empty, Size, Size, Rot),
frames_shift(Mat, Shift, 1, Rot),
( Size mod 2 =:= 1
-> Cen is Size // 2 + 1,
matrix_row_col_element(Mat, Cen, Cen, E),
matrix_row_col_element(Rot, Cen, Cen, E)
; true
).
frames_shift(Mat, Shift, Frame, Rot) :-
length(Mat, Size),
Frame =< Size // 2,
( integer(Shift)
-> ActualShift = Shift
; ActualShift is Size - (Frame - 1)*2 - 1
),
frame(Mat, Frame, L),
shift_right(L, ActualShift, S),
frame(Rot, Frame, S),
F is Frame+1,
!, frames_shift(Mat, Shift, F, Rot).
frames_shift(_Mat, _Shift, _Frame, _Rot).
matrix_is_square(Mat, Size) :-
length(Mat, Size),
forall(member(Row, Mat), length(Row, Size)).
matrix_row_col_element(Mat, Row, Col, El) :-
nth1(Row, Mat, Cells),
nth1(Col, Cells, El).
shift_right(List, Shift, Shifted) :-
length(Post, Shift),
append(Pre, Post, List),
append(Post, Pre, Shifted).
frame(Mat, N, Frame) :-
length(Mat, S),
T is N, B is S-N+1,
L is N, R is S-N+1,
matrix_range_elements(Mat, T,T, L,R-1, Top),
matrix_range_elements(Mat, T,B-1, R,R, Right),
matrix_range_elements(Mat, B,B, R,L+1, Bottom),
matrix_range_elements(Mat, B,T+1, L,L, Left),
append([Top, Right, Bottom, Left], Frame).
matrix_range_elements(Mat, RStart, RStop, CStart, CStop, Elems) :-
bagof(E, matrix_element_between(Mat, RStart, RStop, CStart, CStop, E), Elems).
matrix_element_between(Mat, RStart, RStop, CStart, CStop, Elem) :-
signed_between(RStart, RStop, R),
signed_between(CStart, CStop, C),
matrix_row_col_element(Mat, R, C, Elem).
signed_between(Start, Stop, I) :-
A is Start, B is Stop,
( B < A -> between(B, A, N), I is A+B-N ; between(A, B, I) ).
This snippets highlights some general pattern useful while processing matrices as list of lists. And some of the difficulties, too...
Example usage:
?- matrix_allocate(rowcol,4,4,M),matrix_rotate(M,_,R),maplist(writeln,R).
[(4,1),(3,1),(2,1),(1,1)]
[(4,2),(3,2),(2,2),(1,2)]
[(4,3),(3,3),(2,3),(1,3)]
[(4,4),(3,4),(2,4),(1,4)]
M = [[(1, 1), (1, 2), (1, 3), (1, 4)], [(2, 1), (2, 2), (2, 3), (2, 4)], [(3, 1), (3, 2), (3, 3), (3, 4)], [(4, 1), (4, 2), (4, 3), (4, 4)]],
R = [[(4, 1), (3, 1), (2, 1), (1, 1)], [(4, 2), (3, 2), (2, 2), (1, 2)], [(4, 3), (3, 3), (2, 3), (1, 3)], [(4, 4), (3, 4), (2, 4), (1, 4)]].
?- matrix_allocate(rowcol,3,3,M),matrix_rotate(M,_,R),maplist(writeln,R).
[(3,1),(2,1),(1,1)]
[(3,2),(2,2),(1,2)]
[(3,3),(2,3),(1,3)]
M = [[(1, 1), (1, 2), (1, 3)], [(2, 1), (2, 2), (2, 3)], [(3, 1), (3, 2), (3, 3)]],
R = [[(3, 1), (2, 1), (1, 1)], [(3, 2), (2, 2), (1, 2)], [(3, 3), (2, 3), (1, 3)]].

Prolog: Putting elements in a list for a decimal to binary conversion

Hello I was trying to modify a decimal to binary conversion function, so that it would display the results in a list. I'm new to prolog and I can't seem to get it to function properly.
dec2bin(0,0).
dec2bin(1,1).
dec2bin(N,L):- N>1,X is N mod 2,Y is N//2, dec2bin(Y,L1), L = [L1|[X]].
Then this is the result:
86 ?- dec2bin(26,L).
L = [[[[1, 1], 0], 1], 0]
Can someone help me understand what it is that I'm doing wrong.
Thanks
if you amend your code
dec2bin(0,[0]).
dec2bin(1,[1]).
dec2bin(N,L):-
N > 1,
X is N mod 2,
Y is N // 2,
dec2bin(Y,L1),
L = [X|L1].
you will get your solution with bits in reverse order:
?- dec2bin(26,L).
L = [0, 1, 0, 1, 1]
Instead of appending each bit, consider a final reverse/2, or invert the order by means of an accumulator
dec2bin(N,L) :- dec2bin(N,[],L).
dec2bin(0,L,[0|L]).
dec2bin(1,L,[1|L]).
dec2bin(N,L,R):-
N > 1,
X is N mod 2,
Y is N // 2,
dec2bin(Y,[X|L],R).
You have to apply some list concatenation, but you are just creating two terms lists and nesting them with L = [L1|[X]] when you consider L1 to be just a number.
If you consider it as a list, you can simply appending to it the newly created X, but to do so you have to rewrite the base cases of your recursion:
dec2bin(0,[0]).
dec2bin(1,[1]).
dec2bin(N,L):-
N > 1,
X is N mod 2,
Y is N // 2,
dec2bin(Y,L1),
append(L1, [X], L).
yielding to:
?- dec2bin(26,L).
L = [1, 1, 0, 1, 0]
where append/3 can be a library predicate or your own implementation.