"""
Simple functions operating on a matrix, potentially modifying it.

These are useful for neuron output functions, normalization of
matrices, etc.

All of these function objects (callable objects) should work for
Numpy array arguments of arbitrary shape.  Some may also work for
scalars.

$Id$
"""
__version__='$Revision$'

import copy

import param

import numpy, numpy.random
import numpy.oldnumeric as Numeric
from numpy import exp,zeros,ones,power

import topo
import topo.base.functionfamily
from topo.base.sheet import activity_type
from topo.base.arrayutil import clip_lower,clip_upper
from topo.base.arrayutil import L2norm, norm
from topo.base.functionfamily import TransferFn
# Imported here so that all TransferFns will be in the same package
from topo.base.functionfamily import IdentityTF


# CEBHACKALERT: these need to respect the mask - which will be passed in.


class PiecewiseLinear(TransferFn):
    """ 
    Piecewise-linear TransferFn with lower and upper thresholds.
    
    Values below the lower_threshold are set to zero, those above
    the upper threshold are set to 1.0, and those in between are
    scaled linearly.
    """
    lower_bound = param.Number(default=0.0,softbounds=(0.0,1.0))
    upper_bound = param.Number(default=1.0,softbounds=(0.0,1.0))
    
    def __call__(self,x):
        fact = 1.0/(self.upper_bound-self.lower_bound)        
        x -= self.lower_bound
        x *= fact
        x.clip(0.0,1.0,out=x)



class Sigmoid(TransferFn):
    """ 
    Sigmoidal (logistic) transfer function: 1/(1+exp-(r*x+k)).

    As defined in Jochen Triesch, ICANN 2005, LNCS 3696 pp. 65-70. 
    The parameters control the growth rate (r) and the x position (k)
    of the exponential.
    
    This function is a special case of the GeneralizedLogistic
    function, with parameters r=r, l=0, u=1, m=-k/2r, and b=1.  See
    Richards, F.J. (1959), A flexible growth function for empirical
    use. J. Experimental Botany 10: 290--300, 1959.
    http://en.wikipedia.org/wiki/Generalised_logistic_curve
    """
    
    r = param.Number(default=1,doc="Parameter controlling the growth rate")
    k = param.Number(default=0,doc="Parameter controlling the x-postion")
    
    def __call__(self,x):
        x_orig = copy.copy(x)
        x *= 0.0
        x += 1.0 / (1.0 + exp(-(self.r*x_orig+self.k)))


                  
class NakaRushton(TransferFn):
    #JABALERT: Please write the equation into words in the docstring, as in Sigmoid.
    """
    Naka-Rushton curve.

    From Naka, K. and Rushton, W. (1996), S-potentials from luminosity
    units in the retina of fish (Cyprinidae). J. Physiology 185:587-599.

    The Naka-Rushton curve has been shown to be a good approximation
    of constrast gain control in cortical neurons.  The input of the
    curve is usually contrast, but under the assumption that the
    firing rate of a model neuron is directly proportional to the
    contrast, it can be used as a TransferFn for a Sheet.
    
    The parameter c50 corresponds to the contrast at which the half of
    the maximal output is reached.  For a Sheet TransferFn this translates
    to the input for which a neuron will respond with activity 0.5.