Rotate a matrix in Prolog - list
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)]].
Related
How to calculate distances from coordinates stored in lists
So far I managed to calculate the distances between an Point P(x,y) and a multitude of points stored in a list l = [(x1,y1), (x2,y2), (x3,y3), ...) Here is the code : import math import pprint l = [(1,2), (2,3), (4,5)] p = (3,3) dists = [math.sqrt((p[0]-l0)**2 + (p[1]-l1)**2) for l0, l1 in l] pprint.pprint(dists) Output : [2.23606797749979, 1.0, 2.23606797749979] Now I want to calculate the distances from multitude points in a new list to the points in the list l. I haven't found a solution yet, so does anyone have an idea how this could be done?
Here is a possible solution: from math import sqrt def distance(p1, p2): return sqrt((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2) lst1 = [(1,2), (2,3), (4,5)] lst2 = [(6,7), (8,9), (10,11)] for p1 in lst1: for p2 in lst2: d = distance(p1, p2) print(f'Distance between {p1} and {p2}: {d}') Output: Distance between (1, 2) and (6, 7): 7.0710678118654755 Distance between (1, 2) and (8, 9): 9.899494936611665 Distance between (1, 2) and (10, 11): 12.727922061357855 Distance between (2, 3) and (6, 7): 5.656854249492381 Distance between (2, 3) and (8, 9): 8.48528137423857 Distance between (2, 3) and (10, 11): 11.313708498984761 Distance between (4, 5) and (6, 7): 2.8284271247461903 Distance between (4, 5) and (8, 9): 5.656854249492381 Distance between (4, 5) and (10, 11): 8.48528137423857
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).
How to calculate the outer product of two matrices A and B per rows faster in python (numpy)?
Let say we have two matrices A and B. A has the shape (r, k) and B has the shape (r, l). Now I want to calculate the np.outer product of these two matrices per rows. After the outer product I then want to sum all values in axis 0. So my result matrix should have the shape (k, l). E.g.: Form of A is (4, 2), of B is (4, 3). import numpy as np A = np.array([[0, 7], [4, 1], [0, 2], [0, 5]]) B = np.array([[9, 7, 7], [6, 7, 5], [2, 7, 9], [6, 9, 7]]) # This is the first outer product for the first values of A and B print(np.outer(A[0], B[0])) # This will give me # First possibility is to use list comprehension and then sum1 = np.sum((np.outer(x, y) for x, y in zip(A, B)), axis=0) # Second possibility would be to use the reduce function sum2 = reduce(lambda sum, (x, y): sum+np.outer(x, y), zip(A, B), np.zeros((A.shape[1], B.shape[1]))) # result for sum1 or sum2 looks like this: # array([[ 175., 156., 133.], [ 133., 131., 137.]]) I'm asking my self, is there a better or faster solution? Because when I have e.g. two matrices with more than 10.000 rows this takes some time. Only using the np.outer function is not the solution, because np.outer(A, B) will give me a matrix with shape (8, 12) (this is not what I want). Need this for neural networks backpropagation.
You could literally transfer the iterators as string notation to np.einsum - np.einsum('rk,rl->kl',A,B) Or with matrix-multiplication using np.dot - A.T.dot(B)
Prolog: list of n of n x n matrix
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]].