@ -13,7 +13,7 @@ sp.init_printing()
k , x0 , y0 , phi_rf , theta_rf , sigma_x , sigma_y , sigma , x , y , theta_grating , phi_grating = sp . symbols ( r ' k x_0 y_0 \ phi_ {rf} \ theta_ {rf} \ sigma_x \ sigma_y \ sigma x y \ theta_ {grating} \ phi_ {grating} ' )
k , x0 , y0 , phi_rf , theta_rf , sigma_x , sigma_y , sigma , x , y , theta_grating , phi_grating = sp . symbols ( r ' k x_0 y_0 \ phi_ {rf} \ theta_ {rf} \ sigma_x \ sigma_y \ sigma x y \ theta_ {grating} \ phi_ {grating} ' )
defaults = {
defaults = {
k : 6 ,
k : 6 ,
sigma : 0.2 ,
sigma : 1 ,
phi_rf : sp . pi / 2 ,
phi_rf : sp . pi / 2 ,
phi_grating : sp . pi / 2 ,
phi_grating : sp . pi / 2 ,
theta_grating : 0 ,
theta_grating : 0 ,
@ -46,6 +46,31 @@ xy_split = np.arange(-1, 1, 0.05)
phi_split = np . arange ( 0 , 2 * np . pi , np . pi / 100 )
phi_split = np . arange ( 0 , 2 * np . pi , np . pi / 100 )
theta_split = np . arange ( 0 , np . pi , np . pi / 100 )
theta_split = np . arange ( 0 , np . pi , np . pi / 100 )
# The second option is (the distribution function, the function that takes the size and returns the step and the starting point)
Distribution = typing . Union [ float , typing . Dict [ float , float ] , typing . Tuple [ typing . Callable [ [ float ] , float ] , typing . Callable [ [ int ] , typing . Tuple [ float , float ] ] ] ]
def sample_distribution ( distribution : Distribution , size : int = 1 ) - > np . ndarray :
if isinstance ( distribution , float ) or isinstance ( distribution , int ) :
return np . array ( [ float ( distribution ) ] * size )
if isinstance ( distribution , dict ) :
return np . random . choice ( list ( distribution . keys ( ) ) , size , p = list ( distribution . values ( ) ) )
elif isinstance ( distribution , tuple ) :
step , start = distribution [ 1 ] ( size )
res = [ start ]
for i in range ( size ) :
res . append ( res [ - 1 ] + step / distribution [ 0 ] ( res [ - 1 ] ) )
return np . array ( res )
else :
raise ValueError ( f ' Unknown distribution type: { type ( distribution ) } ' )
def get_uniform_dist ( start : float , stop : float ) - > Distribution :
return ( lambda _x : 1 , lambda size : ( ( stop - start ) / ( size - 1 or 1 ) , start ) )
phi_dist_uni = get_uniform_dist ( 0 , 2 * np . pi )
theta_dist_uni = get_uniform_dist ( 0 , np . pi )
def sigmoid ( x ) :
def sigmoid ( x ) :
return 1 / ( 1 + np . exp ( - x ) )
return 1 / ( 1 + np . exp ( - x ) )
@ -60,22 +85,6 @@ class Cell:
y0_val : float = defaults [ y0 ]
y0_val : float = defaults [ y0 ]
k_val : float = defaults [ k ]
k_val : float = defaults [ k ]
@classmethod
def random ( cls ,
phi_dist : np . ndarray = np . ones ( len ( phi_split ) ) ,
theta_dist : np . ndarray = np . ones ( len ( theta_split ) ) ,
sigma_dist : np . ndarray = np . ones ( len ( sigma_split ) ) ,
k_val : float = defaults [ k ] ,
xy_dist : np . ndarray = np . ones ( len ( xy_split ) ) ) :
return cls (
sigma_val = 1 , # np.random.choice(sigma_split, p=sigma_dist / np.sum(sigma_dist)),
phi_val = np . random . choice ( phi_split , p = phi_dist / np . sum ( phi_dist ) ) ,
theta_val = np . random . choice ( theta_split , p = theta_dist / np . sum ( theta_dist ) ) ,
x0_val = 0 , # np.random.choice(xy_split, p=xy_dist / np.sum(xy_dist)),
y0_val = 0 , # np.random.choice(xy_split, p=xy_dist / np.sum(xy_dist)),
k_val = k_val ,
)
@property
@property
def sympy_func ( self ) - > sp . Expr :
def sympy_func ( self ) - > sp . Expr :
return receptive_field \
return receptive_field \
@ -135,12 +144,20 @@ class Population:
@classmethod
@classmethod
def random ( cls , n : int ,
def random ( cls , n : int ,
phi_dist : np . ndarray = np . ones ( len ( phi_split ) ) ,
phi_dist : Distribution = phi_dist_uni ,
theta_dist : np . ndarray = np . ones ( len ( theta_split ) ) ,
theta_dist : Distribution = theta_dist_uni ,
sigma_dist : np . ndarray = np . ones ( len ( sigma_split ) ) ,
sigma_dist : Distribution = defaults [ sigma ] ,
k_val : float = defaults [ k ] ,
k_val : float = defaults [ k ] ,
xy_dist : np . ndarray = np . ones ( len ( xy_split ) ) ) :
xy_dist : Distribution = get_uniform_dist ( - 5 , 5 ) ) :
return cls ( cells = [ Cell . random ( phi_dist , theta_dist , sigma_dist , k_val , xy_dist ) for _ in range ( n ) ] )
return cls ( cells = [
Cell ( phi_val = phi_val , theta_val = theta_val , sigma_val = sigma_val , x0_val = x0_val , y0_val = y0_val , k_val = k_val )
for phi_val , theta_val , sigma_val , x0_val , y0_val in zip (
sample_distribution ( phi_dist , n ) ,
sample_distribution ( theta_dist , n ) ,
sample_distribution ( sigma_dist , n ) ,
sample_distribution ( xy_dist , n ) ,
sample_distribution ( xy_dist , n ) )
] )
def get_response ( self , phi_deg : float , theta_deg : float , coef : float = 4 , use_sigmoid : bool = True ) - > np . ndarray :
def get_response ( self , phi_deg : float , theta_deg : float , coef : float = 4 , use_sigmoid : bool = True ) - > np . ndarray :
return ( sigmoid if use_sigmoid else ( lambda x : x ) ) ( np . array ( [ cell . get_value ( theta_deg , phi_deg ) for cell in self . cells ] ) * coef )
return ( sigmoid if use_sigmoid else ( lambda x : x ) ) ( np . array ( [ cell . get_value ( theta_deg , phi_deg ) for cell in self . cells ] ) * coef )