Trova la sandpile di identità


18

Questa domanda riguarda le sabbie abeliane . Leggi questa sfida precedente e guarda questo video con numero di file per saperne di più.


Una catasta di sabbia abeliana di dimensioni n per n è una griglia contenente il numero 0, 1, 2 e 3 (che rappresenta il numero di granelli di sabbia). L'aggiunta di due sandpiles funziona aggiungendo prima elemento per elemento, quindi rovesciando qualsiasi elemento che vada al di sopra di 3. L'ordine in cui si rovescia non ha importanza, il risultato finale è lo stesso. Quando una cellula si ribalta il suo numero diminuisce di 4 e ciascuno dei suoi vicini diretti aumenta di 1. Ciò può causare una reazione a catena. Se una cella si trova sul bordo della griglia, tutti i grani che cadono dalla griglia mentre cadono scompaiono.

Ad esempio, sto aggiungendo due sandpiles 3 per 3 (dando una reazione a catena piuttosto estrema):

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

In questa sfida ci interessa un sottoinsieme di tutti i possibili n da n sandpiles. Questo sottoinsieme contiene qualsiasi sandpile che è possibile ottenere aggiungendo una sandpile arbitraria alla sandpile all-3s n by n . Ad esempio, appena sopra abbiamo visto che 212 | 101 | 212è nel sottoinsieme, perché l'abbiamo ottenuto aggiungendo qualcosa alla sandpile all-3.

Ora questo sottoinsieme ha un elemento interessante: l' elemento identità . Se si prende questo elemento e lo si aggiunge a qualsiasi altro elemento nel sottoinsieme , la somma rimane invariata. In altre parole, questa catasta di sabbia si comporta come uno zero di questo sottoinsieme. Accade solo che 212 | 101 | 212sia l'elemento zero per il sottoinsieme di 3 per 3. Ad esempio:

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

Ora questa è la tua sfida: dato n , trova l'elemento identità del sottoinsieme di n per n griglia . Emettilo assegnando un colore unico con un contrasto sufficiente a tua scelta a ciascuno di essi 0, 1, 2, 3e producendo un'immagine n per n. Il tuo codice deve essere in grado di produrre il caso 50 per 50 in meno di un minuto su un PC moderno e ragionevole.


Ad esempio, l'elemento identità 500 per 500:

500 per 500 elemento di identità

Qui è blu = 3, verde = 2, rosso = 1, bianco = 0. Ma non è necessario utilizzare questa combinazione di colori nella risposta.


2
Un avvertimento per i concorrenti: ho descritto qual è la soluzione, non come calcolarla. Il tuo codice deve essere in grado di produrre il caso 50 per 50 in meno di un minuto, quindi la forzatura bruta non è una possibilità. Ci sono algoritmi per risolverlo e non te li sto dando. È intenzionale. Sento che troppe sfide ti presentano cibi pre-masticati. Darò una taglia +100 alla prima risposta che non banalizza il problema con un builtin (guardandoti, Mathematica), a mia discrezione.
orlp,

2
Penso che l'immagine dell'identità 500x500 trarrebbe beneficio dal dire a quale numero corrisponde ciascun colore.
xnor

Cosa costituisce "contrasto sufficiente"?
Conor O'Brien,

@ ConorO'Brien Qualsiasi set di colori sufficientemente distinguibili. Potrei renderlo obiettivo al 100% con una certa misura del colore, ma penso che sia eccessivo. Non mi interessa se usi il rosso, il giallo, il verde, la scala di grigi o qualsiasi altra cosa, semplicemente non usi 4 tonalità di grigio che si trovano all'interno dell'1% l'una dell'altra (come # 000000, # 000001, # 000002, # 000003).
orlp,

ahem Credo che questa domanda sia ora ammissibile per la generosità. Posso ottenere il bonus +100? :)
JungHwan Min

Risposte:


2

Ottava, 120 113 byte

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

Grazie a JungHwan Min per aver fornito un link al documento di riferimento nella sua risposta Mathematica.
Grazie a Stewie Griffin mi ha salvato 7 byte[any(any(x)) -> nnz(x)]

Qui vengono utilizzate due funzioni:

1 f.: per la stabilizzazione di una matrice
2. Una funzione anonima che assumen come input e mostra la matrice di identità.

Provalo su rextester!per la generazione di una matrice 50 * 50

Tempo trascorso per il calcolo della matrice: 0.0844409 seconds.

Spiegazione:

Considera una funzione f che stabilizza una matrice il compito di trovare l'identità è semplicemente

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

ciò ones(n)*6significa una matrice * n di 6.

quindi per n=3:

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

Il risultato sarà f(M-f(M))

Per la funzione di stabilizzazione convoluzione 2D utilizzata per accelerare l'attività; In ogni iterazione creiamo una matrice binaria bcon le stesse dimensioni della matrice di input e la impostiamo su 1 se l'elemento corrispondente della matrice di input è> 3. Quindi applichiamo una convoluzione 2D della matrice binaria con la seguente maschera

0 1 0
1 0 1
0 1 0

che rappresenta quattro vicini diretti.
Il risultato della convoluzione viene aggiunto alla matrice e 4 volte la matrice binaria sottratta da essa.

Il ciclo è continuato fino a quando tutti gli elementi della matrice sono <= 3

Versione non golfata :

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 byte

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

Prende un numero n. L'output è la sandpile di identità. 0 è nero, 1 è grigio chiaro, 2 è magenta e 3 è blu-grigio.

Purtroppo, Mathematica non ha un incorporato per questo ...

Utilizza l'algoritmo dichiarato nel documento di Scott Corry e David Perkinson .

Richiede 91,7 secondi sul mio laptop di 5 anni per calcolare la sandpile di identità 50x50. Sono fiducioso che un computer desktop moderno ragionevole sia più veloce del 50%. (Ho anche un codice molto più veloce alla fine).

Spiegazione

f= ...

Definisci funzione f(l'input è una matrice sandpile): una funzione che ...

BlockMap[ ... ]~FixedPoint~#&

... ripete l' BlockMapoperazione fino a quando l'uscita non cambia. BlockMapoperazione: ...


#~ArrayPad~1

... pad dell'array di input con uno strato di 0 ...

{3,3},1

... partizionalo in matrici 3x3, con offset 1 ...

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

... e per ogni partizione, aggiungi il numero di granelli di sabbia rovesciati sulla cella centrale e il valore della cella centrale mod 4.

cioè l'uscita di fè la versione stabilizzata dell'ingresso.


k=Table[6,#,#]

Definire kcome una matrice n per n di 6 secondi.

f[k-f@k]]

Calcola f (k - f (k)).

Colorize[ ... ]

Applica i colori al risultato.

Versione più veloce (142 byte)

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

Stesso codice, ma utilizza la rotazione dell'elenco integrata anziché BlockMap. Calcola n = 50 in 4,0 secondi sul mio laptop.


Considerando che hai seguito lo spirito del limite di tempo (implementando un vero algoritmo piuttosto che una forza bruta), ed è molto plausibile che un potente computer desktop sia più veloce del 50%, lo permetterò. Dal momento che implementa un algoritmo reale senza banalizzazione integrata, questo si qualifica per il bonus +100. Dovrai comunque aspettarlo, dato che non posso ancora iniziare una taglia.
orlp

Detto questo, implementare questo in modo abbastanza banale in Python (un linguaggio notoriamente lento), richiede solo ~ 2s per n = 50. Forse puoi accelerarlo un po '?
orlp

@orlp Fatto, ma è più lungo del codice originale. Devo rendere la versione più veloce la mia risposta principale o posso semplicemente metterla alla fine?
JungHwan Min

In questo modo, penso.
orlp

0

Python 3 + Numpy + PIL, 385 370 364 byte

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

Accetta input su STDIN. Invia l'immagine in scala di grigi a i.png. Il nero corrisponde a 0, il grigio scuro a 1, il grigio chiaro a 2 e il bianco a 0.

Utilizza la formula I = R(S - R(S)), dove Iè l'elemento identità, Sè la matrice piena di sei ed Rè la funzione di riduzione.

Probabilmente potrei salvare alcuni byte passando a Python 2 e facendo from numpy import*, ma (1) non ho Numpy installato su Python 2 e (2) il programma non stava terminando 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')

Potrebbe essere possibile salvare byte utilizzando scipyo matplotlibper visualizzare i dati anziché generare un'immagine in modo esplicito con PIL.
orlp,
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.