Hilbert-Curvify a Matrix


19

Ispirato da questa domanda

Un altro modo per srotolare un'immagine 2D in una stringa 1D è utilizzare una curva di Hilbert.

Esistono molte versioni di questa curva, a seconda del numero di iterazioni utilizzate durante il calcolo. Di seguito segui l'esempio delle curve di Hilbert dal primo al quinto ordine.

inserisci qui la descrizione dell'immagine

Il modo di calcolare questa curva è il seguente. Per prima cosa definiamo il primo ordine di Hilbert Curve come quello mostrato in figura (quello per n = 1), in modo che si adatti a un quadrato 1x1. Dobbiamo quindi fare quattro copie di questa curva, spaziandole in un quadrato 4x4, in modo che presentino tutti la "concavità" verso il lato sinistro. Quindi capovolgiamo le due curve 1 all'ordine più a sinistra, in modo che la concavità superiore sia rivolta verso l'alto, mentre quella inferiore è rivolta verso il basso. Finalmente colleghiamo gli angoli delle curve di Hilbert adiacenti. Se si desidera ottenere una curva di ordine (n + 1), è sufficiente ripetere il processo con quattro curve di ordine n. Possiamo vedere una visualizzazione del processo qui (aggiungerò presto anche un'immagine che dettaglia il processo)

Il tuo compito in questa sfida è srotolare una matrice di numeri interi lungo la curva di Hilbert di ordine più basso per quella matrice.

Per semplicità, avremo la curva a partire dall'angolo in alto a sinistra della matrice.

È possibile ricevere l'input come un elenco di un numero intero, in cui ciascun elenco secondario rappresenta una riga della matrice.

Si può presumere che l'input sarà una matrice quadrata (n * n).

Per esempio:

Ingresso:

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

Produzione:

[ 1, 2, 4, 3 ]

Dal momento che stiamo usando il primo ordine di Hilbert Curve mostrato in figura

Ingresso:

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

Produzione:

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

Utilizzando il secondo ordine di Hilbert Curve

Come al solito, non sono consentite scappatoie standard.

Questo è code-golf, quindi vince la risposta più breve in byte.



@StewieGriffin certo, ci sono io
WizardOfMenlo

1
@StewieGriffin Ho aggiunto un breve riassunto, farò un lavoro più approfondito entro circa un'ora, dopo aver terminato le lezioni
WizardOfMenlo

Le necessità di matrice non solo essere un quadrato, deve anche n essere una potenza di 2.
mbomb007

Risposte:


5

MATL , 86 85 byte

Questa soluzione si basa sulla voce File Exchange di Jonas Lundgren che utilizza numeri complessi per generare la curva di Hilbert. Questi numeri complessi vengono quindi convertiti in valori di indice per recuperare gli elementi della matrice che cadono lungo la curva.

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

Provalo online!

Spiegazione

%--- 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 Sto lavorando a un modo migliore per gestirlo. È decisamente tutt'altro che elegante! Grazie per i suggerimenti. Aggiornato!
Suever,

Non ho esaminato questa sfida specifica. A volte gli Appunti non possono essere evitati
Luis Mendo il

5

APL (Dyalog Unicode) , 41 byte SBCS

Risparmiato 30 byte (!) Consultando la saggezza del frutteto APL, in particolare @ngn e @ Sherlock9.

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

Provalo online!

Spiegazione come segue:

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

Maggiori dettagli su " scansione trasposizione monadica ".

Documentazione Dyalog sulle protezioni errori .


3

Mathcad, 302 byte

Il seguente programma Mathcad si basa sul programma @ Sherlock9 Python. Si differenzia curvando le matrici rettangolari ignorando quelle parti della curva di Hilbert che si trovano al di fuori dei limiti della matrice. Si noti che poiché Mathcad ha una gestione delle stringhe relativamente scarsa, ho mappato i simboli Lindenmayer su numeri interi nella funzione Hilbert.

inserisci qui la descrizione dell'immagine

Mathcad funziona attraverso un'interfaccia 2D che consente all'utente di posizionare (e mescolare liberamente) espressioni matematiche, grafici, testo, input e output. Ho equiparato un byte all'operazione minima equivalente della tastiera dell'utente per creare un simbolo (ad esempio, l'operatore di definizione (: =) viene inserito semplicemente digitando:.


3

Python 3, 327 289 275 271 239 234 byte

Questa è una soluzione che ho modificato dalla mia risposta per un'altra domanda sulla curva di Hilbert qui . Tutti i suggerimenti per il golf sono apprezzati.

Modifica: modificato il modo in cui gviene incrementato e decrementato. Ora usando eval()e str.translate. Non più in uso 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

Wolfram - 233

Basato sulla rappresentazione come sistema 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}}]]

Potresti pubblicare alcuni screenshot funzionanti, per gli utenti che non hanno Mathematica?
WizardOfMenlo

2
"Wolfram" è diverso da Mathematica? In caso contrario, dovrebbe essere chiamato Mathematica.
mbomb007,

@WizardOfMenlo Qui funziona online
swish

@swish Penso che sia necessario modificare l'autorizzazione dell'app Web, sembra bloccata
WizardOfMenlo

@ mbomb007 Wolfram è il nome della lingua , Mathematica è come un IDE.
Swish

1

Rubino, 224 221 216 byte

Questa risposta si basa sulla mia risposta 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}

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

Provalo online

Spiegazione:

Sto costruendo il frattale come una serie di direzioni di movimento: 0 = destra, 1 = giù, 2 = sinistra, 3 = su.

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.