Simula un neurone modello


16

Un neurone di Izhikevich è un modello semplice ma abbastanza efficace di un neurone biologico, progettato per l'uso in una simulazione discreta del time-stepping. In questa sfida del golf, implementerai questo modello.

parametri

Questo modello coinvolge solo 7 variabili organizzate in 2 equazioni differenziali, rispetto alle dozzine di parametri di un modello fisiologicamente accurato.

  • ve usono le due variabili di stato del neurone. Qui, vè la variabile "veloce" che rappresenta il potenziale cellulare nel tempo, ed uè la variabile "lenta" che rappresenta alcune proprietà della membrana. La vvariabile è la più importante, poiché si tratta dell'output della simulazione.
  • a, b, c, E dsono fissati costanti che descrivono le proprietà del neurone. Diversi tipi di neuroni hanno costanti diverse, a seconda del comportamento desiderato. In particolare, cè il potenziale di ripristino, ovvero il potenziale di membrana a cui la cellula ritorna dopo l'aggiunta.
  • Irappresenta la corrente in ingresso al neurone. Nelle simulazioni di rete, questo cambierà nel tempo, ma per i nostri scopi considereremo Iuna costante fissa.

Il modello

Questo modello ha uno pseudocodice molto semplice. Innanzitutto, prendiamo i valori costanti di abcde li usiamo per inizializzare ve u:

v = c
u = b * c

Successivamente, eseguiamo il ciclo del codice di simulazione tutte le volte che lo desideri. Ogni iterazione rappresenta 1 millisecondo di 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

Alcune implementazioni del mondo reale includono passaggi aggiuntivi per l'accuratezza numerica, ma non stiamo includendo quelli qui.

Ingresso

Come input, il programma / funzione dovrebbe assumere i valori di a, b, c, d, I, e t(il numero di passaggi di tempo per simulare). Una volta impostato, nessuno di questi parametri cambierà durante la nostra semplice simulazione. L'ordine di input non ha importanza: puoi specificare l'ordine in cui il tuo programma accetta questi parametri.

Produzione

L'output sarà un elenco di numeri che rappresentano il potenziale di membrana della cellula (dato dalla variabile v) nel corso della simulazione. L'elenco può essere in qualsiasi formato appropriato.

Puoi scegliere se includere il valore 0 della simulazione (la configurazione iniziale prima che sia trascorso un qualsiasi momento) nell'output. Ad esempio, per un input di 0.02 0.2 -50 2 10 6(for a b c d I t), un output di entrambi

-50
-40
-16.04
73.876224
-42.667044096
-25.8262335380956
29.0355029192068

o

-40
-16.04
73.876224
-42.667044096
-25.8262335380956
29.0355029192068

è accettabile.

I tuoi valori non devono essere esattamente gli stessi di quelli sopra, a seconda di come la tua lingua gestisce i float.

Implementazione di riferimento

Ecco un'implementazione TIO che ho scritto in Perl per dimostrare il modello. I parametri sono quelli di un neurone "chiacchierone" dall'articolo collegato sopra, e questo serve come dimostrazione di come questo modello è in grado di ricreare alcune delle proprietà più complesse dei neuroni, come l'alternanza tra stati di alta e bassa attività. Se guardi l'output, puoi vedere dove il neurone si innesca immediatamente più volte, ma poi aspetta un po 'prima di spuntare più volte (nonostante la tensione di ingresso della cella Isia costante per tutto il tempo).


Sarà tmai negativo?
kamoroso94,

1
@ kamoroso94 No, non puoi simulare il tempo negativo.
PhiNotPi

Risposte:


6

R , 110 99 byte

Funzione anonima che accetta 6 argomenti. Niente di speciale, solo una porta semplice dell'implementazione di riferimento. L'aggiornamento di u, ve la stampa di vsono stati tutti combinati in un'unica riga, grazie al fatto che R's printrestituisce il valore che viene stampato, quindi è possibile utilizzarlo nell'assegnazione. Mille grazie a Giuseppe per aver salvato 11 byte!

pryr::f({v=c;u=b*c;for(i in 1:t){if(v>=30){v=c;u=u+d}
u=a*b*(v=print((.04*v+6)*v+140+I-u))-a*u+u}})

Provalo online!


2
Questo è fantastico, +1. Sebbene, dato che stai etichettando esplicitamente gli argomenti, non c'è alcun risparmio di byte tra pryr::f()e function(). Tuttavia, dopo un po 'di sperimentazione, puoi spostare ve ule dichiarazioni nel corpo della funzione preservando l'ordine degli argomenti, per salvare una dozzina di byte: provalo online!
Giuseppe

poiché vnon richiede necessariamente valori interi, è necessario v>=30, però
Giuseppe

@Giuseppe Grazie, questi miglioramenti sono fantastici. Per qualche ragione non avevo considerato di non etichettare esplicitamente gli argomenti ...
rturnbull

4

Pulito , 150 145 140 138 byte

import StdEnv
$a b c d i t=map snd(iterate(\(u,v)#(w,n)=if(30.0<v)(c,u+d)(v,u)
#y=0.04*w*w+6.0*w+140.0-n+i
=(a*b*y-a*n+n,y))(b*c,c))%(0,t)

Provalo online!

Definisce la funzione $ :: Real Real Real Real Real Int -> [Real], implementando l'algoritmo come descritto nel PO, a partire dal 0 ° termine.


3

Python 2 , 100 byte

a,b,c,d,I,t=input();v=c;u=b*c
exec"if v>=30:v=c;u+=d\nv=v*v/25+6*v+140-u+I;u+=a*(b*v-u);print v\n"*t

Provalo online!

Salvato 2 byte grazie a user71546 .


@ovs Oops, hai ragione. Ora dovrebbe essere risolto.
Mr. Xcoder,

Passando 0.04*v*va v*v/25.dovrebbe salvare 1 byte. Se i float vengono sempre indicati, callora è v*v/25sufficiente -2 byte.
Shieru Asakoto,

@ceilingcat Se dai un'occhiata alla mia cronologia delle revisioni, noterai che avevo v>29nella mia versione iniziale. Tuttavia, ciò non è valido perché vnon è necessariamente un numero intero.
Mr. Xcoder,

3

JavaScript (Node.js) , 107 ... 103 101 byte

Contributo di @apsillers

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

Provalo online!

Approccio originale: 105 103 byte. -1 byte Grazie Arnauld e -2 byte Grazie @ Kamoroso94.

(a,b,c,d,I,t)=>{for(u=b*(v=c);t--;){v<30||(v=c,u+=d);v=v*(v/25+6)+140-u+I;u+=a*(b*v-u);console.log(v)}}

Provalo online!

O se gli avvisi di popping sono OK, quindi 101 ... 99 97 byte (-1 byte Grazie Arnauld, -2 byte Grazie @ Kamoroso94):

(a,b,c,d,I,t)=>{for(u=b*(v=c);t--;){v<30||(v=c,u+=d);v=v*(v/25+6)+140-u+I;u+=a*(b*v-u);alert(v)}}

var u, v;
var f = 
(a,b,c,d,I,t)=>{for(u=b*(v=c);t--;){v<30||(v=c,u+=d);v=v*(v/25+6)+140-u+I;u+=a*(b*v-u);alert(v)}}

function run() {
 f(...["a", "b", "c", "d", "I", "t"].map(x => document.getElementById(x).value * 1));
}
a = <input id="a" value="0.02"><br>
b = <input id="b" value="0.2"><br>
c = <input id="c" value="-50"><br>
d = <input id="d" value="2"><br>
I = <input id="I" value="10"><br>
t = <input id="t" value="6"><br>
<input type="button" value="Run" onclick="run()">


v>29non è equivalente a v>=30per i galleggianti. Probabilmente vuoi fare v<30?0:(v=c,u+=d)invece, o meglio ancora v<30||(v=c,u+=d)che salva un byte.
Arnauld

@Arnauld Oh sì, quando ho guardato la risposta di Python mi sono reso conto che non l'ho ottimizzato, ma non mi rendevo conto che stavo anche elaborando i float.; P Risolto.
Shieru Asakoto,

2
È possibile salvare due byte cambiando t-->0semplicemente t--.
kamoroso94,

1
È possibile ottenere questo fino a 101 dal refactoring del forciclo in mapun'operazione su un array di lunghezza t: (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)). La funzione restituisce un array anziché i valori di registrazione, che sembrano soddisfare le specifiche. Non batte la alertsoluzione, però.
apsillers

2

Rubino , 94 byte

->a,b,c,d,i,t{v=c
u=b*c
t.times{v>=30?(v=c;u+=d):0
v+=0.04*v**2+5*v+140-u+i
u+=a*(b*v-u)
p v}}

Provalo online!

Un'altra semplice porta dell'implementazione di riferimento, una lambda che accetta 6 argomenti.


2

Haskell , 112 111 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))

Provalo online!

Non genera il caso zero. Dal presupposto che cnon è mai >=30dato che non avrebbe senso.

Non avrei mai pensato di dover usare una whereclausola in un codice golf ma ci sono troppe variabili.

EDIT: Grazie @Lynn per aver rimosso un byte! Ho dimenticato che puoi mettere le letdichiarazioni in guardia. Sicuramente uccide la leggibilità però


1
È possibile sostituire la wherestrana f x|let g a=b=ysintassi per salvare un 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))
Lynn

1

Elemento , 81 byte

_a;_b;_3:b~*u;_d;_I;_'[3:\.04*5+*140+u~-+I~++4:\
.`30<!b~*u~-+a~*u~+[d~+]u;[#2:]]

Provalo online! , Pagina di Esolangs

Spiegazione:

_a;_b;_3:b~*u;_d;_I;_'[ ... ]

Questa parte del programma accetta input. Memorizza le costanti a, b, d, e Iin variabili. L'input per cnon viene mai memorizzato in una variabile, ma rimane nello stack principale durante l'esecuzione. Vengono eseguite tre copie: una in alto per l'inizializzazione u, una al centro per l'iniziale ve una in basso per la costante c. L'input per tviene immediatamente gettato nello stack di controllo per fungere da base del ciclo FOR (il [...]) che circonda il resto del programma.

3:\.04*5+*140+u~-+I~++4:

Questa parte del programma prende il valore corrente di ve calcola il nuovo valore, quindi vvengono eseguite quattro copie del nuovo valore.

\
.`

La prima copia di vha una riga aggiunta e viene stampata.

30<!

La seconda copia di vviene utilizzata per testare se il neurone è aumentato. Il risultato di questo test viene messo nello stack di controllo per un uso successivo.

b~*u~-+a~*u~+

Questa parte calcola il "delta u", ovvero l'importo da aggiungere u.

[d~+]

Questo blocco IF si aggiunge dalla somma sopra se il neurone sta picchiando. Questo combina quelli che normalmente sarebbero due incarichi in un unico compito.

u;

Questo memorizza il valore aggiornato di u.

[#2:]

Questo blocco IF è una continuazione del blocco IF sopra. Se il neurone sta picchiando, elimina il valore corrente di v(che ora è in cima allo stack principale) e sostituiscilo con un duplicato dic (che è stato in fondo allo stack principale per tutto questo tempo).

E questo è praticamente tutto quello che c'è da fare. Una nota minore è che questa cosa perde memoria: ci vuole un extra"# per eliminare la parte superiore dello stack di controllo (la condizione IF valutata) dopo ogni iterazione del ciclo.

Anche se non definirei Element il linguaggio di golf più elegante, questa sfida mi consente di mostrare una caratteristica interessante: a causa della divisione tra lo stack principale e lo stack di controllo, posso prendere un'istruzione IF e dividere la condizione e il corpo in più parti, intrecciate con codice incondizionato.


0

MATLAB, 111 byte

function z(a,b,c,d,I,t)
v=c;u=b*c;for i=1:t if v>=30 v=c;u=u+d;end
v=.04*v^2+6*v+140-u+I
u=u+a*(b*v-u);
end
end

L'implementazione piuttosto semplice, probabilmente può essere ulteriormente migliorata.

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.