% Galvis et al. 2018 (written by Daniel Galvis)
% Class Spiker
% This class is used for all Tonic Spiking neural ensembles

% Spikers activate in response to an input stimulus and stay active for as
% long as that input persists. They take the value of their input, so
% stronger inputs result in a greater degree of activation. They have a max
% activation of 1.

%PROTOCOL FOR USE!!!
% Spikers must be initialized using X = Spiker([intra_delay,extra_delay]);
% At each time step, run X = X.Step([...]) for all Spikers and Bursters, 
% then run X = X.Syn_step([...]) for all Spikers and Bursters.
% See the main code or below for the inputs into each of these functions



classdef Spiker
    properties
        
        %Each of these variables is described in the constructor
        V;
        V_now;
        
        
        S_close;
        S_far;
    end
    properties(GetAccess=private)
        %Each of these variables is described in the constructor
        delays; 
    end
    
    
    
    methods
        %Constructor/Initialization
        function  obj = Spiker(init_delays)
            if nargin>0
            %The initializer has 4 inputs
            %-"delays" should have two values: (1) intra-nucleus delay
            %(timesteps) and (2) extra-nucleus delay (timesteps)
           
            
            obj.delays = init_delays;

           
            % V is the value of the Spiker, but also tracks previous
            % values. The value of synaptic connections is
            % based on previous values of V because of delay
            
            % At each step entry k of this array is updated with the new
            % value of V. k-1...1,n,n-1,...k+1 is the ordering of past
            % values of V (assuming V is an n sized array).
            obj.V = zeros(max(obj.delays),1);
            
            
            %V_now is the index of the immediate value of V
            %obj.V_now = 0; (initialized in Step Function)

            %These are values of the synaptic connections at this timestep
            % S_close is intra/S_far is extra 
            obj.S_close = 0;
            obj.S_far = 0;
            end
            

                     
        end
        
        
        %Step function. Finds the new value of the spiker given it's
        %current value and the values of its excitatory and inhibitory
        %inputs
        function    obj = Step(obj,step_times,step_exc,step_inh)
            
            
            %update index of V at this timestep
            obj.V_now = (1+mod(step_times,size(obj.V,1)));
                    

            % Tonic Spiker
            % The ensemble takes the value of its input, but has a max
            % value of 1.
            % V = 0 if there is inhibition
            
            if(step_inh==0)
                obj.V(obj.V_now) = min([1.0,step_exc]);
             
            else
                obj.V(obj.V_now) = 0;
            end
            %End updating the value of V at this timestep
            
            

     
        end    
    
        
        %This function updates the synaptic weights for both intra and
        %extra nucleus connections. This function should be run AFTER step
        %this function updates these values given the values this timestep
        %for the next timestep
        function    obj = Syn_Step(obj,syn_times)
            
            %moves back the current index by delays(x)-1 units. On the next
            %timestep, this will contain the values of V from the time
            %point delays(x) in the past.
            del_1 = 1+mod(syn_times-obj.delays(1)+1,size(obj.V,1));
            del_2 = 1+mod(syn_times-obj.delays(2)+1,size(obj.V,1));
            
            %Update synaptic weights for intra-nucleus connections
               obj.S_close = obj.V(del_1);
               obj.S_far   = obj.V(del_2);
        end   
    end
end