function [stimulus, x0, outputs, soas] = SWMdend1(p_mn, timings, p_ff, p_re, q_ris, p_rid, p_dend, p_stim, initrand, isavename)
% Spatial Working Memory Circuit Incorporating Nonlinear Input Integration in the Dendritic Branches
%
% p_mn : [m n] (number of dendritic branches per neuron / number of neurons) % e.g., [50 50]
% timings : [t_stim_start, t_stim_end, t_final] % e.g., [0 100 200]
% p_ff : [Jsigma_ff, Jbase_ff, Jamp_ff] % e.g., [pi/12 0 1]
% p_re : [Jsigma_re, Jbase_re, Jamp_re] % e.g., [pi/12 0 15]
% q_ris : str_ris % e.g., 2
% p_rid : [Jsigma_rid, Jbase_rid, Jamp_rid, thr_rid] % e.g., [pi/2 2 0 0], [pi/4 0 16 0]
% p_dend : [dend_threshold * m (number of branches), dend_slope, dendrand] % e.g., [0 1 0]
% #dendrand : randomness on the parameters regarding the dendritic nonlinearity, i.e., (standard variation / mean) of threshold, slope, and saturation
% p_stim : [Jsigma_stimulus, Jbase_stimulus, Jamp_stimulus, noiselevel] % e.g., [pi/12 0.5 0 0.2] (BLA), or [pi/12 0.5 0.5 0.2] (WTA)
% initrand : randomness on the initial activities of the neurons will be set to "initrand * rand(n,1)" % e.g., 0.1 or 0 or 0.05
%
% stimulus : actually presented stimulus
% x0 : actual initial activites of the neurons
% outputs: [(1st row) neural activities at the end of the stimulus presentation; (2nd row) neural activities at the end of the simulation]
% soas : time evolution of the "Sum Of Activity"
%
% (e.g)
% dendvar 0.1 + thrdend 0.05 : pi/8 dendritic
% [stim, x0, out, soas] = SWMdend1([100 100],[0 200 400],[pi/12 0 1],[pi/12 0 15],1.6,[pi/8 0 24 0.05],[0.1 5 0.1],[pi/12 0.3 0.1 0.1],0.05,[]);
%
% Kenji Morita
% Mar 2008 @ Tokyo
%%%%% the input dimension and the number of the principal neurons %%%%%
global m n
m = p_mn(1); % input dimension
n = p_mn(2); % number of the principal neurons
%%%%% protocol %%%%%
global t_stim_start t_stim_end t_final
t_stim_start = timings(1);
t_stim_end = timings(2);
t_final = timings(3);
%%%%% connection strengths %%%%%
global ff re str_ris rid thr_rid
% phase (selectivity) of the input layer ('pre') and the output layer ('post')
phase_pre = 2*pi * [0:m-1] / m;
phase_post = 2*pi * [0:n-1] / n;
% feed-forward excitation from the input layer to the output layer
ff = zeros(n,m);
Jsigma_ff = p_ff(1);
Jbase_ff = p_ff(2); % constant baseline (NB: this is not minimum value of the connection)
Jamp_ff = p_ff(3); % amplitude of the exp-cos curve
tmp = (phase_post' * ones(1,m)) - (ones(n,1) * phase_pre); % self - other
phasedifs_ff = min(abs(tmp), 2*pi - abs(tmp)); % NB: be aware of the necessity of this step
ff = (Jamp_ff * exp((cos(phasedifs_ff) - 1) / Jsigma_ff^2) + Jbase_ff) / m; % NB: should be normalized w.r.t. the input dimension
% recurrent excitation between the principal neurons in the output layer
re = zeros(n,n);
Jsigma_re = p_re(1);
Jbase_re = p_re(2); % constant baseline (NB: this is not minimum value of the connection)
Jamp_re = p_re(3); % amplitude of the exp-cos curve
tmp = (phase_post' * ones(1,n)) - (ones(n,1) * phase_post); % self - other
phasedifs_re = min(abs(tmp), 2*pi - abs(tmp)); % NB: be aware of the necessity of this step
re = (Jamp_re * exp((cos(phasedifs_re) - 1) / Jsigma_re^2) + Jbase_re) / n; % NB: should be normalized w.r.t. the number of the neurons
% recurrent somatic inhibition between the principal neurons in the output layer, via soma-targeting GABAergic cell
str_ris = q_ris; % strength of the somatic inhibition
% recurrent dendritic inhibition between the principal neurons in the output layer, via hidden dendrite-targeting GABAergic cells
rid = zeros(n,n);
Jsigma_rid = p_rid(1);
Jbase_rid = p_rid(2); % constant baseline (NB: this is not minimum value of the connection)
Jamp_rid = p_rid(3); % amplitude of the exp-cos curve
tmp = (phase_post' * ones(1,n)) - (ones(n,1) * phase_post); % self - other
phasedifs_rid = min(abs(tmp), 2*pi - abs(tmp)); % NB: be aware of the necessity of this step
rid = (Jamp_rid * exp((cos(phasedifs_rid) - 1) / Jsigma_rid^2) + Jbase_rid) / n; % NB: should be normalized w.r.t. the number of the neurons
thr_rid = p_rid(4); % threshold for dendritic recurrent inhibition
%plot(rid(round(n)/2+1,:));
%%%%% dendritic nonlinearity %%%%%
global dend_threshold dend_slope dend_upperbound % NB: these are n*m matrice
dend_threshold = p_dend(1) * (1/m) * max((1 + p_dend(3) * randn(n,m)), 0);
dend_slope = p_dend(2) * max((1 + p_dend(3) * randn(n,m)), 0);
dend_upperbound = 1/m * max((1 + p_dend(3) * randn(n,m)), 0);
%%%%% input stimulus %%%%%
global stimulus
global stimulus_signal stimulus_noise_level
stimulus = zeros(1,m);
stimcenter = pi; % location (radian) of the stimulus center
Jsigma_stimulus = p_stim(1);
Jbase_stimulus = p_stim(2); % constant baseline (NB: this is not minimum value of the connection)
Jamp_stimulus = p_stim(3); % amplitude of the exp-cos curve
noiselevel = p_stim(4);
tmp = stimcenter - phase_pre; % self - other
phasedifs_stimulus = min(abs(tmp), 2*pi - abs(tmp)); % NB: be aware of the necessity of this step
stimulus_signal = (Jamp_stimulus * exp((cos(phasedifs_stimulus) - 1) / Jsigma_stimulus^2) + Jbase_stimulus);
stimulus_noise_level = noiselevel * Jbase_stimulus;
%stimulus_noise = noiselevel * Jbase_stimulus * randn(1,m);
%stimulus = stimulus_signal + stimulus_noise;
if 1
F = figure;
A = axes;
set(F,'position',[4 406 506 287]);
hold on;
tmp = bar([0.5:1:m-0.5],stimulus_signal,1);
set(tmp,'BarWidth',1,'FaceColor',[0.5 0.5 0.5],'EdgeColor',[0.5 0.5 0.5]);
%shading interp
plot([m/2+0.5 m/2+0.5],[0 1.2],'k:');
axis([0 m 0 1.2]);
set(A,'Box','on');
set(A,'FontName','Ariel','FontSize',18);
set(A,'XTick',[0 m/2+0.5 m],'XTickLabel',[]);
set(A,'YTick',[0:0.2:1.2],'YTickLabel',[]);
if ~isempty(isavename)
print(F,'-depsc',[isavename '_input']);
end
end
%%%%% main ode loop %%%%%
global input_ff input_re input_ris input_rid dend_upperbound J_dend % need to refer to those values to plot each component of the input
x0 = initrand * rand(n,1);
if 1 % Runge-Kutta
tstep_calc = 0.1;
tstep_save = 1;
% until the end of the stimulus presentation
[tseq1, xseq1] = runge4('SWMdend1_fun1', 0, t_stim_end, x0, tstep_calc, tstep_save);
output1 = xseq1(end,:);
% after the extinction of the stimulus
[tseq2, xseq2] = runge4('SWMdend1_fun1', t_stim_end, t_final, output1', tstep_calc, tstep_save);
output2 = xseq2(end,:);
% integrate
tseq = [tseq1(1:end-1); tseq2];
xseq = [xseq1(1:end-1,:); xseq2];
elseif 0 % ode45
odeopt = odeset('NonNegative', [1:n], 'MaxStep', 1);
% until the end of the stimulus presentation
[tseq1,xseq1]=ode45(@SWMdend1_fun1,[0,t_stim_end],x0,odeopt);
output1 = xseq1(end,:);
if 0 % plot the input components
% specify the potential winner and the potential loser neurons
[tmpvalue,pot_win_index] = min(abs(phase_post - stimcenter)); pot_win_index = min(pot_win_index);
[tmpvalue,pot_los_index] = min(abs(phase_post - mod((stimcenter - pi),2*pi))); pot_los_index = min(pot_los_index);
% for the potential winner
F = figure;
A = axes;
set(F,'Position',[516 406 506 287]);
hold on
plot(1:m,input_ff(pot_win_index,:),'m');
plot([1 m],input_re(pot_win_index)/m * ones(1,2),'r');
plot(1:m,J_dend(pot_win_index,:),'g');
plot([1 m],dend_threshold * ones(1,2),'c');
plot([1 m],dend_threshold+dend_upperbound * ones(1,2),'y');
plot([1 m],[0 0],'k');
axis([1 m -dend_upperbound/10 dend_upperbound*1.1]);
set(A,'Box','on');
set(A,'FontName','Ariel','FontSize',18);
set(A,'XTick',[1 (1+m)/2 m],'XTickLabel',[]);
set(A,'YTick',[0],'YTickLabel',[0]);
if ~isempty(isavename)
print(F,'-depsc',[isavename '_pot_win_inputs']);
end
% for the potential loser
F = figure;
A = axes;
set(F,'Position',[516 37 506 287]);
hold on
plot(1:m,input_ff(pot_los_index,:),'m');
plot([1 m],input_re(pot_los_index)/m * ones(1,2),'r');
plot(1:m,J_dend(pot_los_index,:),'g');
plot([1 m],dend_threshold * ones(1,2),'c');
plot([1 m],dend_threshold+dend_upperbound * ones(1,2),'y');
plot([1 m],[0 0],'k');
axis([1 m -dend_upperbound/10 dend_upperbound*1.1]);
set(A,'Box','on');
set(A,'FontName','Ariel','FontSize',18);
set(A,'XTick',[1 (1+m)/2 m],'XTickLabel',[]);
set(A,'YTick',[0],'YTickLabel',[0]);
if ~isempty(isavename)
print(F,'-depsc',[isavename '_pot_los_inputs']);
end
end
% after the extinction of the stimulus
[tseq2,xseq2]=ode45(@SWMdend1_fun1,[t_stim_end,t_final],output1',odeopt);
output2 = xseq2(end,:);
% integrate
tmp_tseq = [tseq1; tseq2(2:end)];
tmp_xseq = [xseq1; xseq2(2:end,:)];
tseq = [0:t_final]';
xseq = interp1(tmp_tseq,tmp_xseq,tseq);
end
% output variables
outputs = [output1; output2];
soas = sum(xseq,2);
%%%%% plot the neural activities %%%%%
% stimulus end
if 1
% calculate the peak location
tmp_cos = sum(output1 .* cos(2*pi*[0:1/n:(n-1)/n]));
tmp_sin = sum(output1 .* sin(2*pi*[0:1/n:(n-1)/n]));
tmp_peak = atan(tmp_sin / tmp_cos) / (2*pi);
if tmp_cos < 0
tmp_peak = tmp_peak + 0.5;
elseif tmp_sin < 0 % (& tmp_cos > 0)
tmp_peak = tmp_peak + 1;
end
peak1 = tmp_peak;
% plot
F = figure;
A = axes;
set(F,'Position',[516 406 506 287]);
hold on;
tmp = bar([0.5:1:n-0.5],output1,1);
set(tmp,'BarWidth',1,'FaceColor','r','Edgecolor','r');
plot([n/2+0.5 n/2+0.5],[0 1.2],'k:');
plot([n*peak1+0.5 n*peak1+0.5],[0 1.2],'k'); % NB: 'n*' is necessary, and also, '+0.5' is necessary to correct the shift of 'bar'
axis([0 n 0 1.2]); % for 'bar'
set(A,'Box','on');
set(A,'FontName','Ariel','FontSize',18);
set(A,'XTick',[0 n/2+0.5 n],'XTickLabel',[]); % for 'bar'
set(A,'YTick',[0 1],'YTickLabel',[]);
%set(A,'PlotBoxAspectRatio',[2 1 1]);
if ~isempty(isavename)
print(F,'-depsc',[isavename '_output1']);
end
end
% final
if 1
% calculate the peak location
tmp_cos = sum(output2 .* cos(2*pi*[0:1/n:(n-1)/n]));
tmp_sin = sum(output2 .* sin(2*pi*[0:1/n:(n-1)/n]));
tmp_peak = atan(tmp_sin / tmp_cos) / (2*pi);
if tmp_cos < 0
tmp_peak = tmp_peak + 0.5;
elseif tmp_sin < 0 % (& tmp_cos > 0)
tmp_peak = tmp_peak + 1;
end
peak2 = tmp_peak;
% plot
F = figure;
A = axes;
set(F,'Position',[516 37 506 287]);
hold on;
tmp = bar([0.5:1:n-0.5],output2,1);
set(tmp,'BarWidth',1,'FaceColor','r','Edgecolor','r');
plot([n/2+0.5 n/2+0.5],[0 1.2],'k:');
plot([n*peak2+0.5 n*peak2+0.5],[0 1.2],'k'); % NB: 'n*' is necessary, and also, '+0.5' is necessary to correct the shift of 'bar'
axis([0 n 0 1.2]); % for 'bar'
set(A,'Box','on');
set(A,'FontName','Ariel','FontSize',18);
set(A,'XTick',[0 n/2+0.5 n],'XTickLabel',[]); % for 'bar'
set(A,'YTick',[0 1],'YTickLabel',[]);
%set(A,'PlotBoxAspectRatio',[2 1 1]);
if ~isempty(isavename)
print(F,'-depsc',[isavename '_output2']);
end
end
% activity evolution 2D
if 1
F = figure;
A = axes;
set(F,'Position',[4 37 506 287]);
hold on;
image_amp = 60; % just for nice view
image_power = 1/3; % just for nice view
image_matrix = max(0, fliplr(xseq')'); % just to avoid infinitesimal negative value "-0.0000", which causes problem if imposed by '.^(1/3) etc'.
O = image(image_amp * image_matrix.^(image_power));
L = plot([0.5+(n/2+0.5) 0.5+(n/2+0.5)],[0.5 t_final+0.5],'w'); % '0.5+' is because 'image' plot starts at 0.5. '+0.5)' is because of the band width.
%C = colorbar;
axis([0.5 n+0.5 0.5 t_final+1.5]); % '0.5' is because 'image' plot starts at 0.5.
set(A,'Box','on');
set(A,'FontName','Ariel','FontSize',18);
set(A,'XTick',[0.5 0.5+(n/2+0.5) n+0.5],'XTickLabel',[]);
set(A,'YTick',[0.5 200.5 401.5],'YTickLabel',[400 200 0]);
set(A,'PlotBoxAspectRatio',[1 1.5 1]);
%set(C,'YTick',[0 image_amp],'YTickLabel',[]);
if ~isempty(isavename)
print(F,'-depsc',[isavename '_2D']);
end
end
%%%%% Runge-Kutta %%%%%
function [tseq, xseq] = runge4(fun_name, t_init, t_end, x_init, tstep_calc, tstep_save)
howoftensave = tstep_save / tstep_calc; % this SHOULD BE an integer
howmanystep = (t_end - t_init) / tstep_calc; % this SHOULD BE an integer
tseq = [t_init:tstep_save:t_end]';
xseq = zeros(length(tseq),length(x_init));
xseq(1,:) = x_init';
t = t_init;
x = x_init;
for k = 1:howmanystep
tmp1 = tstep_calc * feval(fun_name, t, x);
tmp2 = tstep_calc * feval(fun_name, t+tstep_calc/2, x+tmp1/2);
tmp3 = tstep_calc * feval(fun_name, t+tstep_calc/2, x+tmp2/2);
tmp4 = tstep_calc * feval(fun_name, t+tstep_calc, x+tmp3);
delta = (tmp1 + tmp4) / 6 + (tmp2 + tmp3) / 3;
x = x + delta;
if mod(k, howoftensave) == 0
xseq((k/howoftensave)+1,:) = x';
end
t = t + tstep_calc;
end
%%%%% dynamics of neural activity %%%%%
function diff_x = SWMdend1_fun1(t,x)
global t_stim_start t_stim_end t_final
global m n
global ff re str_ris rid thr_rid
global dend_threshold dend_slope dend_upperbound
global stimulus_signal stimulus_noise_level
global input_ff input_re input_ris input_rid dend_upperbound J_dend
% determine the stimulus at this time (it is changing because of the presumed dynamic noise)
stimulus = stimulus_signal + stimulus_noise_level * randn(1,m);
% whether the stimulus is presented or not
if (t_stim_start <= t) && (t <= t_stim_end)
current_stimulus = stimulus;
else
current_stimulus = zeros(1,m);
end
input_ff = ff .* (ones(n,1) * current_stimulus); % n*m matrix
input_re = re * x; % n*1 matrix
input_ris = str_ris * (1/n) * sum(x);
input_rid = max((rid * x - thr_rid), 0); % n*1 matrix
% dendritic saturation, rather than somatic saturation
J_dend = (input_ff + (input_re * ones(1,m))/m) ./ (1 + (input_rid * ones(1,m))); % divisive inhibition on the dendritic input (before thresholding)
dend_output = min(dend_slope .* max(J_dend - dend_threshold, 0), dend_upperbound);
diff_x = -x + max(sum(dend_output,2) - input_ris, 0);