Моделюйте модельний нейрон


16

Izhikevich нейрон є простим , але досить ефективною моделлю біологічного нейрона, призначеним для використання в дискретний час покрокового моделювання. У цьому виклику з гольфу ви будете реалізовувати цю модель.

Параметри

Ця модель включає лише 7 змінних, організованих у 2 диференціальних рівняння, порівняно з десятками параметрів фізіологічно точної моделі.

  • vі uє двома змінними стану нейрона. Тут vє "швидка" змінна, що представляє потенціал клітини в часі, і u"повільна" змінна, що представляє певні властивості мембрани. vЗмінна є найбільш важливим, так як це вихід моделювання.
  • a, b, c, І dє фіксованими константами , які описують властивості нейрона. Різні типи нейронів мають різні константи, залежно від бажаної поведінки. Зокрема, cє потенціал скидання, який є мембранним потенціалом, до якого повертається клітина після шипування.
  • Iявляє вхідний струм до нейрона. У моделюваннях мережі це зміниться з часом, але для наших цілей ми будемо розглядатись Iяк фіксовану константу.

Модель

Ця модель має дуже простий псевдокод. Спочатку ми беремо постійні значення abcdі використовуємо їх для ініціалізації vта u:

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

Деякі реальні реалізації включають додаткові кроки для чисельної точності, але ми не включаємо сюди.

Вхідні дані

Як вхід, ваша програма / функція повинна приймати значення a, b, c, d, I, і t(число кроків по часу для імітації). Після встановлення жоден із цих параметрів не зміниться під час нашого простого моделювання. Порядок введення не має значення: ви можете вказати порядок, у якому ваша програма приймає ці параметри.

Вихідні дані

Вихідним буде перелік чисел, що представляють мембранний потенціал клітини (заданий змінною v) протягом моделювання. Список може бути у будь-якому відповідному форматі.

Ви можете вибрати, чи включити 0-е значення моделювання (початкова конфігурація до того, як пройде будь-який час) у свій висновок. Наприклад, для введення 0.02 0.2 -50 2 10 6(для 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

є прийнятним.

Ваші значення не повинні бути такими ж, як наведені вище, залежно від того, як ваша мова обробляє плавання.

Довідкова реалізація

Ось реалізація TIO, яку я написав у Perl, щоб продемонструвати модель. Параметри - параметр нейтрону "балакання" нейрону з паперу, зв'язаного вище, і це демонструє, наскільки ця модель здатна відтворити деякі більш складні властивості нейронів, такі як чергування станів високої та низької активності. Якщо ви подивитеся на вихід, ви можете побачити, де нейрон одразу кілька разів вискакує, але потім чекає деякого часу, перш ніж вискочити ще кілька разів (незважаючи на те, що вхідна напруга клітини Iпостійно є постійним).


Буде tколись негативним?
kamoroso94

1
@ kamoroso94 Ні, ви не зможете імітувати негативний час.
PhiNotPi

Відповіді:


6

R , 110 99 байт

Анонімна функція, яка бере 6 аргументів. Нічого фантазійного, просто прямий порт референтної реалізації. Оновлення u, vдрук та друк vбули об'єднані в один рядок, завдяки тому, що R printповертає значення, яке друкується, тому ви можете використовувати його у призначенні. Велике спасибі Джузеппе за збереження 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()і не існує function(). Однак ви можете, після деякого експерименту, переміщати vта uдекларувати декларації у тіло функції, зберігаючи порядок аргументів, щоб зберегти десяток байтів: Спробуйте це в Інтернеті!
Джузеппе

оскільки vнеобов’язково приймати цілі значення, вам потрібно v>=30, однак
Джузеппе

@Giuseppe Спасибі, ці покращення є фантастичними. Чомусь я не вважав, що явно
маркую

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-го члена.


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

Спробуйте в Інтернеті!

Збережено 2 байти завдяки користувачеві71546 .


@ovs На жаль, ви праві. Слід виправити зараз.
Містер Xcoder

Звертаючись 0.04*v*vдо v*v/25.слід зберегти 1 байт. Якщо поплавці завжди даються, cтоді v*v/25вистачає -2 байт.
Шиеру Асакото

@ceilingcat Якщо ви подивитесь на мою історію редагувань, ви помітите, що я мав v>29у своїй початковій версії. Однак це недійсне vзначення, не обов'язково, є цілим числом.
Містер Xcoder

3

JavaScript (Node.js) , 107 ... 103 101 байт

Сприяв @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 байт Спасибі Арнолд, і -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 байт Спасибі Арнолд, -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 О так, коли я подивився на відповідь Python, то зрозумів, що не оптимізував цього, але не зрозумів, що я також обробляю плавці.; P Виправлено.
Шиеру Асакото

2
Ви можете зберегти два байти, змінивши t-->0на просто t--.
kamoroso94

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Однак це не перемагає рішення.
апспіллери


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пункт у гольф-коді, але змінних просто дуже багато.

EDIT: Дякую @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;_'[ ... ]

Ця частина програми приймає вклад. Він зберігає константи a, b, dі 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~+]

Цей блок ІФ додає 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

Досить проста реалізація, можливо, може бути вдосконалена.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.