
'''
Author: Guilherme Marino Toso
Title = integrateandfire
Project = Semi-Supervised Learning Using Competition for Neurons' Synchronization
Package = neurons

Discription:
   A Neural Dynamical System is a set of differential equations that discribes
   the time evolution of the differential equations' variables as the action
   potential generated by a neuron and which is a variable in common with all
   the models. The model presented here is the Integrate And Fire. This model 
   was first studied at a graduation project called "Análise de Sincronização em 
   Modelos de Osciladores Acoplados". 

'''
import numpy as np

class IntegrateAndFire():
    
    
    '''
    This is the Integrate and Fire Neural Dynamical System Model
    '''
    
    def __init__(self, v_rest, r, tau, threshold):
        
        '''
        
        Args:
            
            v_rest: Resting Potential
            r: Neural Resistance, equivalent to a RC circuit
            tau: Time to charge the neuron, equivalent to the capacitor charge time
            threshold: limit potential where occurs the spike.
        
        Dimensions:

            It can be a n-dimensional Numpy array. Each value is 
            respective to a neuron, so, for example: A 1-dimensional
            array of parameters values, means there's a 1-dimensional
            array of neurons.

            Note: the parameters must have the same shape.
        
        Data Type:

            It can be integer ('int') or floating ('float') values.
        
        Returns the parameters of the Integrate and Fire Model
            
        '''
        
        self.v_rest = v_rest
        self.r = r
        self.tau = tau
        self.threshold = threshold
        
        
    def lif(self, v, current):
        
        '''
        Returns the value of the potential based on a RC circuit model

        Args:

            v: membrane potential
            current: external electrical current

        Dimensions:

            It can be a n-dimensional Numpy array. Each value is 
            respective to a neuron, so, for example: A 1-dimensional
            array of parameters values, means there's a 1-dimensional
            array of neurons.

            Note: the parameters must have the same shape.
        
        Data Type:

            It can be integer ('int') or floating ('float') values.

        
        '''
        
        potential = (-(v - self.v_rest) + self.r*current)/self.tau
        
        return potential
    
    def reset(self, v_last, v):
        
        '''
        This function resets the value of the potential to the resting potential
        if the potential is higher or equal to the threshold potential.

        Args:

            v_last: membrante potential of a previous time t-1
            v: membrane potential of actual time t


        Dimensions:

            It can be a n-dimensional Numpy array. Each value is 
            respective to a neuron, so, for example: A 1-dimensional
            array of parameters values, means there's a 1-dimensional
            array of neurons.

            Note: the parameters must have the same shape.

            Note 2: Not necessarily all array values will reset, if it is an array.
            That is why we use np.where and the condition that if the last potential value
            is higher than the threshold, the elements that satisfy this condition will be
            reseted to the resting potential.
        
        Data Type:

            It can be integer ('int') or floating ('float') values.

        Returns an array of membrane potential values, and those which are higher
        than the threshold is reseted to the resting potential (Vrest)
        
        '''
        
        reseted = np.where(v_last>=self.threshold,self.v_rest,v)
        
        return reseted
    
