Um neurônio Izhikevich é um modelo simples, mas bastante eficaz, de um neurônio biológico, projetado para uso em uma simulação discreta do tempo. Neste desafio de golfe, você estará implementando este modelo.
Parâmetros
Este modelo envolve apenas 7 variáveis organizadas em 2 equações diferenciais, em comparação com as dezenas de parâmetros de um modelo fisiologicamente preciso.
v
eu
são as duas variáveis de estado do neurônio. Aqui,v
é a variável "rápida" que representa o potencial da célula ao longo do tempo eu
é a variável "lenta" que representa certas propriedades da membrana. Av
variável é a mais importante, pois esta é a saída da simulação.a
,b
,c
, Ed
são constantes que descrevem as propriedades do neurónio fixo. Diferentes tipos de neurônios têm constantes diferentes, dependendo do comportamento desejado. Notavelmente,c
é o potencial de redefinição, que é o potencial de membrana ao qual a célula retorna após o pico.I
representa a corrente de entrada para o neurônio. Nas simulações de rede, isso mudará com o tempo, mas, para nossos propósitos, trataremosI
como uma constante fixa.
O Modelo
Este modelo possui um pseudocódigo muito simples. Primeiro, pegamos os valores constantes de abcd
e os usamos para inicializar v
e u
:
v = c
u = b * c
Em seguida, percorreremos o código de simulação quantas vezes desejar. Cada iteração representa 1 milissegundo de tempo.
for 1..t:
if v >= 30: # reset after a spike
v = c
u = u + d
v += 0.04*v^2 + 5*v + 140 - u + I
u += a * (b*v - u)
print v
Certas implementações do mundo real incluem etapas adicionais para precisão numérica, mas não as incluímos aqui.
Entrada
Como entrada, a sua função / programa deve ter os valores de a
, b
, c
, d
, I
, e t
(o número de passos de tempo para simular). Uma vez definido, nenhum desses parâmetros será alterado durante nossa simulação simples. A ordem de entrada não importa: você pode especificar a ordem em que seu programa aceita esses parâmetros.
Resultado
A saída será uma lista de números que representam o potencial de membrana da célula (fornecido por variável v
) ao longo da simulação. A lista pode estar em qualquer formato apropriado.
Você tem a opção de incluir o 0º valor da simulação (a configuração inicial antes de qualquer momento) em sua saída. Por exemplo, para uma entrada de 0.02 0.2 -50 2 10 6
(for a b c d I t
), uma saída de
-50
-40
-16.04
73.876224
-42.667044096
-25.8262335380956
29.0355029192068
ou
-40
-16.04
73.876224
-42.667044096
-25.8262335380956
29.0355029192068
é aceitável.
Seus valores não precisam ser exatamente os mesmos que os acima, dependendo de como seu idioma lida com flutuações.
Implementação de referência
Aqui está uma implementação de TIO que escrevi no Perl para demonstrar o modelo. Os parâmetros são os de um neurônio "tagarelado" do artigo acima, e isso serve como uma demonstração de como esse modelo é capaz de recriar algumas das propriedades mais complexas dos neurônios, como alternar entre estados de alta e baixa atividade. Se você observar a saída, poderá ver onde o neurônio dispara imediatamente várias vezes, mas depois espera um pouco antes de disparar várias vezes (apesar da tensão de entrada da célula I
ser constante o tempo todo).
fonte
t
ser sempre negativo?Respostas:
R ,
11099 bytesFunção anônima que recebe 6 argumentos. Nada extravagante, apenas uma porta direta da implementação de referência. A atualização de
u
,v
e a impressão dev
todas foram combinadas em uma única linha, graças ao fato de R'sprint
retornar o valor que está sendo impresso, para que você possa usá-lo na atribuição. Muito obrigado a Giuseppe por salvar 11 bytes!Experimente online!
fonte
pryr::f()
efunction()
. No entanto, você pode, depois de algumas experiências, moverv
eu
's declarações no corpo da função, preservando a ordem dos argumentos, para salvar uma dúzia Bytes: Experimente online!v
não necessariamente inteiros valores, você precisa fazerv>=30
, emboraLimpo ,
150145140138 bytesExperimente online!
Define a função
$ :: Real Real Real Real Real Int -> [Real]
, implementando o algoritmo conforme descrito no OP, começando no 0º termo.fonte
Python 2 , 100 bytes
Experimente online!
Economizou 2 bytes graças a user71546 .
fonte
0.04*v*v
parav*v/25.
deve economizar 1 byte. Se forem sempre fornecidos carros alegóricos,c
então seráv*v/25
suficiente para -2 bytes.v>29
na minha versão inicial. No entanto, isso é inválido porquev
não é necessariamente um número inteiro.JavaScript (Node.js) ,
107...103101 bytesContribuição de @apsillers
Experimente online!
Abordagem original:
105103 bytes. -1 byte Obrigado Arnauld e -2 bytes Obrigado @ Kamoroso94.Experimente online!
Ou se os alertas popping estiverem OK,
101...9997 bytes (-1 byte Obrigado Arnauld, -2 bytes Obrigado @ Kamoroso94):fonte
v>29
não é equivalente av>=30
para carros alegóricos. Você provavelmente quer fazer issov<30?0:(v=c,u+=d)
, ou melhor ainda,v<30||(v=c,u+=d)
que economiza um byte.t-->0
para simplesmentet--
.for
circuito em umamap
operação em uma matriz de comprimentot
:(a,b,c,d,I,t)=>[...Array(t)].map(_=>(v<30||(v=c,u+=d),v=v*(v/25+6)+140-u+I,u+=a*(b*v-u),v),u=b*(v=c))
. A função retorna uma matriz em vez de registrar valores, que parece satisfazer a especificação. Não supera aalert
solução, no entanto.Ruby , 94 bytes
Experimente online!
Outra porta simples da implementação de referência, um lambda que aceita 6 argumentos.
fonte
Haskell ,
112111 bytesExperimente online!
Não gera o caso zero. Supõe que
c
nunca,>=30
já que isso não faria sentido.Nunca pensei que eu teria que usar umawhere
cláusula em um código de golfe, mas existem variáveis demais.EDIT: Obrigado @Lynn por tirar um byte! Esqueci que você pode colocar
let
declarações em guardas. Claro que mata a legibilidade emborafonte
where
pelaf x|let g a=b=y
sintaxe estranha para salvar um byte:(a#b)c d i t|let r(v,u)|v>=30=r(c,u+d)|p<-0.04*v^2+6*v+140-u+i=(p,u+a*(b*p-u))=fst<$>take t(iterate r$r(c,b*c))
Elemento , 81 bytes
Experimente online! , Página Esolangs
Explicação:
Esta parte do programa recebe entrada. Ele armazena constantes
a
,b
,d
, eI
em variáveis. A entrada parac
nunca é armazenada em uma variável, mas permanece na pilha principal durante a execução. Três cópias são feitas: uma no topo para inicializaru
, uma no meio para servir como inicialv
e uma na parte inferior para servir como constantec
. A entrada parat
é lançada imediatamente na pilha de controle para servir como base do loop FOR (o[...]
) ao redor do restante do programa.Esta parte do programa pega o valor atual
v
e calcula o novo valor e, em seguida,v
são feitas quatro cópias do novo valor.A primeira cópia de
v
tem uma nova linha anexada e é impressa.A segunda cópia de
v
é usada para testar se o neurônio disparou. O resultado desse teste é colocado na pilha de controle para uso posterior.Esta parte calcula o "delta
u
", significando a quantidade a ser adicionadau
.Este bloco IF adiciona
d
à soma acima se o neurônio estiver disparando. Isso combina o que normalmente seriam duas atribuições em uma única atribuição.Isso armazena o valor atualizado de
u
.Este bloco IF é uma continuação do bloco IF acima. Se o neurônio estiver disparando, exclua o valor atual de
v
(que agora está no topo da pilha principal) e substitua-o por uma duplicata dec
(que esteve na parte inferior da pilha principal esse tempo todo).E isso é basicamente tudo o que existe. Uma observação secundária é que essa coisa vaza memória: é preciso um extra
"#
para excluir a parte superior da pilha de controle (a condição IF avaliada) após cada iteração do loop.Embora eu não diria que Element é a linguagem de golfe mais elegante, esse desafio me permite mostrar um recurso interessante: devido à divisão entre a pilha principal e a pilha de controle, posso pegar uma instrução IF e dividir a condição e o corpo em vários partes, entrelaçadas com código incondicional.
fonte
MATLAB, 111 bytes
Implementação bastante simples, provavelmente pode ser melhorada ainda mais.
fonte