找到身份沙堆


18

这个问题是关于阿贝尔沙堆的。阅读此先前的挑战,观看此亲密视频以了解更多信息。


大小为n × n的阿贝尔沙堆是一个包含数字0、1、2和3(代表沙粒数量)的网格。添加两个沙堆的工作方式是:先逐个元素地添加元素,然后对高于3的任何元素进行推倒。推倒的顺序无关紧要,最终结果是相同的。当一个单元倾倒时,其数量减少4,而其每个直接相邻单元的数量增加1。这可能导致链反应。如果单元格位于网格的边缘,则在倾倒时掉落到网格上的所有颗粒都会消失。

例如,我要添加两个三乘三的沙堆(产生非常极端的连锁反应):

3 3 3   1 2 1   4 5 4    4 6 4    6 2 6    6 3 6    2 5 2    4 1 4    4 2 4    0 4 0    2 0 2    2 1 2
3 3 3 + 2 1 2 = 5 4 5 -> 6 0 6 -> 2 4 2 -> 3 0 3 -> 5 0 5 -> 1 4 1 -> 2 0 2 -> 4 0 4 -> 0 4 0 -> 1 0 1
3 3 3   1 2 1   4 5 4    4 6 4    6 2 6    6 3 6    2 5 2    4 1 4    4 2 4    0 4 0    2 0 2    2 1 2

在此挑战中,我们对所有可能的n × n沙堆的子集感兴趣。此子集包含您可以通过将任意沙堆添加到所有3s n by n沙堆中而获得的任何沙堆。例如,在上面我们看到了212 | 101 | 212它在子集中,因为我们是通过在全三堆中添加一些东西来得到的。

现在,此子集具有一个有趣的元素:identity元素。如果采用此元素并将其添加到子集中的任何其他元素,则总和不变。换句话说,此沙堆的作用​​类似于该子集的。恰好212 | 101 | 212是3乘3的子集的零元素。例如:

2 2 2   2 1 2   4 3 4    0 5 0    2 1 2    2 2 2
2 2 2 + 1 0 1 = 3 2 3 -> 5 2 5 -> 1 6 1 -> 2 2 2
2 2 2   2 1 2   4 3 4    0 5 0    2 1 2    2 2 2

现在这是您的挑战:给定n,找到n by n grid 的子集的标识元素。通过为每种0, 1, 2, 3图像分配一个具有足够对比度的独特颜色并输出n x n图像来输出图像。您的代码必须能够在一台合理的现代PC上在一分钟内产生50 x 50的大小写。


例如,500 x 500标识元素:

500 x 500身份元素

这里是蓝色= 3,绿色= 2,红色= 1,白色=0。但是您不必在答案中使用此配色方案。


2
对竞争对手的警告:我描述了解决方案是什么,而不是如何计算它。您的代码必须能够在一分钟之内产生50 x 50的大小写,因此不可能强行使用。有解决此问题的算法,我没有给您。那是故意的。我觉得太多的挑战给您带来了预咀嚼的食物。我将酌情决定为第一个答案提供+100的悬赏,而这不能用内置函数解决问题(对您,Mathematica而言)。
Orlp

2
我认为说出每种颜色对应的数字将有益于500x500标识的图像。
xnor

什么构成“足够的对比度”?
科纳·奥布莱恩

@ ConorO'Brien足以区分的任何颜色。我可以通过一些色彩测量使其达到100%客观,但是我觉得这太过分了。我不在乎是否使用红色,黄色,绿色,灰度或其他任何颜色,只是不要使用彼此相差1%以内的4种灰度(例如#000000,#000001,#000002,#000003)。
orlp

啊哈,我相信这个问题是现在有资格的赏金。我可以获得+100奖金吗?:)
JungHwan Min'2

Answers:


2

八度,120个 113字节

function a=W(a);while nnz(b=a>3);a+=conv2(b,[t=[0 1 0];!t;t],'same')-b*4;end;end;@(n)imagesc(W((x=ones(n)*6)-W(x)))

感谢MinhHwan Min在Mathematica答案中提供了参考文件的链接。
感谢Stewie Griffin为我节省了7个字节[any(any(x)) -> nnz(x)]

这里使用两个函数:

1 f.:用于矩阵稳定化
。2.一个匿名函数n作为输入并显示身份矩阵。

试一试!用于生成50 * 50矩阵

计算矩阵所用的时间:0.0844409 seconds

说明:

考虑一个f 稳定矩阵的函数,找到身份的任务很简单

f(ones(n)*6 - f(ones(n)*6)

ones(n)*6意味着一个* n矩阵为6。

因此n=3

M = [6 6 6
     6 6 6
     6 6 6];

结果将是 f(M-f(M))

用于稳定功能的2D卷积用于加速任务;在每次迭代中,我们将生成一个b与输入矩阵大小相同的二进制矩阵,如果输入矩阵的对应元素> 3,则将其设置为1。然后我们使用下面的掩码对二进制矩阵进行二维卷积

0 1 0
1 0 1
0 1 0

代表四个直接邻居。
卷积的结果被添加到矩阵中,并从中减去二进制矩阵的四倍。

循环继续进行,直到矩阵的所有元素均<= 3

非高尔夫版本

function a=stabilize(a)
    mask = [t=[0 1 0];!t;t];
    while any(any(b=a>3))
        a+=conv2(b,mask,'same')-b*4;
    end
end
n= 50;
M = ones(n)*6;
result = stabilize(M-stabilize(M));
imagesc(result);

8

数学,177个 157 135 133字节

Colorize[f=BlockMap[⌊{l={0,1,0},1-l,l}#/4⌋~Total~2+#[[2,2]]~Mod~4&,#~ArrayPad~1,{3,3},1]&~FixedPoint~#&;k=Table[6,#,#];f[k-f@k]]&

取一个数字n。输出是身份Sandpile。0是黑色,1是浅灰色,2是洋红色,3是蓝灰色。

可悲的是,Mathematica对此没有内置功能。

使用Scott Corry和David Perkinson论文中所述的算法。

在我5岁的笔记本电脑上花费91.7秒来计算50x50身份的沙堆。我相信,一台合理的现代台式计算机的速度可以提高50%以上。(最后我还有一种更快的代码)。

说明

f= ...

定义函数f(输入是一个堆矩阵):

BlockMap[ ... ]~FixedPoint~#&

...重复该BlockMap操作,直到输出不变。BlockMap操作:...


#~ArrayPad~1

...用一层0填充输入数组...

{3,3},1

...将其划分为3x3矩阵,偏移量为1 ...

⌊{l={0,1,0},1-l,l}#/4⌋~Total~2+#[[2,2]]~Mod~4&

...并为每个分区添加倒在中心单元格上的沙粒数量和中心单元格值mod 4。

即的输出f是输入的稳定版本。


k=Table[6,#,#]

定义k为6个nn的数组。

f[k-f@k]]

计算f(k-f(k))。

Colorize[ ... ]

将颜色应用于结果。

更快的版本(142字节)

Colorize[r=RotateLeft;a=ArrayPad;f=a[b=#~a~1;b+r[g=⌊b/4⌋,s={0,1}]+g~r~-s+r[g,1-s]+r[g,s-1]-4g,-1]&~FixedPoint~#&;k=Table[6,#,#];f[k-f@k]]&

相同的代码,但使用内置列表轮换代替BlockMap。在我的笔记本电脑上在4.0秒内计算n = 50。


考虑到您遵循了时间限制的精神(执行实际算法而不是蛮力),并且功能强大的台式计算机的运行速度提高了50%非常合理,我同意。由于它无需细化内置函数即可实现实际算法,因此有资格获得+100的奖励。不过,您必须等待,因为我还无法开始赏金。
orlp

话虽这么说,但是用Python(一种臭名昭著的慢速语言)非常简单地实现了这一功能,在n = 50的情况下仅需花费约2s的时间。也许您可以加快速度?
orlp

@orlp完成,但是比原始代码长。我应该以更快的版本为主要答案,还是可以在最后加上它?
JungHwan Min

我认为这样很好。
orlp

0

蟒3 + numpy的+ PIL,385个 370 364字节

import numpy as q,PIL.Image as w
n=int(input())
z=n,n
def r(p):
 while len(p[p>3]):
  for x,y in q.ndindex(z):
   if p[x,y]>3:
    p[x,y]-=4;p[x-1,y]+=x>0;p[x,y-1]+=y>0
    if~-n>x:p[x+1,y]+=1
    if~-n>y:p[x,y+1]+=1
s=q.full(z,6)
t=s.copy()
r(t)
i=s-t
r(i)
w.fromarray(q.uint8(q.array(q.vectorize(lambda x:[x//1*65]*3,otypes=[object])(i).tolist()))).save('i.png')

在STDIN上输入。将图像输出为灰度i.png。黑色对应0,深灰色对应1,浅灰色对应2,白色对应0。

使用公式I = R(S - R(S)),其中I是标识元素,S是填充了6的矩阵,R是归约函数。

我可能可以通过切换到Python 2并执行操作来节省一些字节from numpy import*,但是(1)我没有在Python 2上安装Numpy,并且(2)程序并未终止from numpy import*

取消高尔夫:

import numpy as np
from PIL import Image

# Compute the identity element

n = int(input('Size of the sandpile: '))

def reduce_pile(sandpile):
  while any(element >= 4 for element in np.nditer(sandpile)):
    for x, y in np.ndindex((n, n)):
      if sandpile[x, y] >= 4:
        sandpile[x, y] -= 4
        if x > 0: sandpile[x - 1, y] += 1
        if y > 0: sandpile[x, y - 1] += 1
        if x < n - 1: sandpile[x + 1, y] += 1
        if y < n - 1: sandpile[x, y + 1] += 1

s = np.full((n, n), 6, dtype=np.int32)
s_prime = np.copy(s)

reduce_pile(s_prime)

identity = s - s_prime
reduce_pile(identity)

# Output it to identity.png as an image

colours = [[255, 255, 255], [255, 0, 0], [0, 255, 0], [0, 0, 255]]
img_array = np.vectorize(lambda x: colours[x], otypes=[object])(identity)
img_array = np.array(img_array.tolist(), dtype=np.uint8)

img = Image.fromarray(img_array)
img.save('identity.png')

您也许可以通过使用scipymatplotlib显示数据来节省字节,而不是使用PIL显式生成图像。
orlp
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.