模拟模型神经元


16

一个Izhikevich神经元是一个简单但非常有效的生物神经元,专为在离散时步仿真使用的模型。在这个高尔夫挑战赛中,您将实现此模型。

参量

与生理上精确的模型的数十个参数相比,该模型仅涉及组织为2个微分方程的7个变量。

  • vu是神经元的两个状态变量。在此,v“快速”变量代表随着时间的细胞电势,并且u“缓慢”变量代表某些膜的性质。v变量是最重要的变量,因为这是模拟的输出。
  • abc,和d被固定描述该神经元的特性的常数。根据所需的行为,不同类型的神经元具有不同的常数。值得注意的c是,复位电位是细胞在加标后返回的膜电位。
  • I代表输入到神经元的电流。在网络仿真中,这会随着时间而变化,但是出于我们的目的,我们将其I视为固定常数。

该模型

该模型具有非常简单的伪代码。首先,我们采用的常量值abcd并使用它们来初始化vu

v = c
u = b * c

接下来,我们将根据需要遍历仿真代码多次。每次迭代代表1毫秒的时间。

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

某些实际的实现中包括用于数字精度的其他步骤,但此处未包括这些步骤。

输入值

作为输入,你的程序/函数应该采取的值abcdI,和t(的时间步来模拟数字)。设置后,在我们的简单仿真过程中,这些参数均不会改变。输入的顺序并没有此事:你可以指定你的程序有这些参数的顺序。

输出量

输出将是一个数字列表,代表v模拟过程中细胞的膜电位(由给出)。该列表可以采用任何适当的格式。

您可以选择是否在输出中包括模拟的第0个值(经过任何时间的初始配置)。例如,对于0.02 0.2 -50 2 10 6(for a b c d I t)的输入,其中一个的输出

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

要么

-40
-16.04
73.876224
-42.667044096
-25.8262335380956
29.0355029192068

是可以接受的。

你的价值观也并不必须是完全一样上面,这取决于如何你的语言把手浮动。

参考实施

这是我在Perl中编写的TIO实现,以演示该模型。参数是上面链接的论文中“震颤”神经元的参数,这证明了该模型如何重现神经元的一些更复杂的特性,例如在高活动和低活动状态之间交替。如果查看输出,则可以看到神经元立即在哪里突跳几次,然后等待一会儿再突刺几次(尽管电池输入电压I始终保持恒定)。


t否定的?
kamoroso94

1
@ kamoroso94不,您不能模拟负时间。
PhiNotPi

Answers:


6

R110 99字节

带有6个参数的匿名函数。没什么,只是参考实现的直接移植。的更新uv以及印刷v已全部合并成一条线,这要归功于这个事实是R的print收益正在打印,所以你可以在分配使用它的价值。非常感谢Giuseppe节省了11个字节!

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

在线尝试!


2
太好了,+ 1。虽然,由于您要明确标记参数,所以pryr::f()and 之间没有字节节省function()。但是,经过一些试验,您可以将vu的声明移到函数体中,同时保留参数的顺序,以节省十几个字节:在线尝试!
朱塞佩

因为v不一定需要整数值,你需要做的v>=30,虽然
朱塞佩

@Giuseppe谢谢,这些改进很棒。由于某些原因,我没有考虑过不明确标记参数...
rturnbull

4

干净150个 145 140 138字节

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)

在线尝试!

定义函数$ :: Real Real Real Real Real Int -> [Real],从0项开始,按照OP中的描述实施算法。


3

Python 2,100字节

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

在线尝试!

由于user71546节省了2个字节。


@ovs糟糕,您是对的。现在应该修复。
Xcoder先生18年

谈及0.04*v*vv*v/25.应该保存1个字节。如果总是给定浮点数,cv*v/25-2个字节就足够了。
Shieru Asakoto

@ceilingcat如果您查看我的修订历史,您会注意到v>29我的初始版本中。但是,这是无效的,因为v不一定是整数。
Xcoder先生18年

3

JavaScript(Node.js)107 ... 103101字节

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

在线尝试!

原始方法:105 103字节。-1个字节感谢Arnauld,-2个字节感谢@ 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)}}

在线尝试!

或者,如果弹出警报正常,则101 ... 99 97字节(-1字节感谢Arnauld,-2字节感谢@ 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>29不等于v>=30浮点数。您可能想v<30?0:(v=c,u+=d)代替它,或者更好的方法v<30||(v=c,u+=d)是节省一个字节。
Arnauld

@Arnauld哦,是的,当我查看Python答案时,我意识到我并没有对其进行优化,但是我也没有意识到我正在处理浮点数。
Shieru Asakoto

2
您可以通过将更t-->0改为simple 来节省两个字节t--
kamoroso94 '18 -2-8

1
您可以通过重构的得到这个下降到101 for环进入map操作长度的阵列上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))。该函数返回一个数组,而不是记录似乎符合规范的值。alert但是,没有击败解决方案。
apsillers 18-2-8

2

红宝石,94字节

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

在线尝试!

参考实现的另一个直接端口是接受6个参数的lambda。


2

Haskell中112个 111字节

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

在线尝试!

不输出零大小写。假设c永远>=30道理的。

没想到我必须使用 where在代码高尔夫中子句,但是变量太多了。

编辑:感谢@Lynn脱掉一个字节!我忘了你可以放一些let警句。当然会杀死可读性


1
您可以用where奇怪的f x|let g a=b=y语法替换来保存字节:(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

元素,81个字节

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

在线尝试!Esolangs页面

说明:

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

程序的这一部分需要输入。它存储常数abd,和I成变量。的输入c从不存储在变量中,而是在整个执行过程中保留在主堆栈中。制作了三份副本:一份在顶部进行初始化u,一份在中间作为初始v,而底层在一份作为常量c。输入t立即引发到控制堆栈上,以作为[...]围绕程序其余部分的FOR循环()的基础。

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

程序的此部分采用的当前值v并计算新值,然后v制作新值的四个副本。

\
.`

的第一个副本v附加了换行符并被打印。

30<!

第二份 v用于测试神经元是否已尖峰。测试的结果放在控制堆栈上,以备后用。

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

此部分计算“增量u”,表示要添加到的量u

[d~+]

这个IF块增加了 d如果神经元发出尖峰,则加到上述总和上。这将通常是两个分配的任务合并为一个分配。

u;

这将存储更新的值 u

[#2:]

该IF块是上述IF块的延续。如果神经元发出尖峰信号,请删除当前值v(现在位于主堆栈的顶部),然后将其替换为副本(始终位于主堆栈c的底部)。

基本上就是全部。有一点需要注意的是,这件事会泄漏内存:"#每次循环迭代之后,都需要在内存中额外删除控制堆栈的顶部(评估的IF条件)。

尽管我不会将Element称为最优美的高尔夫语言,但这一挑战确实使我能够展示一个有趣的功能:由于主堆栈和控制堆栈之间的划分,我可以采用IF语句并将条件和主体分成多个零件,与无条件代码交错。


0

MATLAB,111字节

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

非常简单的实现,可能会进一步改进。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.