
import numpy as np
import math
from popkin.utility.kinematic import unwrap

class ReceptiveFieldGaussianAngular(object):
    def __init__(self, theta, sigma):
        self.sigma=sigma
        self.theta=theta
        
    '''
    Evaluate the receptive field. Assumes Stimuli array of form
    Nx2, where N stimuli are given in two-dimensional euclidean
    coordinates
    '''
    def __call__(self, stimuli):
        thetas=np.arctan2(stimuli[:,1],stimuli[:,0])
        n_stimuli=len(thetas)
        self_theta_repeated=np.repeat(self.theta,n_stimuli)
        differences=self_theta_repeated-thetas
        differences[:]=unwrap(differences)
        activations=np.exp(-0.5*(differences**2.0)/self.sigma**2.0)
        activations*=2.0
        activations-=1.0
        return activations

class ReceptiveFieldSineAngular(object):
    def __init__(self, alpha, delta):
        self.delta=delta
        self.alpha=alpha

    def __call__(self, stimuli):
        thetas=np.arctan2(stimuli[:,1],stimuli[:,0])
        
        n_stimuli=len(thetas)
            
        activations=np.sin(self.alpha*(thetas+(2.0*math.pi*self.delta/self.alpha)))
        #activations=0.5*(activations+1.0)
        return activations

class ReceptiveFieldSine2D(object):
    def __init__(self, domain, alpha, delta, theta):
        self.domain=domain
        self.alpha=alpha
        self.delta=delta
        self.theta=theta

    def __call__(self, stimuli):
        
        stimuli=(stimuli-self.domain[:,0])/(self.domain[:,1]-self.domain[:,0])*2.0*math.pi
        n_stimuli=stimuli.shape[0]
        #first project the stimulus onto the primary
        #direction of the sine
        a=np.array([math.cos(self.theta),math.sin(self.theta)])
        a=np.tile(a,(n_stimuli,1))

        s=stimuli
        s_len=(s[:,0]**2.0+s[:,1]**2.0)**0.5
        #a_len=(a[:,0]**2.0+a[:,1]**2.0)**0.5
        
        #print "SHAPES",a.shape,s.shape
        a_dot_s=a[:,0]*s[:,0]+a[:,1]*s[:,1]
        x=a_dot_s#/(a_len*s_len)*s_len
        #print x.shape
        #then, in the rotated dimension of the sine,
        #evaluate the sine function at the projected
        #stimulus
        
        activations=np.sin(self.alpha*(x+(2.0*math.pi*self.delta/self.alpha)))
        #activations=0.5*(activations+1.0)
        #print activations.shape
        return activations


class ReceptiveFieldGaussianPolar(object):
    def __init__(self, radius, angle, sigma_radial, sigma_angular):
        self.radius=radius
        self.theta=angle
        self.sigma_radial=sigma_radial
        self.sigma_angular=sigma_angular

    '''
    Evaluate the receptive field. Assumes Stimuli array of form
    Nx2, where N stimuli are given in two-dimensional euclidean
    coordinates
    '''
    def __call__(self, stimuli):
        #print "----------------"
        #print self.radius, self.theta
        #print "__________________________RECEPTIVE"
        #print stimuli
        thetas=np.arctan2(stimuli[:,1],stimuli[:,0])
        radii=(stimuli[:,1]**2.0+stimuli[:,0]**2.0)**0.5
        #print thetas
        #print radii
        n_stimuli=len(thetas)

        differences_angular=thetas-self.theta
        differences_angular[:]=unwrap(differences_angular)

        differences_radial=radii-self.radius

        #print self.theta, self.radius

        #print differences_angular
        #print differences_radial

        activations=np.exp(-0.5*(differences_angular**2.0/self.sigma_angular**2.0 + differences_radial**2.0 / self.sigma_radial**2.0))

        activations*=2.0
        activations-=1.0
        return activations
