Sandpile kimliğini bulun


18

Bu soru abelya kumsalları hakkında . Bu önceki sorguyu okuyun ve daha fazla bilgi edinmek için bu sayı videosunu izleyin .


Boyut bir değişmeli sandpile n ile n (kum taneciklerinin sayısını temsil eder) 0, 1, 2 ve 3 ihtiva eden bir ızgaradır. İki sandpile eklemek önce öğeyi tek tek ekleyerek ve sonra 3'ün üzerine çıkan herhangi bir öğeyi devirerek çalışır. Devrilme sırası önemli değil, sonuç aynıdır. Bir hücre devrildiğinde sayısı 4 azalır ve doğrudan komşularının her biri 1 artar. Bu bir zincirleme reaksiyona neden olabilir. Bir hücre ızgaranın kenarındaysa, devrilirken ızgaradan düşen taneler kaybolur.

Örneğin, iki 3'e 3 sandpile ekliyorum (oldukça aşırı bir zincirleme reaksiyon veriyor):

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

Bu meydan okumada, tüm n tarafından n sandpiles'in bir alt kümesiyle ilgileniyoruz . Bu alt küme, all-3s n by n sandpile'a rasgele bir sandpile ekleyerek alabileceğiniz herhangi bir sandpile içerir . Örneğin, hemen üstte bunun 212 | 101 | 212alt kümede olduğunu gördük , çünkü 3 kum havuzuna bir şey ekleyerek anladık.

Şimdi bu alt kümenin ilginç bir öğesi var: kimlik öğesi. Bu öğeyi alıp alt kümedeki herhangi bir öğeye eklerseniz , toplam değişmez. Başka bir deyişle, bu kum kuşu bu altkümenin sıfırı gibi davranır . Bu 212 | 101 | 212, 3'e 3 alt kümesi için sıfır elemanıdır. Örneğin:

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

Şimdi bu sizin meydan okuma: n verildiğinde , n by n grid alt kümesinin kimlik elemanını bulun . Her birine seçtiğiniz kontrastı yeterli olan benzersiz bir renk atayarak 0, 1, 2, 3ve bir n x n görüntü çıkararak çıktı alın. Kodunuz makul bir modern bilgisayarda bir dakikadan az bir sürede 50 ila 50 kasayı üretebilmelidir.


Örneğin, 500 x 500 kimlik öğesi:

500 x 500 kimlik elemanı

İşte mavi = 3, yeşil = 2, kırmızı = 1, beyaz = 0. Ama cevabınızda bu renk şemasını kullanmak zorunda değilsiniz.


2
Rakipler için bir uyarı: Çözümün nasıl olduğunu değil, çözümün ne olduğunu anlattım. Kodunuz bir dakikadan kısa sürede 50 x 50 kasa üretebilmelidir, bu nedenle kaba zorlama bir olasılık değildir. Bunu çözmek için algoritmalar var ve ben onları vermiyorum. Bu kasıtlı. Çok fazla zorluğun size önceden çiğnenmiş yiyecekler sunduğunu hissediyorum. Kendi takdirime bağlı olarak, bir yerleşik ile (sana bakmak, Mathematica) sorunu önemsizleştirmeyen ilk cevaba +100 lütuf vereceğim.
orlp

2
500x500 kimliğinin imajının, her rengin hangi sayıya karşılık geldiğini söylemekten fayda sağlayacağını düşünüyorum.
xnor

"Yeterli kontrast" ı ne oluşturur?
Conor O'Brien

@ ConorO'Brien Yeterince ayırt edilebilir herhangi bir renk kümesi. Bazı renk ölçülerinde% 100 objektif yapabilirdim, ama aşırıya kaçtığını hissediyorum. Kırmızı, sarı, yeşil, gri tonlamalı ya da her neyse, umarım, birbirinin% 1'inde bulunan 4 gri tonunu kullanmayın (# 000000, # 000001, # 000002, # 000003 gibi).
orlp

ahem bu sorunun şimdi lütuf için uygun olduğuna inanıyorum. +100 bonusu alabilir miyim? :)
JungHwan Min

Yanıtlar:


2

Octave, 120 113 bayt

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

Mathematica cevabındaki referans kağıdına bir bağlantı sağladığı için JungHwan Min'e teşekkürler . Stewie Griffin
sayesinde 7 bayt kurtardı[any(any(x)) -> nnz(x)]

Burada iki işlev kullanılır:

1 f.: bir matrisin stabilizasyonu için
2. nGirdi olarak alınan ve kimlik matrisini gösteren anonim bir fonksiyon .

Rextester üzerinde deneyin! 50 * 50 matris üretimi için

Matrisin hesaplanması için geçen süre: 0.0844409 seconds.

Açıklama:

f Bir matrisi stabilize eden bir işlevi düşünün , kimliğini bulma görevi basitçe

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

bu ones(n)*66'lık bir * n matrisi anlamına gelir.

için n=3:

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

Sonuç f(M-f(M))

Stabilizasyon fonksiyonu için görevi hızlandırmak için kullanılan 2D evrişim; Her yinelemede b, aynı giriş matrisi boyutuna sahip bir ikili matris yaparız ve giriş matrisinin karşılık gelen elemanı> 3 ise, 1'e ayarlarız. Ardından, aşağıdaki matrisle ikili matrisin 2D konvülsiyonunu uygularız

0 1 0
1 0 1
0 1 0

dört doğrudan komşuyu temsil ediyor.
Evrişim sonucu matrise eklenir ve ikili matristen 4 kez çıkarılır.

Döngü, matrisin tüm öğesi <= 3 olana kadar devam etti

Ungolfed sürümü :

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

Mathematica, 177 157 135 133 bayt

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

Bir sayı alır n. Çıktı sandpile kimliğidir. 0 siyah, 1 açık gri, 2 macenta ve 3 mavi-gridir.

Ne yazık ki, Mathematica bunun için bir yerleşik yok ...

Scott Corry ve David Perkinson gazetesinde belirtilen algoritmayı kullanır .

50x50 kimlik kumunu hesaplamak için 5 yaşındaki dizüstü bilgisayarımda 91.7 saniye sürüyor. Makul bir modern masaüstü bilgisayarın% 50'den daha hızlı olduğundan eminim. (Ayrıca sonunda bir yol daha hızlı kod var).

açıklama

f= ...

Fonksiyonu tanımlayın f(giriş bir sandpile matrisidir): ...

BlockMap[ ... ]~FixedPoint~#&

... BlockMapçıkış değişmeyene kadar işlemi tekrarlar . BlockMapoperasyon: ...


#~ArrayPad~1

... giriş dizisini 0 katmanıyla doldurun ...

{3,3},1

... ofset 1 ile 3x3 matrislere ayırın ...

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

... ve her bölüm için, orta hücreye devirilen kum tanelerinin sayısını ve orta hücre değeri mod 4'ü ekleyin.

yani çıkışı f, girişin stabilize edilmiş versiyonudur.


k=Table[6,#,#]

Tanımlama kbir şekilde n ile n, 6s dizisi.

f[k-f@k]]

F (k - f (k)) hesaplaması.

Colorize[ ... ]

Sonuca renkler uygulayın.

Daha hızlı sürüm (142 bayt)

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

Aynı kod, ancak yerine yerleşik liste döndürme kullanır BlockMap. Dizüstü bilgisayarımda 4.0 saniyede n = 50 hesaplar.


Zaman sınırının ruhunu takip ettiğinizi (kaba kuvvet yerine gerçek bir algoritma uyguladığınızı) ve güçlü bir masaüstü bilgisayarın% 50 daha hızlı olması çok makul, buna izin vereceğim. Dahili bir önemsizleştirici olmadan gerçek bir algoritma uyguladığından, bu +100 bonusu için uygundur. Henüz bir ödül başlayamadığım için beklemeniz gerekecek.
orlp

Bununla birlikte, bunu oldukça önemsiz bir şekilde Python'da (kötü bir şekilde yavaş bir dil) uygulamak, n = 50 için ~ 2s alır. Belki biraz hızlandırabilirsiniz?
orlp

@orlp Bitti, ancak orijinal koddan daha uzun. Daha hızlı sürümü ana cevabım yapmalı mıyım yoksa sonuna koyabilir miyim?
JungHwan Min

Sanki bu iyi gibi.
orlp

0

Python 3 + Numpy + PIL, 385 370 364 bayt

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 üzerine girdi alır. Görüntüyü gri tonlamalı olarak verir i.png. Siyah 0, koyu gri 1, açık gri 2 ve beyaz 0 olur.

Kimlik elemanının I = R(S - R(S))bulunduğu formül , altı ile doldurulmuş matris ve indirgeme işlevini kullanır.ISR

Muhtemelen Python 2'ye from numpy import*geçip yaparak bazı baytlar kaydedebilirim , ancak (1) Python 2'de yüklü Numpy'm yok ve (2) programın sona ermediği from numpy import*.

Ungolfed:

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

Baytları, PIL ile açıkça bir görüntü oluşturmak yerine scipyveya matplotlibkullanarak görüntülemek için kaydedebilirsiniz .
orlp
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.