Hilbert-Curvify một ma trận


19

Lấy cảm hứng từ câu hỏi này

Một cách khác để hủy hình ảnh 2D thành chuỗi 1D là sử dụng Hilbert Curve.

Có nhiều phiên bản của đường cong này, tùy thuộc vào số lần lặp được sử dụng trong khi tính toán nó. Dưới đây là ví dụ về Hilbert Curves từ đơn hàng đầu tiên đến đơn hàng thứ năm.

nhập mô tả hình ảnh ở đây

Cách tính đường cong này là như sau. Đầu tiên, chúng tôi xác định thứ tự đầu tiên Hilbert Curve là thứ tự được hiển thị trong hình (một cho n = 1), sao cho nó khớp với hình vuông 1x1. Chúng tôi hơn là tạo ra bốn bản sao của đường cong này, đặt chúng trong một hình vuông 4 x 4, sao cho tất cả chúng đều thể hiện "độ chụm" về phía bên trái. Sau đó, chúng ta lật hai đường cong thứ tự ngoài cùng bên trái 1, sao cho phần trên cùng của mặt phải hướng về phía trên, trong khi phần dưới cùng hướng về phía dưới. Cuối cùng chúng tôi kết nối các góc của Hilbert Curves liền kề. Nếu muốn có được Đường cong thứ tự (n + 1), chúng ta chỉ cần lặp lại quy trình với bốn Đường cong thứ tự n. Chúng ta có thể thấy một hình ảnh trực quan của quá trình ở đây (tôi cũng sẽ thêm một hình ảnh chi tiết quá trình này sớm)

Nhiệm vụ của bạn trong thử thách này là hủy bỏ một ma trận các số nguyên dọc theo đường cong Hilbert bậc thấp nhất cho ma trận đó.

Để đơn giản, chúng ta sẽ có đường cong bắt đầu từ góc trên cùng bên trái của ma trận.

Bạn có thể nhận đầu vào dưới dạng danh sách các số nguyên, trong đó mỗi danh sách phụ đại diện cho một hàng của ma trận.

Bạn có thể giả sử rằng đầu vào sẽ là một ma trận vuông (n * n).

Ví dụ:

Đầu vào:

[[ 1, 2,]
 [ 3, 4 ]]

Đầu ra:

[ 1, 2, 4, 3 ]

Vì chúng ta đang sử dụng thứ tự đầu tiên Hilbert Curve được hiển thị trong hình

Đầu vào:

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

Đầu ra:

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

Sử dụng lệnh thứ hai Hilbert Curve

Như thường lệ, sơ hở tiêu chuẩn không được phép.

Đây là môn đánh gôn, vì vậy câu trả lời ngắn nhất trong byte thắng.



@StewieGriffin chắc chắn, tôi tham gia
WizardOfMenlo 17/03/2016

1
@StewieGriffin Tôi đã thêm một bản tóm tắt ngắn gọn, tôi sẽ thực hiện công việc kỹ lưỡng hơn trong một giờ tới, sau khi kết thúc bài học
WizardOfMenlo 17/03/2016

Ma trận không chỉ cần phải là một hình vuông, mà còn cần n để có sức mạnh bằng 2.
mbomb007 17/03/2016

Câu trả lời:


5

MATL , 86 85 byte

Giải pháp này dựa trên mục nhập Trao đổi tệp của Jonas Lundgren , sử dụng các số phức để tạo đường cong Hilbert. Các số phức này sau đó được chuyển đổi thành các giá trị chỉ mục để lấy các phần tử của ma trận nằm dọc theo đường cong.

nZl2/1XLJQXH1J-XI0,1L:"XJJZj1j*XKKH-JI-JH+IK-,4$h2/]XJJ1L*XJJH+J1)-XHGHXjHYj3$)1$Xd1$

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

Giải trình

%--- Define some numbers to be used throughout ---%
n                   % Retrieve the number of elements in the input matrix
Zl2/                % Compute the order of the curve (log2(numel(i))/2)
1XL                 % Store the order in the 1L clipboard
JQ XH               % Store 1 + j in H clipboard
1J- XI              % Store 1 - j in I clipboard
0                   % Place 0 onto the stack

%--- Compute the hilbert curve ---%
1L:"                % For k = 1:order
    XJ                   % Store the top of the stack (z) in J clipboard
    JZj                  % Compute the conjugate of z (stored in J)
    1j*                  % Multiply by j to get conj(z) * j
    XK                   % Store result in K clipboard
    KH- JI- JH+ IK- 4$h  % Horizontal concatenation of K-H, J-I, J+H, and I-K
    2/                   % Divide entire array by 2
]                   % End for loop
XJ                  % Store z in J clipboard

%----- Convert complex decimal values to complex integer indices ----%
J1L*                % Multiply z by the order
XJ                  % Store result in clipboard J
JH+                 % Add 1 + j to H
J1)-                % Subtract the first element of z
XH                  % Store integer complex numbers in H

%--- Retrieve the elements from the input along the curve ---%  
G HXj HYj 3$)       % Index into input using real/imag components input(real, imag)
                    % This will yield an numel(real) x numel(imag) matrix where 
            % the diagonal values are the values we want
1$Xd                % Extract the diagonals using diag with one input
1$                   % Display only the top element on the stack

@DonMuesli Tôi đang làm việc theo cách tốt hơn để xử lý việc này. Nó chắc chắn là xa thanh lịch! Cảm ơn các con trỏ. Đã cập nhật!
Suever 30/03/2016

Tôi chưa nhìn vào thử thách cụ thể này. Đôi khi không thể tránh được những
tấm

5

APL (Dyalog Unicode) , 41 byte SBCS

Đã lưu 30 byte (!) Bằng cách tham khảo sự khôn ngoan của APL Orchard, đặc biệt là @ngn và @ Sherlock9.

{0::⍵⋄∊∇¨⌽∘⊖¨@4,⌽@1⊢∘⍉\⌽↑∘⍵¨∘.,⍨2 ¯2÷⍨≢⍵}

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

Giải thích như sau:

{0::⍵⋄∊∇¨⌽∘⊖¨@4,⌽@1⊢∘⍉\⌽↑∘⍵¨∘.,⍨2 ¯2÷⍨≢⍵}  Recursive function - takes input as an
                                           n*n square matrix
 0::⍵                                      Our base case - this is an error guard
                                           If there's any error, catch it and
                                          ⍝ return the function's input
                                      ≢⍵   Find the number of rows in the input
                                2 ¯2÷⍨     Divide the above by 2 and negative 2,
                                           resulting in a 2-element vector
                            ∘.,⍨           Outer product - take the above vector and
                                           apply concatenation (,) with each element
                                           against all elements in the vector. Since
                                           we have a 2-element vector, this results in
                                           a 2-by-2 matrix, e.g.
                                           [[(2,2),(22)],[(¯2,2),(¯22)]]
                        ↑∘⍵¨               For each element in the matrix, we apply
                                           "take" against our original input matrix.
                                           Take, given a negative number, will take
                                           elements from the end of a particular rank.
                                           With our argument above, this means that we end
                                           up with our original original input matrix
                                           split by quadrant into a 2-by-2 matrix.
                                           It is also worth noting that take expects
                                           an integer argument, so for matrices whose
                                           rowcount divided by two results in a decimal
                                           (i.e., 1-by-1 matrices), we throw an error
                                           which is caught by the guard above, returning
                                           the original input.
                                          Flip the above matrix about the vertical axis.
                   ⊢∘⍉\                    Apply a "monadic transpose scan". More details
                                           on how this works below, but for our purposes
                                           this applies transpose to each of the two 
                                           sub-matrices on the right half.
                ⌽@1                        Swap the two upper sub-matrices. Given our
                                           flip for the overall matrix above, this returns
                                           the two upper quadrants to their original
                                           positions.
               ,                           Ravel: flatten the 2-by-2 matrix into a
                                           4-element vector
         ⌽∘⊖¨@4                            Take the last element of the list (the lower
                                           right quadrant originally) and flip it
                                           along the vertical and horizontal axes. Given
                                           the transposition above, this has the final
                                           effect of transposition along the antidiagonal.
       ∇¨                                  For each element in the above vector, recurse.
                                          Recursively flatten the results into a single
                                           vector.

Thêm chi tiết về " quét chuyển tiếp đơn âm ".

Tài liệu Dyalog về bảo vệ lỗi .


3

Mathcad, 302 byte

Chương trình Mathcad dưới đây dựa trên chương trình @ Sherlock9 Python. Nó khác nhau bằng cách làm cong các ma trận hình chữ nhật bằng cách bỏ qua các phần của Đường cong Hilbert nằm bên ngoài giới hạn ma trận. Lưu ý rằng vì Mathcad có khả năng xử lý chuỗi tương đối kém, tôi đã ánh xạ các ký hiệu Lindenmayer thành các số nguyên trong hàm Hilbert.

nhập mô tả hình ảnh ở đây

Mathcad hoạt động thông qua giao diện 2D cho phép người dùng đặt (và tự do trộn) các biểu thức toán học, sơ đồ, văn bản, đầu vào và đầu ra. Tôi đã đánh đồng một byte với thao tác tương đương bàn phím người dùng tối thiểu để tạo ký hiệu (ví dụ: toán tử định nghĩa (: =) được nhập bằng cách nhập :.


3

Python 3, 327 289 275 271 239 234 byte

Đây là một giải pháp tôi đã sửa đổi từ câu trả lời của mình cho một câu hỏi khác về đường cong Hilbert ở đây . Bất kỳ lời khuyên chơi golf được đánh giá cao.

Chỉnh sửa: Thay đổi cách gtăng và giảm. Hiện đang sử dụng eval()str.translate. Không còn sử dụng l=len(s).

def h(s):
 t=[s[0][0]];x=y=g=0;b="A"
 for j in range(len(bin(len(s)))-3):b=b.translate({65:"-BF+AFA+FB-",66:"+AF-BFB-FA+"})
 for c in b:g+=(c<"-")-(c=="-");a=c>"B";x,y=[[x,y],[[x+1-g%4,y],[x,y+g%4-2]][g%2]][a];t+=[s[x][y]]*a
 return t

Ung dung:

# the following function is implemented in the code with b=b.translate

def hilbert(it):
    s="A"
    n=""
    for i in range(it):
        for c in s:
            if c == "A":
                n += "-BF+AFA+FB-"
            elif c == "B":
                n += "+AF-BFB-FA+"
            else:
                n += c
        s=n;n=""
    return s

def matrix_to_hilbert(mat):
    length = len(mat)       # this returns the number of rows in the matrix
    if length < 2:
        return mat
    it = len(bin(length)) - 3
    hil = hilbert(it)
    output = [mat[0][0]]    # a list that starts with the first element of the matrix
    x = 0
    y = 0
    heading = 0
    for char in hil:        # navigating the Hilbert curve
        if char == "-": heading += -1
        elif char == "+": heading += 1
        elif char == "F":
            if heading % 4 == 3: y += 1
            elif heading % 4 == 2: x -= 1
            elif heading % 4 == 1: y -= 1
            else: x += 1
            output.append(mat[x][y])
    return output

2

Sói - 233

Dựa trên đại diện như hệ thống Lindenmayer :

f[m_]:=m[[Sequence@@Reverse[#+1]]]&/@DeleteDuplicates@AnglePath[Pi/2,List@@StringReplace[Last@SubstitutionSystem[{"A"->"-BF+AFA+FB-","B"->"+AF-BFB-FA+"},"A",Round@Sqrt@Length@m],{"A"|"B"->"","-"->{0,-Pi/2},"+"->{0,Pi/2},"F"->{1,0}}]]

Bạn có thể đăng một số ảnh chụp màn hình của nó hoạt động, cho người dùng không có Mathicala?
WizardOfMenlo 17/03/2016

2
"Wolfram" có khác với Mathicala không? Nếu không, nó nên được gọi là Mathicala.
mbomb007 17/03/2016

@WizardOfMenlo Ở đây nó đang hoạt động trực tuyến
swish

@swish Tôi nghĩ bạn cần thay đổi sự cho phép của ứng dụng Web, nó dường như bị chặn
WizardOfMenlo 17/03/2016

@ mbomb007 Wolfram là tên của ngôn ngữ , Mathicala giống như một IDE.
swish

1

Ruby, 224 221 216 byte

Câu trả lời này dựa trên câu trả lời Python của tôi .

->s{t=[s[0][0]];x=y=g=0;b=?A;(s.size.bit_length-1).times{b=b.split("").map{|c|c==?A?"-BF+AFA+FB-":c==?B?"+AF-BFB-FA+":c}.join("")};b.each_char{|c|g+=c==?-?-1:c==?+?1:0;(g%2>0?y+=g%4-2:x+=1-g%4;t<<s[x][y])if c==?F};t}

Ungolfing:

def hilbert(mat)
  result = mat[0][0]
  x = 0
  y = 0
  heading = 0
  b = "A"
  (mat.size.bit_length-1).times do each |j| # Hilbert curve using a Lindenmayer system
    a = b.split("").map do |char|
      if char == "A"
        "-BF+AFA+FB-"
      else if char == "B"
        "+AF-BFB-FA+"
      else
        char
      end
    end
    b = a.join("")
  end
  b.each_char do |char| # navigating the matrix
    if char == "-"
      heading += -1
    else if char == "+"
      heading += 1
    else if char == "F"
      if heading % 2 == 0
        y += heading % 4 - 2
      else
        x += 1 - heading % 4
      end
      result << s[x][y]
    end
  return result
  end

1

Camam, 60

Lq~:A,2mL{:B1f^0B1B2B3f^]:+}*1+{AT=U=\2md'U^_~)@2*-':@+~;}%p

Dùng thử trực tuyến

Giải trình:

Tôi đang xây dựng fractal như một chuỗi các hướng di chuyển: 0 = phải, 1 = xuống, 2 = trái, 3 = lên.

L          push an empty array (level 0 fractal)
q~:A       read the input, evaluate and store in A
,2mL       get the length (number of rows) and calculate the logarithm in base 2
            (to get the desired level)
{…}*       repeat <level> times
  :B       store the previous-level fractal in B
  1f^      XOR it with 1 (top-left part)
  0        (move right)
  B        copy the fractal (top right part)
  1        (move down)
  B        copy the fractal (bottom right part)
  2        (move left)
  B3f^     copy the fractal and XOR it with 3 (bottom left part)
  ]:+      put everything in an array and concatenate the parts
1+         add a dummy move (needed for the last step)
{…}%       apply to each direction in the array
  AT=U=    push A[T][U] (T and U are initially 0)
  \2md     bring the direction to the top and get the quotient and remainder mod 2
  'U^      XOR the 'U' character with the remainder,
            to get the variable we want to modify
  _~)      make a copy of it, then evaluate it and increment
  @2*-     bring the quotient to the top, multiply by 2 and subtract
  ':@+     concatenate ':' with the variable name
  ~;       evaluate (this updates the variable) and pop the result
p          pretty-print the resulting array
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.