Bản đồ mèo của Arnold


21

Thử thách

Đưa ra một hình ảnh raster màu * có cùng chiều rộng và chiều cao, xuất ra hình ảnh được biến đổi dưới bản đồ mèo của Arnold . (* xem chi tiết bên dưới)

Định nghĩa

Với kích thước của hình ảnh, Nchúng tôi giả sử rằng tọa độ của một pixel được cho là số giữa 0N-1.

Bản đồ mèo của Arnold sau đó được định nghĩa như sau:

Một pixel tại tọa độ [x,y]được chuyển đến [(2*x + y) mod N, (x + y) mod N].

Đây không là gì ngoài một phép biến đổi tuyến tính trên hình xuyến: Phần màu vàng, tím và xanh lục được ánh xạ trở lại vào hình vuông ban đầu do mod N.

hình dung

Bản đồ này (hãy gọi nó f) có các thuộc tính sau:

  • Nó là tính từ , có nghĩa là có thể đảo ngược: Đó là một phép biến đổi tuyến tính với ma trận [[2,1],[1,1]]. Vì nó có định thức 1và nó chỉ có các mục nguyên, nên nghịch đảo cũng chỉ có các mục nguyên và được đưa ra bởi [[1,-1],[-1,2]], điều này có nghĩa là nó cũng là tính từ trên tọa độ nguyên.

  • Đây là một yếu tố xoắn của nhóm các bản đồ N x Nhình ảnh mô phỏng , điều đó có nghĩa là nếu bạn áp dụng nó đủ nhiều lần, bạn sẽ lấy lại được hình ảnh gốc: f(f(...f(x)...)) = xSố lần bản đồ được áp dụng cho chính nó sẽ được đảm bảo ít hơn hoặc bằng 3*N. Sau đây bạn có thể thấy hình ảnh của một con mèo sau một số ứng dụng lặp đi lặp lại của bản đồ mèo Arnold và một hình ảnh động về một ứng dụng lặp đi lặp lại trông như thế nào:

nhiều ứng dụng lặp đi lặp lại

Chi tiết

  • Chương trình của bạn không nhất thiết phải xử lý hình ảnh, nhưng mảng / ma trận 2D, chuỗi hoặc cấu trúc 2D tương tự cũng được chấp nhận.

  • Không quan trọng là (0,0)điểm của bạn ở phía dưới bên trái hay bên trên bên trái. (Hoặc ở bất kỳ góc nào khác, nếu ngôn ngữ này thuận tiện hơn trong ngôn ngữ của bạn.) Vui lòng chỉ định quy ước bạn sử dụng trong nội dung gửi.

Tủ thử

Ở dạng ma trận ( [1,2,3,4]là hàng trên cùng, 1có chỉ mục (0,0), 2có chỉ mục (1,0), 5có chỉ mục (0,1))

 1     2     3     4
 5     6     7     8
 9    10    11    12
13    14    15    16

maps to:

 1    14    11     8
12     5     2    15
 3    16     9     6
10     7     4    13

 --------------------

 1     2     3
 4     5     6
 7     8     9

 map to:

 1     8     6
 9     4     2
 5     3     7

Như hình ảnh (phía dưới bên trái là (0,0)):


1
Lena tội nghiệp. Tôi hy vọng bạn tiếp tục lặp lại đủ lâu
Luis Mendo

2
Chúng ta có thể lấy kích thước hình ảnh làm đầu vào không? Có phải nó luôn luôn vuông?
xnor

1
Có, hình ảnh luôn luôn vuông và tôi không chắc về kích thước, có điều gì chống lại việc cho phép không?
flawr

Câu trả lời:


10

Thạch , 9 byte

Zṙ"JC$µ2¡

Hãy thử trực tuyến! Các tọa độ như trong câu trả lời.

Giải trình

      µ2¡   Twice:
Z             Transpose, then
 ṙ"           Rotate rows left by
   JC$          0, -1, -2, -3, …, 1-n units.

Cái này bao bọc ma trận theo một hướng, sau đó theo hướng khác.


Thuật toán tuyệt vời!
Greg Martin

7

MATL , 23 byte

tt&n:qt&+&y\tb+&y\b*+Q(

Các (0,0)điểm được trên trái, như trong ví dụ trong văn bản thách thức.

Hãy thử trực tuyến!

Giải trình

Một ma trận trong MATL có thể được lập chỉ mục với một chỉ mục thay vì hai. Điều này được gọi là lập chỉ mục tuyến tính và sử dụng thứ tự chính cột . Điều này được minh họa bằng ma trận 4 × 4 sau, trong đó giá trị ở mỗi mục trùng với chỉ số tuyến tính của nó:

1   5   9  13
2   6  10  14
3   7  11  15
4   8  12  16

Có hai cách tiếp cận tương tự để thực hiện ánh xạ trong thử thách:

  1. Xây dựng một ma trận lập chỉ mục biểu thị ánh xạ nghịch đảo của Arnold trên các chỉ số tuyến tính và sử dụng nó để chọn các giá trị từ ma trận gốc. Đối với trường hợp 4 × 4, ma trận lập chỉ mục sẽ là

     1  8 11 14
    15  2  5 12
     9 16  3  6
     7 10 13  4
    

    nói rằng ví dụ ban đầu 5tại x = 2, y = 1 đi đến x = 3, y = 2. Hoạt động này được gọi là lập chỉ mục tham chiếu : sử dụng ma trận lập chỉ mục để cho biết phần tử nào sẽ chọn từ ma trận gốc. Đây là functon ), có hai đầu vào (trong cấu hình mặc định của nó).

  2. Xây dựng một ma trận lập chỉ mục biểu thị ánh xạ trực tiếp của Arnold trên các chỉ số tuyến tính và sử dụng nó để ghi các giá trị vào ma trận gốc. Đối với trường hợp 4 × 4, ma trận lập chỉ mục sẽ là

     1 10  3 12
     6 15  8 13
    11  4  9  2
    16  5 14  7
    

    nói rằng mục x = 2, y = 1 của ma trận mới sẽ được ghi đè lên mục nhập với chỉ số tuyến tính 10, nghĩa là, x = 3, y = 2. Đây được gọi là lập chỉ mục gán : sử dụng ma trận lập chỉ mục, ma trận dữ liệu và ma trận gốc và ghi dữ liệu lên ma trận gốc tại các chỉ mục được chỉ định. Đây là chức năng (, có ba đầu vào (trong cấu hình mặc định của nó).

Phương pháp 1 đơn giản hơn, nhưng phương pháp 2 hóa ra lại ngắn hơn.

tt     % Take the input implicitly and push two more copies
&n     % Get its size as two (equal) numbers: N, N
:qt    % Push range [0  1 ... N-1] twice. This represents the original x values
&+     % Matrix of all pairwise additions. This represents x+y
&y     % Push a copy of N onto the top of the stack
\      % Modulo. This is the new y coordinate: y_new
t      % Push another copy
b+     % Bubble up the remaining copy of [0 1 ... N-1] and add. This is 2*x+y
&y     % Push a copy of N onto the top of the stack
\      % Modulo. This is the new x coordinate: x_new
b*+    % Bubble up the remaining copy of N, multiply, add. This computes
       % x_new*N+y_new, which is the linear index for those x_new, y_new 
Q      % Add 1, because MATL uses 1-based indexing
(      % Assigmnent indexing: write the values of the original matrix into
       % (another copy of) the original matrix at the entries given by the
       % indexing matrix. Implicitly display the result

5

Toán học, 44 byte

(n=MapIndexed[RotateLeft[#,1-#2]&,#]&)@*n

Một cổng của thuật toán tuyệt vời của Lynn . Có một ký tự 3 byte vô hình, U + F3C7 trong mã hóa UTF-8, trước ký tự cuối cùng ]; Mathematica tái hiện nó như một siêu ký tự T, và nó chuyển vị của một ma trận.

Toán học, 54 byte

Table[#2[[Mod[2x-y-1,#]+1,Mod[y-x,#]+1]],{x,#},{y,#}]&

Hàm không tên lấy hai đối số, một số nguyên dương #và một mảng 2D #2có kích thước #x #và trả về một mảng 2D có hình dạng tương tự. Như trong trường hợp thử nghiệm đã cho, điểm có tọa độ {0,0} nằm ở phía trên bên trái và trục x nằm ngang. Việc thực hiện đơn giản bằng cách sử dụng nghịch đảo [[1,-1],[-1,2]]được đề cập trong câu hỏi, với -1tọa độ đầu tiên để giải thích cho thực tế là các mảng vốn đã được lập chỉ mục 1 trong Mathicala. Nếu chúng ta không được phép lấy kích thước của ma trận làm đối số bổ sung, thì giải pháp này sẽ trở thành chín byte dài hơn (thay thế các chú thích đầu tiên #của các chú #2chó con a=Length@#và tất cả các #s tiếp theo bằng as).


Dang, đánh bại tôi với nó
JungHwan Min

3

Python 2, 89 82 77 73 byte

def f(a):exec'a=[l[-i:]+l[:-i]for i,l in enumerate(zip(*a))];'*2;return a

Đầu vào là danh sách các danh sách
Chuỗi bên trong exec thực hiện chuyển danh sách các danh sách và xoay vòng theo từng danh sách theo chỉ số dòng (0 dựa trên - dòng thứ 3 được xoay 2 lần sang phải).
Quá trình này được thực hiện 2 lần cho đầu vào.

+4 byte sẽ thực hiện chuyển đổi N lần

def f(a,n):exec'a=[l[-i:]+l[:-i]for i,l in enumerate(zip(*a))];'*2*n;return a

2

Haskell, 55 byte

m#n|r<-[0..n-1]=[[m!!mod(2*y-x)n!!mod(x-y)n|x<-r]|y<-r]

Ví dụ sử dụng: [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]] # 4-> [[1,14,11,8],[12,5,2,15],[3,16,9,6],[10,7,4,13]].

0,0là góc trên bên trái. Điều này sử dụng biến đổi nghịch đảo.


1

Python, 69 byte

lambda M:eval("[r[-i:]+r[:-i]for i,r in enumerate(zip(*"*2+"M))]))]")

Một cải tiến về phương pháp chuyển vị và dịch chuyển hai lần của Rod . Áp dụng thao tác M -> [r[-i:]+r[:-i]for i,r in enumerate(zip(*M))]hai lần bằng cách tạo và đánh giá chuỗi

[r[-i:]+r[:-i]for i,r in enumerate(zip(*[r[-i:]+r[:-i]for i,r in enumerate(zip(*M))]))]

Điều này sẽ vượt qua một biến đổi trực tiếp (70 byte), giả sử hình ảnh là hình vuông và chiều dài của nó có thể được lấy làm đầu vào:

lambda M,n:[[M[(2*j-i)%n][(i-j)%n]for i in range(n)]for j in range(n)]

1

Macro ImageJ, 29 byte

v=getPixel((x+y)%w,(2*y+x)%h)
  • Hình ảnh mở của Lena
  • Từ menu Process chọn Math / Macro ...

Điều này không thực hiện f ^ (- 1)? Nó nhận được giá trị pixel ở tọa độ mà nó được cung cấp để di chuyển nó tới. Bạn có thể có nghĩa v=getPixel((2*y-x)%w,(x-y)%h).
Robin Koch

@RobinKoch Cảm ơn, 2*x+yđã đổi thành2*y+x
rahnema1

Đó không phải là những gì tôi viết cũng không phải ý tôi. Bạn cần chuyển đổi ngược lại cho cách tiếp cận của bạn. Đối với f(x,y) = (2x+y, x+y)chuyển đổi nghịch đảo này được mô tả bởi f^(-1) = (x-y, 2y-x). (Nhận xét khác của tôi là sai.) Vì vậy, mã của bạn sẽ bị v=getPixel((x-y)%w,(2*y-x)%h).
Robin Koch

Tôi đã thử nghiệm công thức của mình và kết quả giống như hình ảnh của Lena trong câu hỏi
rahnema1

@RobinKoch Bạn có thể tải xuống ImageJ và kiểm tra cả hai công thức
rahnema1

1

Java, 160

Chơi gôn

int[][]f(int[][]m){int x=0,y,l=m.length,r[][]=new int[l][];for(;x<l;++x)r[x]=new int[l];for(x=0;x<l;++x)for(y=0;y<l;++y)r[(x+y)%l][(2*x+y)%l]=m[y][x];return r;}

Ung dung:

  int[][] f(int[][] m) {
    int x = 0, y, l = m.length, r[][] = new int[l][];
    for (; x < l; ++x) {
      r[x] = new int[l];
    }
    for (x = 0; x < l; ++x) {
      for (y = 0; y < l; ++y) {
        r[(x + y) % l][(2 * x + y) % l] = m[y][x];
      }
    }
    return r;
  }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.