希尔伯特-求矩阵


19

受启发 问题

将2D图像展开为1D字符串的另一种方法是使用 希尔伯特曲线。

该曲线有很多版本,具体取决于计算时使用的迭代次数。下面是从一阶到五阶的希尔伯特曲线示例。

在此处输入图片说明

计算该曲线的方法如下。首先,我们将一阶希尔伯特曲线定义为图中所示的那条曲线(n = 1的曲线),以使其适合1x1的正方形。然后,我们制作该曲线的四个副本,将它们间隔为4x4正方形,以便它们都向左侧呈现“凹面”。然后,我们翻转两条最左侧的1曲线,以使顶部的一个凹面朝向顶部,而底部的凹面朝向底部。最后,我们连接相邻的希尔伯特曲线的角。如果要获得(n + 1)阶曲线,我们只需要对四个n阶曲线重复该过程即可。我们可以在此处看到该过程的可视化(我还将添加一张详细描述该过程的图像)

您在此挑战中的任务是沿着该矩阵的最低阶希尔伯特曲线展开整数矩阵。

为简单起见,我们将从矩阵的左上角开始绘制曲线。

您可以将输入作为整数列表的列表来接收,其中每个子列表代表矩阵的一行。

您可以假定输入将是一个方矩阵(n * n)。

例如:

输入:

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

输出:

[ 1, 2, 4, 3 ]

由于我们使用的是如图所示的一阶希尔伯特曲线

输入:

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

使用二阶希尔伯特曲线

与往常一样,不允许出现标准漏洞。

这是代码高尔夫球,因此最短的答案以字节为单位。



@StewieGriffin当然,我正在接受
WizardOfMenlo

1
@StewieGriffin我添加了一个简短摘要,在完成课程后,我将在下一个小时左右完成更彻底的工作
WizardOfMenlo

矩阵需要不仅是正方形一个,它也需要Ñ是2的幂
mbomb007

Answers:


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

我没有研究这个特定的挑战。有时无法避免使用剪贴板
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的字符串处理相对较差,因此我已将Lindenmayer符号映射为Hilbert函数中的整数。

在此处输入图片说明

Mathcad通过2D界面工作,该界面允许用户放置(并自由混合)数学表达式,曲线图,文本,输入和输出。我已经将一个字节等同于最小用户键盘等效操作来创建符号(例如,只需输入:即可输入定义运算符(:=)。


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

@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

果酱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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.