Hilbert-Matrisin Eğrilmesi


19

Bu sorudan ilham alındı

Bir 2D görüntüyü 1D dizesine açmak için başka bir yol Hilbert Curve kullanmaktır .

Hesaplarken kullanılan yineleme sayısına bağlı olarak, bu eğrinin birçok sürümü vardır. Aşağıda Hilbert Curves örneğini birinci dereceden beşinci dereceye kadar takip edin.

resim açıklamasını buraya girin

Bu eğriyi hesaplamanın yolu şudur. İlk olarak Hilbert Curve ilk sırasını 1x1 kareye sığacak şekilde şekilde gösterildiği gibi (n = 1 için olan) olarak tanımlarız. Bu eğrinin dört kopyasını, 4x4 kareye yerleştirerek, sol tarafa doğru "içbükeyliği" sunacak şekilde kopyalarız. Daha sonra en soldaki iki sıra 1 eğrisini ters çeviririz, böylece üstteki içbükeylik üste, alt kısım alttan aşağı bakar. Sonunda bitişik Hilbert Eğrilerinin köşelerini birleştiriyoruz. Eğer (n + 1) -düzeyli bir Eğri elde etmek istiyorsanız, işlemi sadece dört n-dereceli Eğri ile tekrarlamamız gerekir. Biz sürecin bir görselleştirme görebilirsiniz burada (yakında ben de süreci ayrıntılı olarak gösteren bir görüntü katacak)

Bu görevdeki göreviniz, bu matris için en düşük sıralı Hilbert Curve boyunca bir tamsayı matrisini açmaktır .

Basitlik adına, matrisin sol üst köşesinden başlayan eğriye sahip olacağız.

Girdiyi, her bir alt listenin matrisin bir satırını temsil ettiği tamsayıların bir listesi olarak alabilirsiniz.

Girişin bir kare matris (n * n) olacağını varsayabilirsiniz.

Örneğin:

Giriş:

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

Çıktı:

[ 1, 2, 4, 3 ]

Şekilde gösterilen birinci dereceden Hilbert Curve kullandığımız için

Giriş:

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

Çıktı:

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

İkinci dereceden Hilbert Curve kullanımı

Her zamanki gibi standart boşluklara izin verilmez.

Bu kod golf, bu yüzden bayttaki en kısa cevap kazanır.



@StewieGriffin eminim, üzereyim
WizardOfMenlo

1
@StewieGriffin Kısa bir özet ekledim, dersleri bitirdikten sonra önümüzdeki bir saat içinde daha kapsamlı bir iş yapacağım
WizardOfMenlo

Matrisin sadece bir kare olması değil, aynı zamanda n'nin 2 gücü olması gerekir.
mbomb007

Yanıtlar:


5

MATL , 86 85 bayt

Bu çözüm, Jonas Lundgren'in Hilbert eğrisini oluşturmak için karmaşık sayılar kullanan Dosya Değişimi girişine dayanmaktadır . Bu karmaşık sayılar daha sonra eğri boyunca düşen matris elemanlarını almak için indeks değerlerine dönüştürülür.

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

Çevrimiçi deneyin!

açıklama

%--- 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 Bunu halletmenin daha iyi bir yolu üzerinde çalışıyorum. Kesinlikle zarif olmaktan uzak! İşaretçiler için teşekkürler. Güncellenmiş!
Suever

Bu özel zorluğa bakmadım. Bazen
panolardan

5

APL (Dyalog Unicode) , 41 bayt SBCS

APL Orchard'ın bilgeliğine, özellikle @ngn ve @ Sherlock9'a danışarak 30 bayt (!) Tasarruf sağladı.

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

Çevrimiçi deneyin!

Aşağıdaki gibi açıklama:

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

" Monadik transpoze tarama " hakkında daha fazla bilgi .

Hata korumaları hakkında dyalog belgeleri .


3

Mathcad, 302 bayt

Aşağıdaki Mathcad programı @ Sherlock9 Python programını temel almaktadır. Hilbert Curve'un matris sınırlarının dışında kalan kısımlarını göz ardı ederek dikdörtgen matrisleri kıvrılarak farklılaşır. Mathcad nispeten zayıf dize işleme sahip olduğu için, Lindenmayer sembollerini Hilbert işlevindeki tamsayılarla eşleştirdim.

resim açıklamasını buraya girin

Mathcad, kullanıcının matematiksel ifadeleri, grafikleri, metni, girişleri ve çıktıları yerleştirmesini (ve serbestçe karıştırmasını) sağlayan bir 2D arabirim aracılığıyla çalışır. Bir sembol oluşturmak için minimum kullanıcı klavyesi eşdeğer işlemine bir bayt eşitledim (örneğin, tanım operatörü (: =) basitçe: yazarak girilir.


3

Python 3, 327 289 275 271 239 234 bayt

Bu modifiye edilen bir çözüm I benim cevap başka Hilbert eğrisi soru için buraya . Herhangi bir golf ipuçları takdir edilmektedir.

Düzenleme: Nasıl gartırılır ve azaltılır. Şimdi eval()ve str.translate. Artık kullanılmıyor 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

Ungolfed:

# 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

Volfram - 233

Lindenmayer sistemi olarak temsile dayanarak :

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'ya sahip olmayan kullanıcılar için bazı ekran görüntülerini yayınlayabilir misiniz?
WizardOfMenlo

2
"Wolfram" Mathematica'dan farklı mıdır? Değilse, Mathematica olarak adlandırılmalıdır.
mbomb007

@WizardOfMenlo Burada çalışıyor Online
homoseksüel

@swish Web uygulamasının iznini değiştirmeniz gerektiğini düşünüyorum, engellenmiş gibi görünüyor
WizardOfMenlo

@ mbomb007 Wolfram dilin adı , Mathematica bir IDE gibi.
swish

1

Yakut, 224 221 216 bayt

Bu cevap Python cevabımı temel alıyor .

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

CJam, 60

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

Çevrimiçi deneyin

Açıklama:

Fraktali bir dizi hareket yönü olarak inşa ediyorum: 0 = sağ, 1 = aşağı, 2 = sol, 3 = yukarı.

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.