如何在Prolog中围绕其中心点旋转4 x 4矩阵?我可以在4×4矩阵的情况下简单地重新排列元素,但是如何为像N x N这样的一般情况做到这一点?在Prolog中旋转矩阵
3
A
回答
2
你想要的是倒不矩阵转置...但差不多!
:- use_module(library(clpfd)). matrix_rotated(Xss, Zss) :- transpose (Xss, Yss), maplist (reverse , Yss, Zss).
样品查询:
?- 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]].
1
如上所述,transpose/2不是正确的解决方案。我已经编写了一些东西(可能有点太笼统),它允许根据单元格数量来指定旋转量以向右移动。移位默认为1,但是我注意到为了获得90°旋转,移位在传递到内部帧时正在减小。将匿名变量传递给matrix_rotate/3具有使用当前内部帧大小的效果。然后顺时针旋转90°。
/** <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)).
这段代码突出了一些有用的通用模式,用于处理列表列表中的矩阵。还有一些困难,太...
用法示例:
?- 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)]].
3
有人为wrong on the internet,使值班电话。 毕竟我们必须服从Cunningham's Law。
这个答案充分利用library(clpfd)在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).
可以旋转通过翻转两次的长方形矩阵(尝试一下用一本书或某事)。 根据您翻转的两个轴,您可以得到3个非平凡旋转中的一个:如果我们同意“一次旋转”是顺时针90度,那么您可以旋转0,1,2或3次。在上面的代码:
- 倒装沿着水平轴是
reverse
- 倒装沿着垂直轴是
maplist(reverse)
- 倒装沿左上 - 低级 - 右轴是
transpose
至于为什么不定义顺时针旋转90度,然后多次旋转:嗯,它实际上是更多的代码! 有了上面的定义,无论我们给rotate_clockwise/3
什么有效的参数,它都做正确的旋转,不会做不必要的翻转,并保持呼叫者代码的简短。
?- 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]].
相关问题
- 1. 在Haskell中旋转矩阵
- 2. 旋转矩阵
- 3. C#旋转矩阵
- 4. 旋转矩阵CCW
- 5. AS3矩阵旋转
- 6. WebGl旋转矩阵
- 7. 在python中转置/旋转矩阵块
- 8. Simulink中的旋转矩阵
- 9. Matlab中的旋转矩阵
- 10. Eigen中的旋转矩阵
- 11. 使用matplotlib旋转矩阵使用旋转矩阵
- 12. 优化旋转矩阵 - 关于矩阵
- 13. 从旋转矩阵Y旋转
- 14. 使用旋转矩阵旋转Java中的矩形
- 15. 在gnuplot中从矩阵旋转热图
- 16. 在C++中使用3x3矩阵旋转
- 17. 在Java中旋转矩阵混淆
- 18. 如何在J中旋转矩阵?
- 19. Matlab矩阵旋转,尺寸
- 20. 旋转矩阵问题
- 21. 计算旋转矩阵
- 22. 2x2旋转矩阵(45度)
- 23. 旋转矩阵不正交
- 24. Python旋转矩阵错误
- 25. 椭圆旋转矩阵?
- 26. OpenGL旋转矩阵和ArcBall
- 27. SVG旋转变换矩阵
- 28. 基本矩阵:纯旋转
- 29. 旋转和OpenGL矩阵
- 30. 仿射旋转矩阵
至少要将旋转加180度:'reverse(M,R0),maplist(reverse ,R0,R)'。另外还要区分顺时针和逆时针旋转90度。 –
@Boris。(2)我明白了。你有一个好名字吗? (1)你是什么意思?我用手写下了一个完整的旋转(4步)作为测试用例,'matrix_rotated/2'很好地匹配了。那么为什么第二个“反向”呢? (是的,在我写测试用例之前,我没有写任何代码,欢呼!) – repeat
@Boris。它当然值得!运行时不是我主要关心的问题:“*过早优化是根... *” – repeat