힐버트-커브 매트릭스


19

이 질문에서 영감을 얻은

2D 이미지를 1D 문자열로 언 롤링하는 또 다른 방법은 Hilbert Curve 를 사용하는 것 입니다.

이 곡선에는 계산 중에 사용 된 반복 횟수에 따라 여러 버전이 있습니다. 아래는 1 차에서 5 차까지 힐버트 곡선의 예입니다.

여기에 이미지 설명을 입력하십시오

이 곡선을 계산하는 방법은 다음과 같습니다. 먼저 1 차 힐버트 곡선을 그림에 표시된 것과 같이 정의합니다 (n = 1의 경우). 1x1 정사각형에 맞습니다. 우리는이 곡선의 복사본을 4x4 정사각형으로 4 개 복사하여 모두 왼쪽으로 "움푹 들어간 곳"을 나타냅니다. 그런 다음 가장 왼쪽에있는 1 개의 커브를 뒤집어 맨 위의 오목한 부분이 위쪽을 향하고 아래쪽의 아래쪽이 아래쪽을 향하도록합니다. 마지막으로 인접한 힐버트 커브의 모서리를 연결합니다. (n + 1) 차수 곡선을 얻으려면 4 개의 n 차수 곡선으로 프로세스를 반복하면됩니다. 여기서 프로세스의 시각화를 볼 수 있습니다 (프로세스를 자세히 설명하는 이미지도 추가하겠습니다).

이 과제의 임무는 해당 행렬에 대해 가장 낮은 차수의 힐버트 곡선 을 따라 정수 행렬을 풀어 내는 것입니다.

간단히하기 위해 행렬의 왼쪽 상단부터 시작하여 곡선을 만듭니다.

정수 목록으로 입력을 수신 할 수 있습니다. 여기서 각 하위 목록은 행렬의 행을 나타냅니다.

입력이 제곱 행렬 (n * n)이라고 가정 할 수 있습니다.

예를 들면 다음과 같습니다.

입력:

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

산출:

[ 1, 2, 4, 3 ]

그림에 표시된 1 차 힐버트 커브를 사용하고 있기 때문에

입력:

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

산출:

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

2 차 힐버트 커브 사용

평소와 같이 표준 허점은 허용되지 않습니다.

이것은 코드 골프이므로 바이트 단위의 최단 답변이 이깁니다.



@StewieGriffin 확실히, 나는 그것에있어
WizardOfMenlo

1
@StewieGriffin 간단한 요약을 추가했습니다. 수업을 마친 후 다음 시간 정도 더 철저한 작업을 수행합니다
WizardOfMenlo

행렬은 정사각형 일뿐만 아니라 n 의 2의 제곱이어야합니다.
mbomb007

답변:


5

MATL , 86 85 바이트

이 솔루션은 복잡한 숫자를 사용하여 힐버트 곡선을 생성하는 Jonas Lundgren의 파일 교환 항목 을 기반으로 합니다. 그런 다음이 복소수는 인덱스 값으로 변환되어 곡선을 따르는 행렬의 요소를 검색합니다.

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

온라인으로 사용해보십시오!

설명

%--- 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 나는 이것을 처리하는 더 좋은 방법을 찾고 있습니다. 우아함과는 거리가 멀다! 포인터 주셔서 감사합니다. 업데이트!
Suever

나는이 특정 도전을 조사하지 않았습니다. 때때로 클립 보드를 피할 수 없습니다
Luis Mendo

5

APL (Dyalog Unicode) , 41 바이트 SBCS

APL 오차드, 특히 @ngn 및 @ Sherlock9의 지혜를 참고하여 30 바이트 (!)를 절약했습니다.

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

온라인으로 사용해보십시오!

다음과 같이 설명하십시오.

{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.

"모 노드 전치 스캔 " 에 대한 자세한 내용 .

오류 가드 에 대한 Dyalog 설명서 .


3

Mathcad, 302 바이트

아래의 Mathcad 프로그램은 @ Sherlock9 Python 프로그램을 기반으로합니다. 행렬 경계 외부에있는 힐버트 곡선의 부분을 무시하여 직사각형 행렬을 곡선 화함으로써 다릅니다. Mathcad는 문자열 처리가 상대적으로 열악하므로 Hilbert 함수에서 Lindenmayer 기호를 정수로 매핑했습니다.

여기에 이미지 설명을 입력하십시오

Mathcad는 사용자가 수학 표현, 플롯, 텍스트, 입력 및 출력을 배치 (및 자유롭게 혼합) 할 수있는 2D 인터페이스를 통해 작동합니다. 바이트를 최소 사용자 키보드의 동등한 작업과 동일하게하여 기호를 만듭니다 (예 : 정의 연산자 (: =)는 단순히 :를 입력하여 입력합니다).


3

파이썬 3 327 289 275 271 239 234 바이트

이것은에서 수정 솔루션 I입니다 내 대답은 또 다른 힐버트 곡선 질문에 대한 여기 . 모든 골프 팁을 부탁드립니다.

편집 :g 증가 및 감소 방법 이 변경되었습니다 . 이제 eval()와를 사용 str.translate합니다. 더 이상 사용하지 않습니다 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

언 골프 드 :

# 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

볼프람-233

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}}]]

Mathematica가없는 사용자를 위해 작동하는 스크린 샷을 게시 할 수 있습니까?
WizardOfMenlo

2
"Wolfram"이 Mathematica와 다른가요? 그렇지 않은 경우 Mathematica라고합니다.
mbomb007

@WizardOfMenlo 여기 온라인
swish

@swish 웹 응용 프로그램의 권한을 변경해야한다고 생각합니다. 차단 된 것 같습니다
WizardOfMenlo

@ mbomb007 Wolfram은 언어 의 이름 이고 Mathematica는 IDE와 같습니다.
Swish

1

루비, 224 (221) 216 바이트

이 답변은 내 파이썬 답변을 기반으로 합니다.

->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}

풀기 :

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

CJam, 60

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

온라인으로 사용해보십시오

설명:

프랙탈을 일련의 이동 방향으로 만듭니다. 0 = 오른쪽, 1 = 아래쪽, 2 = 왼쪽, 3 = 위.

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.