Esta pergunta é sobre pilhas de areia abelianas . Leia este desafio anterior e assista ao vídeo numberphile para saber mais.
Uma pilha de areia abeliana de tamanho n por n é uma grade contendo o número 0, 1, 2 e 3 (representando o número de grãos de areia). A adição de dois montes de areia funciona primeiro adicionando elemento por elemento e, em seguida, derrubando qualquer elemento acima de 3. A ordem na qual você tomba não importa, o resultado final é o mesmo. Quando uma célula tomba, seu número diminui em 4 e cada um de seus vizinhos diretos aumenta em 1. Isso pode causar uma reação em cadeia. Se uma célula estiver na borda da grade, todos os grãos que caem da grade enquanto caem desaparecem.
Por exemplo, estou adicionando duas pilhas de areia de 3 por 3 (dando uma reação em cadeia bastante extrema):
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
Neste desafio, estamos interessados em um subconjunto de todos os n possíveis n por n sandpiles. Esse subconjunto contém qualquer arquivo de areia que você pode obter adicionando um arquivo de areia arbitrário ao arquivo de areia all-3s n por n . Por exemplo, logo acima vimos que212 | 101 | 212
está no subconjunto, porque o conseguimos adicionando algo ao monte de areia all-3.
Agora esse subconjunto tem um elemento interessante: o elemento de identidade . Se você pegar esse elemento e adicioná-lo a qualquer outro elemento no subconjunto , a soma permanecerá inalterada. Em outras palavras, esse sandpile age como um zero desse subconjunto. Acontece que esse 212 | 101 | 212
é o elemento zero para o subconjunto de 3 por 3. Por exemplo:
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
Agora, este é o seu desafio: dado n , encontrar o elemento identidade do subconjunto do n por n grade . Faça a saída atribuindo uma cor exclusiva com contraste suficiente de sua escolha para cada uma 0, 1, 2, 3
e produzindo uma imagem n por n. Seu código deve ser capaz de produzir a caixa de 50 por 50 em menos de um minuto em um PC moderno e razoável.
Por exemplo, o elemento de identidade 500 por 500:
Aqui está azul = 3, verde = 2, vermelho = 1, branco = 0. Mas você não precisa usar esse esquema de cores na sua resposta.
Respostas:
Oitava,
120113 bytesAgradecemos a JungHwan Min por fornecer um link para o documento de referência em sua resposta do Mathematica.
Graças a Stewie Griffin me salvou 7 bytes
[any(any(x)) -> nnz(x)]
Aqui, duas funções são usadas:
1
f
.: para estabilização de uma matriz2. Uma função anônima que assume
n
como entrada e mostra a matriz de identidade.Experimente no rextester! para geração de uma matriz 50 * 50
Tempo decorrido para cálculo da matriz:
0.0844409 seconds
.Explicação:
Considere uma função
f
que estabiliza uma matriz, a tarefa de encontrar a identidade é simplesmentef(ones(n)*6 - f(ones(n)*6)
.isso
ones(n)*6
significa uma matriz * n de 6.assim para
n=3
:O resultado será
f(M-f(M))
Para função de estabilização, convolução 2D usada para acelerar a tarefa; Em cada iteração, criamos uma matriz binária
b
com o mesmo tamanho da matriz de entrada e a definimos como 1 se o elemento correspondente da matriz de entrada for> 3. Em seguida, aplicamos uma convolução 2D da matriz binária com a seguinte máscararepresentando quatro vizinhos diretos.
O resultado da convolução é adicionado à matriz e 4 vezes a matriz binária subtraída dela.
O loop continuou até que todos os elementos da matriz fossem <= 3
Versão não destruída :
fonte
Mathematica,
177157135133 bytesToma um número
n
. A saída é o sandpile de identidade. 0 é preto, 1 é cinza claro, 2 é magenta e 3 é cinza-azul.Infelizmente, o Mathematica não tem um builtin para isso ...
Usa o algoritmo indicado no artigo de Scott Corry e David Perkinson .
O meu laptop de 5 anos leva 91,7 segundos para calcular o sandpile de identidade 50x50. Estou confiante de que um computador desktop moderno e razoável é 50% mais rápido. (Eu também tenho um código muito mais rápido no final).
Explicação
Definir função
f
(a entrada é uma matriz de pilha de areia): uma função que ...... repete a
BlockMap
operação até que a saída não seja alterada.BlockMap
Operação: ...... preencha a matriz de entrada com uma camada de 0 ...
... particione-o em matrizes 3x3, com deslocamento 1 ...
... e para cada partição, adicione o número de grãos de areia derrubados na célula central e o valor da célula central mod 4.
ou seja, a saída de
f
é a versão estabilizada da entrada.Definir
k
como um n por n matriz de 6s.Calcule f (k - f (k)).
Aplique cores ao resultado.
Versão mais rápida (142 bytes)
O mesmo código, mas usa a rotação da lista interna em vez de
BlockMap
. Calcula n = 50 em 4,0 segundos no meu laptop.fonte
Python 3 + Numpy + PIL,
385370364 bytesRecebe entrada em STDIN. Produz a imagem em escala de cinza para
i.png
. Preto corresponde a 0, cinza escuro a 1, cinza claro a 2 e branco a 0.Usa a fórmula
I = R(S - R(S))
, ondeI
é o elemento de identidade,S
é a matriz preenchida com seis eR
é a função de redução.Provavelmente eu poderia salvar alguns bytes mudando para Python 2 e executando
from numpy import*
, mas (1) não tenho o Numpy instalado no Python 2 e (2) o programa não estava terminandofrom numpy import*
.Ungolfed:
fonte
scipy
oumatplotlib
para exibir os dados em vez de gerar uma imagem explicitamente com o PIL.