Hilbert-Curvify a Matrix


19

この質問に触発された

2D画像を1D文字列に展開する別の方法は、ヒルベルト曲線を使用することです。

計算中に使用される反復回数に応じて、この曲線には多くのバージョンがあります。以下は、1次から5次までのヒルベルト曲線の例です。

ここに画像の説明を入力してください

この曲線の計算方法は次のとおりです。最初に、図に示されているもの(n = 1の場合)として1次ヒルベルト曲線を定義し、1x1の正方形に収まるようにします。次に、この曲線の4つのコピーを作成し、それらを4x4の正方形に間隔を空けて、すべてが左側に向かって「凹面」を示すようにします。次に、2つの左端の次数1の曲線を反転し、上の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簡単な要約を追加しました。レッスンを終えた後、次の1時間かそこらでより徹底的な仕事をします
WizardOfMenlo

マトリックスは正方形いずれかで、それはまた、必要ではないだけが必要であるN 2の累乗であること
mbomb007

回答:


5

MATL86 85バイト

このソリューションは、複素数を使用してヒルベルト曲線を生成するJonas LundgrenのFile Exchangeエントリに基づいています。次に、これらの複素数はインデックス値に変換され、曲線に沿ったマトリックスの要素が取得されます。

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

この特定の課題については検討していません。クリップボードを避けることができない場合があります
ルイスメンドー

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インターフェイスを介して機能します。シンボルを作成するための最小のユーザーキーボードの同等の操作に1バイトを割り当てました(たとえば、定義演算子(:=)は:を入力するだけで入力されます)。


3

Pythonの3、327の 289 275 271 239 234バイト

これは、ここで別のヒルベルト曲線の質問に対する答えから修正したソリューションです。ゴルフのヒントは大歓迎です。

編集: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私はブロックされているように見える、あなたはWebアプリケーションの権限を変更する必要があると思う
WizardOfMenlo

@ mbomb007 Wolframは言語の名前であり、MathematicaはIDEのようなものです。
スウィッシュ

1

ルビー、224 221 216バイト

この回答は、Pythonの回答に基づいています

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