Имитация модели нейрона

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остается постоянным все время).

PhiNotPi
источник
Будет ли tкогда-нибудь отрицательным?
kamoroso94
1
@ kamoroso94 Нет, вы не можете симулировать отрицательное время.
PhiNotPi

Ответы:

6

R , 110 99 байтов

Анонимная функция, которая принимает 6 аргументов. Ничего особенного, просто прямой порт эталонной реализации. Обновление u, vи печать vвсе были объединены в одну линию, благодаря тому , что АиР 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}})

Попробуйте онлайн!

rturnbull
источник
2
Это здорово, +1. Хотя, поскольку вы явно помечаете аргументы, между pryr::f()и function(). Однако после некоторого эксперимента вы можете переместить объявления vи uобъявления в тело функции, сохранив порядок аргументов, чтобы сохранить дюжину байтов: попробуйте это онлайн!
Джузеппе
так как vне обязательно принимать целочисленные значения, вам не нужно v>=30, хотя
Giuseppe
@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-го члена.

Οurous
источник
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 байта благодаря user71546 .

Мистер Xcoder
источник
@ovs Ой, ты прав. Должно быть исправлено сейчас.
г-н Xcoder
Обращение 0.04*v*vк v*v/25.должно сохранить 1 байт. Если float всегда указывается для, 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

Рубин , 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 аргументов.

benj2240
источник
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предложение в коде гольф, но слишком много переменных.

РЕДАКТИРОВАТЬ: Спасибо @ Линн за снятие байта! Я забыл, что вы можете поместить letзаявления в охранников. Конечно, убивает читабельность, хотя

user1472751
источник
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))
Линн
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. Ввод для for 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 и разделить условие и тело на несколько части, чередующиеся с безусловным кодом.

PhiNotPi
источник
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

Довольно простая реализация, вероятно, может быть улучшена.

Крис Лунам
источник