def subject_likelihood(likelihood_arglist): """ First handle the different cases of what we need to fit and save parameters. They just set the appropriate values of fine_sigma, reward, and punishment depending on the model type and print what is being evaluated by the optimization algorithm.""" log_parameters, model_params = likelihood_arglist curr_params = deepcopy(model_params) # fine_sigma and punishment are fit, reward fixed at 1 sigma = np.array((np.exp(log_parameters[0]), np.exp(log_parameters[1]))) reward = np.exp(log_parameters[2]) punishment = np.exp(log_parameters[3]) alpha = np.exp(log_parameters[4]) print('sigmas = {:.2f}, {:.2f}'.format(*sigma), '; reward = {:.2f}'.format(reward), '; punishment = {:.2f}'.format(punishment), '; alpha = {:.2f}'.format(alpha)) curr_params['sigma'] = sigma curr_params['reward'] = reward curr_params['punishment'] = -punishment curr_params['alpha'] = alpha bellutil = BellmanUtil(**curr_params) curr_params['rho'] = bellutil.rho curr_params['decisions'] = bellutil.decisions obs = ObserverSim(**curr_params) curr_params['fractions'] = obs.fractions likelihood_data = DataLikelihoods(**curr_params) likelihood_data.increment_likelihood(**curr_params) print(likelihood_data.likelihood) return likelihood_data.likelihood
def comparisons(arglist): fine_sigma, i = arglist[0] reward, j = arglist[1] print(i, j) model_params['fine_sigma'] = fine_sigma model_params['reward'] = reward finegr = FineGrained(**model_params) coarse_stats = finegr.coarse_stats model_params['mu'] = coarse_stats[1, :, 0] model_params['sigma'] = coarse_stats[1, :, 1] model_params['N'] = model_params['N_values'][1] bellutil = BellmanUtil(**model_params) model_params['decisions'] = bellutil.decisions sim_params = deepcopy(model_params) sim_params['simulate'] = True fp_params = deepcopy(model_params) fpobs = ObserverSim(**fp_params) simobs = ObserverSim(**sim_params) sim_likelihood = DataLikelihoods(subject_num) fp_likelihood = DataLikelihoods(subject_num) fp_likelihood.increment_likelihood(fpobs.fractions, **fp_params) sim_likelihood.increment_likelihood_legacy(simobs.dist_matrix, simobs.rts_matrix, **sim_params) fp_value = fp_likelihood.likelihood sim_value = sim_likelihood.likelihood return (fp_value, sim_value, i, j)
def likelihood_inner_loop(curr_params): bellutil = BellmanUtil(**curr_params) curr_params['decisions'] = bellutil.decisions obs = ObserverSim(**curr_params) curr_params['fractions'] = obs.fractions return curr_params
def run_model(model_params): finegr = FineGrained(**model_params) model_params['coarse_stats'] = finegr.coarse_stats N_values = model_params['N_values'] dist_computed_params = [] for i, N in enumerate(N_values): curr_params = deepcopy(model_params) curr_params['N'] = N curr_params['mu'] = model_params['coarse_stats'][i, :, 0] curr_params['sigma'] = model_params['coarse_stats'][i, :, 1] bellutil = BellmanUtil(**curr_params) curr_params['decisions'] = bellutil.decisions obs = ObserverSim(**curr_params) curr_params['fractions'] = obs.fractions dist_computed_params.append(curr_params) return dist_computed_params
def __init__(self, log_params, model_type, T, t_w, dt, size, lapse): ''' log_params is either a float (fine sigma) or a 2x1 array with fine sigma and other param model type is formated as tuple with first argument denoting parameters to fits; options are: sig; fits just a fine grained sigma sig_reward; fits fine grained sigma and reward per subject, punishment set to 0 sig_punish; fit fine grain sigma and punishment, reward set to 0 the second argument denoting the reward scheme used in backwards induction options are: sym; symetric reward matrix in reward and punishment epsilon_punish; reward for correct fixed at 1 for both pres/abs correct response asym_reward; reward for correct absent fixed at 1 and the third argument denoting the model used to bootstrap coarse_stats options are: const: constant mapping over all fine_sigma 'sqrt': sqrt scaling of N weighting of fine_sigma sig_reward_sqrt; fits fine grained sigma and reward per subject with sqrt in d mapping inits is a tuple specifying (total time T, intertrival interval t_w, time step dt, size of grid, lapse rate) ''' self.model_type = model_type self.T, self.t_w, self.dt, self.size, self.lapse = T, t_w, dt, size, lapse self.N_array = np.array([8, 12, 16]) self.bell_func = BellmanUtil(self.T, self.t_w, self.size, self.dt) self.g_values = self.bell_func.g_values if model_type[0] == 'sig': self.fine_sigma = np.exp(log_params) self.reward = 1 self.punishment = 0 elif model_type[0] == 'sig_reward': self.fine_sigma = np.exp(log_params[0]) self.reward = np.exp(log_params[1]) self.punishment = 0 elif model_type[0] == 'epsilon_punish': self.fine_sigma = np.exp(log_params[0]) self.reward = 1 self.punishment = np.exp(log_params[1]) else: raise Exception("Invalid entry in first argument of model_type") print('finesig =', self.fine_sigma, 'reward =', self.reward, 'punish =', self.punishment) self.stats = FineGrained(self.fine_sigma, model_type[2], int(1e5)).coarse_stats self.rho_vec = np.zeros(self.stats.shape[0]) self.decision_vec = np.zeros( (self.size, int(self.T / self.dt), self.stats.shape[0])) self.trans_vec = np.zeros((self.size, self.size, self.stats.shape[0])) for i in range(self.stats.shape[0]): mu = self.stats[i, :, 0] sigma = self.stats[i, :, 1] prob_grid = self.bell_func.trans_probs(sigma, mu) self.trans_vec[:, :, i] = prob_grid rho = self.bell_func.solve_rho(self.reward, self.punishment, model_type[1], sigma, mu, prob_grid) self.rho_vec[i] = rho self.decision_vec[:, :, i] = self.bell_func.back_induct( self.reward, self.punishment, rho, sigma, mu, prob_grid, model_type[1])[1]
class OptDDM: def __init__(self, log_params, model_type, T, t_w, dt, size, lapse): ''' log_params is either a float (fine sigma) or a 2x1 array with fine sigma and other param model type is formated as tuple with first argument denoting parameters to fits; options are: sig; fits just a fine grained sigma sig_reward; fits fine grained sigma and reward per subject, punishment set to 0 sig_punish; fit fine grain sigma and punishment, reward set to 0 the second argument denoting the reward scheme used in backwards induction options are: sym; symetric reward matrix in reward and punishment epsilon_punish; reward for correct fixed at 1 for both pres/abs correct response asym_reward; reward for correct absent fixed at 1 and the third argument denoting the model used to bootstrap coarse_stats options are: const: constant mapping over all fine_sigma 'sqrt': sqrt scaling of N weighting of fine_sigma sig_reward_sqrt; fits fine grained sigma and reward per subject with sqrt in d mapping inits is a tuple specifying (total time T, intertrival interval t_w, time step dt, size of grid, lapse rate) ''' self.model_type = model_type self.T, self.t_w, self.dt, self.size, self.lapse = T, t_w, dt, size, lapse self.N_array = np.array([8, 12, 16]) self.bell_func = BellmanUtil(self.T, self.t_w, self.size, self.dt) self.g_values = self.bell_func.g_values if model_type[0] == 'sig': self.fine_sigma = np.exp(log_params) self.reward = 1 self.punishment = 0 elif model_type[0] == 'sig_reward': self.fine_sigma = np.exp(log_params[0]) self.reward = np.exp(log_params[1]) self.punishment = 0 elif model_type[0] == 'epsilon_punish': self.fine_sigma = np.exp(log_params[0]) self.reward = 1 self.punishment = np.exp(log_params[1]) else: raise Exception("Invalid entry in first argument of model_type") print('finesig =', self.fine_sigma, 'reward =', self.reward, 'punish =', self.punishment) self.stats = FineGrained(self.fine_sigma, model_type[2], int(1e5)).coarse_stats self.rho_vec = np.zeros(self.stats.shape[0]) self.decision_vec = np.zeros( (self.size, int(self.T / self.dt), self.stats.shape[0])) self.trans_vec = np.zeros((self.size, self.size, self.stats.shape[0])) for i in range(self.stats.shape[0]): mu = self.stats[i, :, 0] sigma = self.stats[i, :, 1] prob_grid = self.bell_func.trans_probs(sigma, mu) self.trans_vec[:, :, i] = prob_grid rho = self.bell_func.solve_rho(self.reward, self.punishment, model_type[1], sigma, mu, prob_grid) self.rho_vec[i] = rho self.decision_vec[:, :, i] = self.bell_func.back_induct( self.reward, self.punishment, rho, sigma, mu, prob_grid, model_type[1])[1] # def show_bounds(self): # for i in range(self.stats.shape[0]): # decision = self.decision_vec[:, :, i] # plt.figure() # plt.title('N = {}'.format(self.N_array[i])) # plt.imshow(decision) # # def show_trans_probs(self): # for i in range(self.stats.shape[0]): # probs = self.trans_vec[:, :, i] # plt.figure() # plt.title(str(self.N_array[i])) # plt.imshow(probs) def simulate_observer(self, N, C): N_index = list(self.N_array).index(N) dt = self.dt T = self.T g_values = self.g_values if C != 1 and C != 0: raise ValueError('condition C must be 0 (abs) or 1 (pres)') decisions = self.decision_vec[:, :, N_index] mu = self.stats[N_index, :, 0] sigma = self.stats[N_index, :, 1] dec_vec = decisions[:, 0] abs_bound = g_values[np.amax(np.where(dec_vec == 1)[0])] pres_bound = g_values[np.where(dec_vec == 2)[0][0]] D_t = 0 t = 0 g_trajectory = np.ones(int(T / dt)) * 0.5 D_trajectory = np.zeros(int(T / dt)) while t < T: D_t = D_t + norm.rvs(mu[C] * dt, sigma[C] * dt) g_t = self.bell_func.D_to_g(D_t) D_trajectory[int(t / dt)] = D_t g_trajectory[int(t / dt)] = g_t t += dt if g_t < abs_bound: return (0, t, g_trajectory, D_trajectory) if g_t > pres_bound: return (1, t, g_trajectory, D_trajectory) return (np.NaN, T, g_trajectory, D_trajectory) def get_rt(self, N, condition, numsims=5000): C = condition if C != 1 and C != 0: raise Exception('condition must be 0 (abs) or 1 (pres)') observer_outputs = [] for i in range(numsims): observer_outputs.append(self.simulate_observer(N, C)) response_info = np.array([(x[0], x[1]) for x in observer_outputs]) return response_info def get_kde_dist(self, abs_rts, pres_rts, plot=False, ax=None): # 2x2 matrix of distributions, i (row) is the underlying condition C # and j (column) is the response dist = [] sorted_rts = [] perturb = norm.rvs(0, 0.01) sim_rt = [abs_rts, pres_rts] for i in range(2): cur_rt = sim_rt[i] for j in range(2): if not np.any(cur_rt[:, 0] == j): # case where there are none of the responses given in the model simulation dist.append(uniform) sorted_rts.append([]) else: i_j_sim_rt_marked = np.array( cur_rt[np.where(cur_rt[:, 0] == j)[0]]) i_j_sim_rt = i_j_sim_rt_marked[:, 1] # if they are all the same or of size 1, perturb to allow kde if np.var(i_j_sim_rt) == 0 or i_j_sim_rt.size == 1: # if they are all the same, perturb to allow kde i_j_sim_rt = np.append(i_j_sim_rt, i_j_sim_rt[0] + perturb) # if plot and i == j: # if i == 0: # sns.kdeplot(i_j_sim_rt, bw=0.1, shade=True, color='purple', # label='Sim: con. = {0}, resp. = {1}'.format(i, j), ax=ax) # else: # sns.kdeplot(i_j_sim_rt, bw=0.1, shade=True, color='yellow', # label='Sim: con. = {0}, resp. = {1}'.format(i, j), ax=ax) sorted_rts.append([i_j_sim_rt]) dist.append(gaussian_kde(i_j_sim_rt, bw_method=0.1)) return np.reshape(dist, (2, 2)), np.reshape(sorted_rts, (2, 2)) def get_single_N_likelihood(self, data, dist_matrix, sorted_rt, reward): temp = np.mean(np.array(data['rt'])) abs_0_sim_rt_dist = dist_matrix[0, 0] num_abs_0 = len(sorted_rt[0, 0]) pres_1_sim_rt_dist = dist_matrix[1, 1] num_pres_1 = len(sorted_rt[1, 1]) abs_1_sim_rt_dist = dist_matrix[0, 1] num_abs_1 = len(sorted_rt[0, 1]) pres_0_sim_rt_dist = dist_matrix[1, 0] num_pres_0 = len(sorted_rt[1, 0]) total_pres = num_pres_0 + num_pres_1 total_abs = num_abs_0 + num_abs_1 pres_rts_0 = data.query('resp == 2 & target == \'Present\'').rt.values pres_rts_1 = data.query('resp == 1 & target == \'Present\'').rt.values abs_rts_0 = data.query('resp == 2 & target == \'Absent\'').rt.values abs_rts_1 = data.query('resp == 1 & target == \'Absent\'').rt.values # frac_pres_inc = len(pres_rts_0) / (len(pres_rts_0) + len(pres_rts_1)) # frac_pres_corr = len(pres_rts_1) / (len(pres_rts_0) + len(pres_rts_1)) log_like_pres = np.concatenate( (np.log(num_pres_0 / total_pres) + np.log(pres_0_sim_rt_dist.pdf(pres_rts_0)), np.log(num_pres_1 / total_pres) + np.log(pres_1_sim_rt_dist.pdf(pres_rts_1)))) # frac_abs_inc = len(abs_rts_1) / (len(abs_rts_0) + len(abs_rts_1)) # frac_abs_corr = len(abs_rts_0) / (len(abs_rts_0) + len(abs_rts_1)) log_like_abs = np.concatenate( (np.log(num_abs_0 / total_abs) + np.log(abs_0_sim_rt_dist.pdf(abs_rts_0)), np.log(num_abs_1 / total_abs) + np.log(abs_1_sim_rt_dist.pdf(abs_rts_1)))) log_like_all = np.concatenate((log_like_pres, log_like_abs)) likelihood_pertrial = (1 - self.lapse) * np.exp(log_like_all) + \ (self.lapse / 2) * np.exp(-reward / temp) return -np.sum(np.log(likelihood_pertrial)) def get_data_likelihood(self, sub_data): likelihood = 0 data = [ sub_data.query('setsize == 8'), sub_data.query('setsize == 12'), sub_data.query('setsize == 16') ] for i in range(self.stats.shape[0]): N = self.N_array[i] abs_rt = self.get_rt(N, 0) pres_rt = self.get_rt(N, 1) dist_matrix = self.get_kde_dist(abs_rt, pres_rt)[0] sorted_rt = self.get_kde_dist(abs_rt, pres_rt)[1] likelihood += self.get_single_N_likelihood(data[i], dist_matrix, sorted_rt, self.reward) return likelihood
'alpha': 1., 'fine_model': 'const', 'reward_scheme': 'asym_reward', } finegr = FineGrained(**model_params) model_params['coarse_stats'] = finegr.coarse_stats N_values = model_params['N_values'] dist_computed_params = [] for i, N in enumerate(N_values): curr_params = deepcopy(model_params) curr_params['N'] = N curr_params['mu'] = model_params['coarse_stats'][i, :, 0] curr_params['sigma'] = model_params['coarse_stats'][i, :, 1] bellutil = BellmanUtil(**curr_params) curr_params['decisions'] = bellutil.decisions obs = ObserverSim(**curr_params) curr_params['fractions'] = obs.fractions dist_computed_params.append(curr_params) data_eval = DataLikelihoods(**model_params) for single_N_params in dist_computed_params: data_eval.increment_likelihood(**single_N_params) print(data_eval.likelihood) T = model_params['T'] dt = model_params['dt'] fig, axes = plt.subplots(3, 1) t_values = np.arange(0, T, dt) + (dt / 2)
def __init__(self, model_params, tot_samples=70): curr_params = deepcopy(model_params) bellutil = BellmanUtil(**curr_params) curr_params['rho'] = bellutil.rho curr_params['decisions'] = bellutil.decisions decisions = bellutil.decisions for i, column in enumerate(decisions.T): try: upperbound = (column == 2).nonzero()[0][0] lowerbound = (column == 1).nonzero()[0][-1] except IndexError: raise (ValueError, 'Non-existant bounds at some timestep') column[upperbound:] = 2 column[:lowerbound] = 1 decisions[:, i] = column condN = tot_samples // 2 dt = model_params['dt'] T = model_params['T'] t_d = model_params['t_delay'] t_max = model_params['t_max'] - t_d maxind = int(t_max / dt) - 1 t_values = np.arange(0, T, dt) g_values = model_params['g_values'] ev_values = np.zeros((2, tot_samples // 2, t_values.shape[0])) ev_values[0, :, :] = np.random.normal(loc=0, scale=model_params['sigma'][0], size=ev_values.shape[1:]) ev_values[1, :, :] = np.random.normal(loc=1, scale=model_params['sigma'][1], size=ev_values.shape[1:]) g_traces = np.zeros_like(ev_values) for C in (0, 1): for sample in range(condN): for samplen in range(t_values.shape[0]): g_traces[C, sample, samplen] = self.g_t( ev_values[C, sample, :samplen + 1], model_params['mu'], model_params['sigma']) binned_traces = np.digitize(g_traces, g_values, right=True) binned_traces[binned_traces == g_values.shape[0]] = g_values.shape[0] - 1 response_times = np.zeros(ev_values.shape[:-1]) response_idents = np.zeros(ev_values.shape[:-1]) for C in (0, 1): for sample in range(condN): i = 0 while i <= maxind: currdec = decisions[binned_traces[C, sample, i], i] if currdec == 1: response_times[C, sample] = t_values[i] + t_d response_idents[C, sample] = 0 break elif currdec == 2: response_times[C, sample] = t_values[i] + t_d response_idents[C, sample] = 1 break elif (currdec == 0) and (i == maxind): response_times[C, sample] = t_max + t_d response_idents[C, sample] = 2 i += 1 self.response_times = response_times self.response_idents = response_idents self.model_params = curr_params
def __init__(self, subject_num, T, dt, t_w, t_max, size, lapse, mu, N_values, g_values, experiment, N, reward_scheme, tested_params, likelihoods_returned, t_delay, opt_regime=None, **kwargs): model_params = { 'T': 10, 'dt': 0.05, 't_w': 0.5, 't_delay': 0.2, 't_max': 5., 'size': size, 'lapse': 1e-6, 'mu': np.array((0, 1)), 'N': int(N), 'N_values': (8, 12, 16), 'g_values': np.linspace(1e-4, 1 - 1e-4, size), 'subject_num': int(subject_num), 'reward_scheme': 'asym_reward', 'experiment': experiment } curr_params = deepcopy(model_params) self.opt_params = tested_params[np.argmin(likelihoods_returned)] opt_likelihood = np.amin(likelihoods_returned) curr_params['sigma'] = np.exp(self.opt_params[:2]) curr_params['reward'] = np.exp(self.opt_params[2]) curr_params['punishment'] = -np.exp(self.opt_params[3]) curr_params['alpha'] = np.exp(self.opt_params[4]) # If we don't have the decisions, rho, and reaction times for opt params, compute them if not opt_regime: bellutil = BellmanUtil(**curr_params) rho = bellutil.rho decisions = bellutil.decisions obs = ObserverSim(decisions=decisions, **curr_params) fractions = obs.fractions opt_regime = { 'rho': rho, 'decisions': decisions, 'fractions': fractions } curr_params['opt_regime'] = opt_regime curr_params['rho'] = opt_regime['rho'] curr_params['decisions'] = opt_regime['decisions'] curr_params['fractions'] = opt_regime['fractions'] likelihood_data = DataLikelihoods(**curr_params) likelihood_data.increment_likelihood(**curr_params) if not np.abs(likelihood_data.likelihood - opt_likelihood) < 1e-3: warnings.warn( 'Diff between computed likelihood and opt is greater than 0.0001' ) print(likelihood_data.likelihood - opt_likelihood) self.model_params = curr_params self.opt_regim = opt_regime self.N_data = likelihood_data.sub_data.query('setsize == {}'.format(N))