def _params_spec_from_attributes(attr): csv = csv_template(attr["num_types"]) bounds = np.array(attr["optim_paras"]["paras_bounds"]) csv["lower"] = bounds[:, 0] csv["upper"] = bounds[:, 1] csv["fixed"] = attr["optim_paras"]["paras_fixed"] csv["para"] = get_optim_paras( paras_dict=attr["optim_paras"], num_paras=attr["num_paras"], which="all", is_debug=True, ) return csv
def test_1(self): """ Testing whether back-and-forth transformation have no effect. """ for _ in range(10): num_types = np.random.randint(1, 5) num_paras = 53 + (num_types - 1) * 6 # Create random parameter vector base = np.random.uniform(size=num_paras) x = base.copy() # Apply numerous transformations for _ in range(10): optim_paras = distribute_parameters(x, is_debug=True) args = (optim_paras, num_paras, "all", True) x = get_optim_paras(*args) np.testing.assert_allclose(base, x)
def scripts_modify(identifiers, action, init_file, values=None, bounds=None): """ Modify optimization parameters by either changing their status or values. """ # Select interface is_bounds = action == "bounds" is_fixed = action == "fix" # Baseline init_dict = read_init_file(init_file) respy_obj = RespyCls(init_file) optim_paras, num_paras, num_types = dist_class_attributes( respy_obj, "optim_paras", "num_paras", "num_types") # We now need to ensure a consistent perspective, i.e. all are the parameter values # as specified in the initialization file. x = get_optim_paras(optim_paras, num_paras, "all", True) x[43:53] = cholesky_to_coeffs(optim_paras["shocks_cholesky"]) if action == "value": for i, j in enumerate(identifiers): x[j] = values[i] for identifier in identifiers: if identifier in [0]: j = identifier init_dict["BASICS"]["coeffs"][j] = x[identifier] if is_fixed: init_dict["BASICS"]["fixed"][j] = is_fixed elif is_bounds: init_dict["BASICS"]["bounds"][j] = bounds elif identifier in list(range(1, 3)): j = identifier - 1 init_dict["COMMON"]["coeffs"][j] = x[identifier] if is_fixed: init_dict["COMMON"]["fixed"][j] = is_fixed elif is_bounds: init_dict["COMMON"]["bounds"][j] = bounds elif identifier in list(range(3, 18)): j = identifier - 3 init_dict["OCCUPATION A"]["coeffs"][j] = x[identifier] if is_fixed: init_dict["OCCUPATION A"]["fixed"][j] = is_fixed elif is_bounds: init_dict["OCCUPATION A"]["bounds"][j] = bounds elif identifier in list(range(18, 33)): j = identifier - 18 init_dict["OCCUPATION B"]["coeffs"][j] = x[identifier] if is_fixed: init_dict["OCCUPATION B"]["fixed"][j] = is_fixed elif is_bounds: init_dict["OCCUPATION B"]["bounds"][j] = bounds elif identifier in list(range(33, 40)): j = identifier - 33 init_dict["EDUCATION"]["coeffs"][j] = x[identifier] if is_fixed: init_dict["EDUCATION"]["fixed"][j] = is_fixed elif is_bounds: init_dict["EDUCATION"]["bounds"][j] = bounds elif identifier in list(range(40, 43)): j = identifier - 40 init_dict["HOME"]["coeffs"][j] = x[identifier] if is_fixed: init_dict["HOME"]["fixed"][j] = is_fixed elif is_bounds: init_dict["HOME"]["bounds"][j] = bounds elif identifier in list(range(43, 53)): j = identifier - 43 init_dict["SHOCKS"]["coeffs"][j] = x[identifier] if is_fixed: init_dict["SHOCKS"]["fixed"][j] = is_fixed elif is_bounds: init_dict["SHOCKS"]["bounds"][j] = bounds elif identifier in list(range(53, 53 + (num_types - 1) * 2)): j = identifier - 53 init_dict["TYPE SHARES"]["coeffs"][j] = x[identifier] if is_fixed: init_dict["TYPE SHARES"]["fixed"][j] = is_fixed elif is_bounds: init_dict["TYPE SHARES"]["bounds"][j] = bounds elif identifier in list(range(53 + (num_types - 1) * 2, num_paras)): j = identifier - (53 + (num_types - 1) * 2) init_dict["TYPE SHIFTS"]["coeffs"][j] = x[identifier] if is_fixed: init_dict["TYPE SHIFTS"]["fixed"][j] = is_fixed elif is_bounds: init_dict["TYPE SHIFTS"]["bounds"][j] = bounds else: raise NotImplementedError # Check that the new candidate initialization file is valid. If so, go ahead and # replace the original file. write_init_file(init_dict, ".tmp.respy.ini") RespyCls(".tmp.respy.ini") shutil.move(".tmp.respy.ini", init_file)
def respy_interface(respy_obj, request, data=None): """Provide the interface to the PYTHON functionality.""" # Distribute class attributes ( optim_paras, num_periods, edu_spec, is_debug, num_draws_prob, seed_prob, num_draws_emax, seed_emax, is_interpolated, num_points_interp, maxfun, optimizer_used, tau, optimizer_options, seed_sim, num_agents_sim, file_sim, precond_spec, num_types, num_paras, num_agents_est, ) = dist_class_attributes( respy_obj, "optim_paras", "num_periods", "edu_spec", "is_debug", "num_draws_prob", "seed_prob", "num_draws_emax", "seed_emax", "is_interpolated", "num_points_interp", "maxfun", "optimizer_used", "tau", "optimizer_options", "seed_sim", "num_agents_sim", "file_sim", "precond_spec", "num_types", "num_paras", "num_agents_est", ) if request == "estimate": periods_draws_prob = create_draws( num_periods, num_draws_prob, seed_prob, is_debug ) periods_draws_emax = create_draws( num_periods, num_draws_emax, seed_emax, is_debug ) # Construct starting values x_optim_free_unscaled_start = get_optim_paras( optim_paras, num_paras, "free", is_debug ) x_optim_all_unscaled_start = get_optim_paras( optim_paras, num_paras, "all", is_debug ) # Construct the state space state_space = StateSpace( num_periods, num_types, edu_spec["start"], edu_spec["max"] ) # Collect arguments that are required for the criterion function. # These must be in the correct order already. args = ( is_interpolated, num_points_interp, is_debug, data, tau, periods_draws_emax, periods_draws_prob, state_space, ) # Special case where just one evaluation at the starting values is # requested is accounted for. Note, that the relevant value of the # criterion function is always the one indicated by the class attribute # and not the value returned by the optimization algorithm. num_free = optim_paras["paras_fixed"].count(False) # Take only bounds from unfixed parameters and insert default bounds. mask_paras_fixed = np.array(optim_paras["paras_fixed"]) paras_bounds_free_unscaled = np.array(optim_paras["paras_bounds"])[ ~mask_paras_fixed ] paras_bounds_free_unscaled[:, 0] = np.where( paras_bounds_free_unscaled[:, 0] == None, # noqa: E711 -HUGE_FLOAT, paras_bounds_free_unscaled[:, 0], ) paras_bounds_free_unscaled[:, 1] = np.where( paras_bounds_free_unscaled[:, 1] == None, # noqa: E711 HUGE_FLOAT, paras_bounds_free_unscaled[:, 1], ) record_estimation_scaling( x_optim_free_unscaled_start, None, None, None, optim_paras["paras_fixed"], True, ) precond_matrix = get_precondition_matrix( precond_spec, optim_paras, x_optim_all_unscaled_start, args, maxfun, num_paras, num_types, ) x_optim_free_scaled_start = apply_scaling( x_optim_free_unscaled_start, precond_matrix, "do" ) paras_bounds_free_scaled = np.full((num_free, 2), np.nan) for i in range(2): paras_bounds_free_scaled[:, i] = apply_scaling( paras_bounds_free_unscaled[:, i], precond_matrix, "do" ) record_estimation_scaling( x_optim_free_unscaled_start, x_optim_free_scaled_start, paras_bounds_free_scaled, precond_matrix, optim_paras["paras_fixed"], False, ) opt_obj = OptimizationClass( x_optim_all_unscaled_start, optim_paras["paras_fixed"], precond_matrix, num_types, ) opt_obj.maxfun = maxfun if maxfun == 0: record_estimation_scalability("Start") opt_obj.crit_func(x_optim_free_scaled_start, *args) record_estimation_scalability("Finish") success = True message = "Single evaluation of criterion function at starting values." elif optimizer_used == "SCIPY-BFGS": bfgs_maxiter = optimizer_options["SCIPY-BFGS"]["maxiter"] bfgs_gtol = optimizer_options["SCIPY-BFGS"]["gtol"] bfgs_eps = optimizer_options["SCIPY-BFGS"]["eps"] try: rslt = fmin_bfgs( opt_obj.crit_func, x_optim_free_scaled_start, args=args, gtol=bfgs_gtol, epsilon=bfgs_eps, maxiter=bfgs_maxiter, full_output=True, disp=False, ) success = rslt[6] not in [1, 2] message = "Optimization terminated successfully." if rslt[6] == 1: message = "Maximum number of iterations exceeded." elif rslt[6] == 2: message = "Gradient and/or function calls not changing." except MaxfunError: success = False message = "Maximum number of iterations exceeded." elif optimizer_used == "SCIPY-LBFGSB": lbfgsb_maxiter = optimizer_options["SCIPY-LBFGSB"]["maxiter"] lbfgsb_maxls = optimizer_options["SCIPY-LBFGSB"]["maxls"] lbfgsb_factr = optimizer_options["SCIPY-LBFGSB"]["factr"] lbfgsb_pgtol = optimizer_options["SCIPY-LBFGSB"]["pgtol"] lbfgsb_eps = optimizer_options["SCIPY-LBFGSB"]["eps"] lbfgsb_m = optimizer_options["SCIPY-LBFGSB"]["m"] try: rslt = fmin_l_bfgs_b( opt_obj.crit_func, x_optim_free_scaled_start, args=args, approx_grad=True, bounds=paras_bounds_free_scaled, m=lbfgsb_m, factr=lbfgsb_factr, pgtol=lbfgsb_pgtol, epsilon=lbfgsb_eps, iprint=-1, maxfun=maxfun, maxiter=lbfgsb_maxiter, maxls=lbfgsb_maxls, ) success = rslt[2]["warnflag"] in [0] message = rslt[2]["task"] except MaxfunError: success = False message = "Maximum number of iterations exceeded." elif optimizer_used == "SCIPY-POWELL": powell_maxiter = optimizer_options["SCIPY-POWELL"]["maxiter"] powell_maxfun = optimizer_options["SCIPY-POWELL"]["maxfun"] powell_xtol = optimizer_options["SCIPY-POWELL"]["xtol"] powell_ftol = optimizer_options["SCIPY-POWELL"]["ftol"] try: rslt = fmin_powell( opt_obj.crit_func, x_optim_free_scaled_start, args, powell_xtol, powell_ftol, powell_maxiter, powell_maxfun, disp=0, ) success = rslt[5] not in [1, 2] message = "Optimization terminated successfully." if rslt[5] == 1: message = "Maximum number of function evaluations." elif rslt[5] == 2: message = "Maximum number of iterations." except MaxfunError: success = False message = "Maximum number of iterations exceeded." else: raise NotImplementedError record_estimation_final(success, message) record_estimation_stop() elif request == "simulate": # Draw draws for the simulation. periods_draws_sims = create_draws( num_periods, num_agents_sim, seed_sim, is_debug ) # Draw standard normal deviates for the solution and evaluation step. periods_draws_emax = create_draws( num_periods, num_draws_emax, seed_emax, is_debug ) # Collect arguments for different implementations of the simulation. state_space = pyth_solve( is_interpolated, num_points_interp, num_periods, is_debug, periods_draws_emax, edu_spec, optim_paras, file_sim, num_types, ) simulated_data = pyth_simulate( state_space, num_agents_sim, periods_draws_sims, seed_sim, file_sim, edu_spec, optim_paras, is_debug, ) args = (state_space, simulated_data) else: raise NotImplementedError("This request is not implemented.") return args
def test_10(self): """ This test ensures that the order of the initial schooling level specified in the initialization files does not matter for the simulation of a dataset and subsequent evaluation of the criterion function. Warning ------- This test fails if types have the identical intercept as no unique ordering is determined than. """ point_constr = { "estimation": { "maxfun": 0 }, # We cannot allow for interpolation as the order of states within each # period changes and thus the prediction model is altered even if the same # state identifier is used. "interpolation": { "flag": False }, } params_spec, options_spec = generate_random_model( point_constr=point_constr) respy_obj = RespyCls(params_spec, options_spec) edu_baseline_spec, num_types, num_paras, optim_paras = dist_class_attributes( respy_obj, "edu_spec", "num_types", "num_paras", "optim_paras") # We want to randomly shuffle the list of initial schooling but need to maintain # the order of the shares. edu_shuffled_start = np.random.permutation( edu_baseline_spec["start"]).tolist() edu_shuffled_share, edu_shuffled_lagged = [], [] for start in edu_shuffled_start: idx = edu_baseline_spec["start"].index(start) edu_shuffled_lagged += [edu_baseline_spec["lagged"][idx]] edu_shuffled_share += [edu_baseline_spec["share"][idx]] edu_shuffled_spec = copy.deepcopy(edu_baseline_spec) edu_shuffled_spec["lagged"] = edu_shuffled_lagged edu_shuffled_spec["start"] = edu_shuffled_start edu_shuffled_spec["share"] = edu_shuffled_share # We are only looking at a single evaluation as otherwise the reordering affects # the optimizer that is trying better parameter values one-by-one. The # reordering might also violate the bounds. for i in range(53, num_paras): optim_paras["paras_bounds"][i] = [None, None] optim_paras["paras_fixed"][i] = False # We need to ensure that the baseline type is still in the first position. types_order = [0] + np.random.permutation(range(1, num_types)).tolist() type_shares = [] for i in range(num_types): lower, upper = i * 2, (i + 1) * 2 type_shares += [optim_paras["type_shares"][lower:upper].tolist()] optim_paras_baseline = copy.deepcopy(optim_paras) optim_paras_shuffled = copy.deepcopy(optim_paras) list_ = [ optim_paras["type_shifts"][i, :].tolist() for i in types_order ] optim_paras_shuffled["type_shifts"] = np.array(list_) list_ = [type_shares[i] for i in types_order] optim_paras_shuffled["type_shares"] = np.array(list_).flatten() base_data, base_val = None, None k = 0 for optim_paras in [optim_paras_baseline, optim_paras_shuffled]: for edu_spec in [edu_baseline_spec, edu_shuffled_spec]: respy_obj.unlock() respy_obj.set_attr("edu_spec", edu_spec) respy_obj.lock() # There is some more work to do to update the coefficients as we # distinguish between the economic and optimization version of the # parameters. x = get_optim_paras(optim_paras, num_paras, "all", True) shocks_cholesky, _ = extract_cholesky(x) shocks_coeffs = cholesky_to_coeffs(shocks_cholesky) x[43:53] = shocks_coeffs respy_obj.update_optim_paras(x) respy_obj.reset() simulate_observed(respy_obj) # This part checks the equality of simulated dataset. data_frame = pd.read_csv("data.respy.dat", delim_whitespace=True) if base_data is None: base_data = data_frame.copy() assert_frame_equal(base_data, data_frame) # This part checks the equality of a single function evaluation. _, val = respy_obj.fit() if base_val is None: base_val = val np.testing.assert_almost_equal(base_val, val) respy_obj.reset() k += 1
def check_model_attributes(attr_dict): a = attr_dict # Number of parameters assert isinstance(a["num_paras"], int) assert a["num_paras"] >= 53 # Parallelism assert isinstance(a["num_procs"], int) assert a["num_procs"] > 0 if a["num_procs"] > 1: assert a["version"] == "fortran" assert isinstance(a["num_procs"], int) assert a["num_procs"] > 0 if a["num_procs"] > 1: assert a["version"] == "fortran" assert IS_PARALLELISM_MPI # Version version of package assert a["version"] in ["fortran", "python"] if a["version"] == "fortran": assert IS_FORTRAN assert isinstance(a["num_threads"], int) assert a["num_threads"] >= 1 if a["num_threads"] >= 2: assert a["version"] == "fortran" assert IS_PARALLELISM_OMP # Debug status assert a["is_debug"] in [True, False] # Forward-looking agents assert a["is_myopic"] in [True, False] # Seeds for seed in [a["seed_emax"], a["seed_sim"], a["seed_prob"]]: assert np.isfinite(seed) assert isinstance(seed, int) assert seed > 0 # Number of agents for num_agents in [a["num_agents_sim"], a["num_agents_est"]]: assert np.isfinite(num_agents) assert isinstance(num_agents, int) assert num_agents > 0 # Number of periods assert np.isfinite(a["num_periods"]) assert isinstance(a["num_periods"], int) assert a["num_periods"] > 0 # Number of draws for Monte Carlo integration assert np.isfinite(a["num_draws_emax"]) assert isinstance(a["num_draws_emax"], int) assert a["num_draws_emax"] >= 0 # Debugging mode assert a["is_debug"] in [True, False] # Window for smoothing parameter assert isinstance(a["tau"], float) assert a["tau"] > 0 # Interpolation assert a["is_interpolated"] in [True, False] assert isinstance(a["num_points_interp"], int) assert a["num_points_interp"] > 0 # Simulation of S-ML assert isinstance(a["num_draws_prob"], int) assert a["num_draws_prob"] > 0 # Maximum number of iterations assert isinstance(a["maxfun"], int) assert a["maxfun"] >= 0 # Optimizers assert a["optimizer_used"] in OPT_EST_FORT + OPT_EST_PYTH # Scaling assert a["precond_spec"]["type"] in ["identity", "gradient", "magnitudes"] for key_ in ["minimum", "eps"]: assert isinstance(a["precond_spec"][key_], float) assert a["precond_spec"][key_] > 0.0 # Education assert isinstance(a["edu_spec"]["max"], int) assert a["edu_spec"]["max"] > 0 assert isinstance(a["edu_spec"]["start"], list) assert len(a["edu_spec"]["start"]) == len(set(a["edu_spec"]["start"])) assert all(isinstance(item, int) for item in a["edu_spec"]["start"]) assert all(item > 0 for item in a["edu_spec"]["start"]) assert all(item <= a["edu_spec"]["max"] for item in a["edu_spec"]["start"]) assert all(isinstance(item, float) for item in a["edu_spec"]["share"]) assert all(0 <= item <= 1 for item in a["edu_spec"]["lagged"]) assert all(0 <= item <= 1 for item in a["edu_spec"]["share"]) np.testing.assert_almost_equal(np.sum(a["edu_spec"]["share"]), 1.0, decimal=4) # Derivatives assert a["derivatives"] in ["forward-differences"] # Check model parameters check_model_parameters(a["optim_paras"]) # Check that all parameter values are within the bounds. x = get_optim_paras(a["optim_paras"], a["num_paras"], "all", True) # It is not clear at this point how to impose parameter constraints on # the covariance matrix in a flexible manner. So, either all fixed or # none. As a special case, we also allow for all off-diagonal elements # to be fixed to zero. shocks_coeffs = a["optim_paras"]["shocks_cholesky"][np.tril_indices(4)] shocks_fixed = np.array(a["optim_paras"]["paras_fixed"][43:53]) all_free = not shocks_fixed.any() dim = len(a["optim_paras"]["shocks_cholesky"]) helper = np.zeros((dim, dim)) helper[np.tril_indices(dim)] = shocks_coeffs off_diagonals_zero = np.diag(helper).sum() == helper.sum() helper = np.zeros((dim, dim), dtype=bool) helper[np.tril_indices(dim)] = shocks_fixed off_diagonals_fixed = (helper[np.tril_indices(dim, k=-1)]).all() diagonal_matrix = off_diagonals_zero & off_diagonals_fixed if not (all_free or shocks_fixed.all() or diagonal_matrix): raise UserError(" Misspecified constraints for covariance matrix") # Discount rate and type shares need to be larger than on at all times. for label in ["paras_fixed", "paras_bounds"]: assert isinstance(a["optim_paras"][label], list) assert len(a["optim_paras"][label]) == a["num_paras"] for i in range(1): assert a["optim_paras"]["paras_bounds"][i][0] >= 0.00 for i in range(a["num_paras"]): lower, upper = a["optim_paras"]["paras_bounds"][i] if lower is not None: assert isinstance(lower, float) assert lower <= x[i] assert abs(lower) < PRINT_FLOAT if upper is not None: assert isinstance(upper, float) assert upper >= x[i] assert abs(upper) < PRINT_FLOAT if (upper is not None) and (lower is not None): assert upper >= lower _check_optimizer_options(a["optimizer_options"])
def test_5(self): """ This methods ensures that the core functions yield the same results across implementations. """ params_spec, options_spec = generate_random_model() respy_obj = RespyCls(params_spec, options_spec) # Ensure that backward induction routines use the same grid for the # interpolation. max_states_period = write_interpolation_grid(respy_obj) # Extract class attributes ( num_periods, edu_spec, optim_paras, num_draws_emax, is_debug, is_interpolated, num_points_interp, is_myopic, num_agents_sim, num_draws_prob, tau, seed_sim, num_agents_est, optimizer_options, file_sim, num_types, num_paras, ) = dist_class_attributes( respy_obj, "num_periods", "edu_spec", "optim_paras", "num_draws_emax", "is_debug", "is_interpolated", "num_points_interp", "is_myopic", "num_agents_sim", "num_draws_prob", "tau", "seed_sim", "num_agents_est", "optimizer_options", "file_sim", "num_types", "num_paras", ) min_idx = edu_spec["max"] + 1 shocks_cholesky = optim_paras["shocks_cholesky"] coeffs_common = optim_paras["coeffs_common"] coeffs_home = optim_paras["coeffs_home"] coeffs_edu = optim_paras["coeffs_edu"] coeffs_a = optim_paras["coeffs_a"] coeffs_b = optim_paras["coeffs_b"] delta = optim_paras["delta"] type_spec_shares = optim_paras["type_shares"] type_spec_shifts = optim_paras["type_shifts"] # Write out random components and interpolation grid to align the three # implementations. max_draws = max(num_agents_sim, num_draws_emax, num_draws_prob) write_types(type_spec_shares, num_agents_sim) write_edu_start(edu_spec, num_agents_sim) write_draws(num_periods, max_draws) write_lagged_start(num_agents_sim) # It is critical that the model is simulated after all files have been written # to the disk because they are picked up in the subroutines. respy_obj = simulate_observed(respy_obj) periods_draws_emax = read_draws(num_periods, num_draws_emax) periods_draws_prob = read_draws(num_periods, num_draws_prob) periods_draws_sims = read_draws(num_periods, num_agents_sim) fort, _ = resfort_interface(respy_obj, "simulate") state_space = pyth_solve( is_interpolated, num_points_interp, num_periods, is_debug, periods_draws_emax, edu_spec, optim_paras, file_sim, num_types, ) ( states_all, mapping_state_idx, periods_rewards_systematic, periods_emax, ) = state_space._get_fortran_counterparts() py = ( periods_rewards_systematic, state_space.states_per_period, mapping_state_idx, periods_emax, states_all, ) f2py = fort_debug.wrapper_solve( is_interpolated, num_points_interp, num_draws_emax, num_periods, is_myopic, is_debug, periods_draws_emax, min_idx, edu_spec["start"], edu_spec["max"], coeffs_common, coeffs_a, coeffs_b, coeffs_edu, coeffs_home, shocks_cholesky, delta, file_sim, max_states_period, num_types, type_spec_shares, type_spec_shifts, ) assert_allclose(py[0], fort[0]) assert_allclose(py[1], fort[1]) assert_allclose(py[2], fort[2]) assert_allclose(py[3], fort[3]) assert_allclose(py[4], fort[4]) assert_allclose(py[0], f2py[0]) assert_allclose(py[1], f2py[1]) assert_allclose(py[2], f2py[2]) assert_allclose(py[3], f2py[3]) assert_allclose(py[4], f2py[4]) ( states_all, mapping_state_idx, periods_rewards_systematic, periods_emax, ) = state_space._get_fortran_counterparts() simulated_data = pyth_simulate( state_space, num_agents_sim, periods_draws_sims, seed_sim, file_sim, edu_spec, optim_paras, is_debug, ) py = simulated_data.copy().fillna(MISSING_FLOAT).values data_array = process_dataset(respy_obj).to_numpy() # Is is very important to cut the data array down to the size of the estimation # sample for the calculation of contributions. data_array = py[:num_agents_est * num_periods, :] f2py = fort_debug.wrapper_simulate( periods_rewards_systematic, mapping_state_idx, periods_emax, states_all, num_periods, num_agents_sim, periods_draws_sims, seed_sim, file_sim, edu_spec["start"], edu_spec["max"], edu_spec["share"], edu_spec["lagged"], optim_paras["coeffs_common"], optim_paras["coeffs_a"], optim_paras["coeffs_b"], shocks_cholesky, delta, num_types, type_spec_shares, type_spec_shifts, is_debug, ) assert_allclose(py, f2py) # We have to cut the simulated data to `num_agents_est` as the Python # implementation calculates the likelihood contributions for all agents in the # data. simulated_data = simulated_data.loc[simulated_data.Identifier.lt( num_agents_est)] py = pyth_contributions(state_space, simulated_data, periods_draws_prob, tau, optim_paras) num_obs_agent = np.bincount(simulated_data.Identifier.to_numpy()) f2py = fort_debug.wrapper_contributions( periods_rewards_systematic, mapping_state_idx, periods_emax, states_all, data_array, periods_draws_prob, tau, num_periods, num_draws_prob, num_agents_est, num_obs_agent, num_types, edu_spec["start"], edu_spec["max"], shocks_cholesky, delta, type_spec_shares, type_spec_shifts, ) assert_allclose(py, f2py) # Evaluation of criterion function x0 = get_optim_paras(optim_paras, num_paras, "all", is_debug) py = pyth_criterion( x0, is_interpolated, num_points_interp, is_debug, simulated_data, tau, periods_draws_emax, periods_draws_prob, state_space, ) f2py = fort_debug.wrapper_criterion( x0, is_interpolated, num_draws_emax, num_periods, num_points_interp, is_myopic, is_debug, data_array, num_draws_prob, tau, periods_draws_emax, periods_draws_prob, states_all, state_space.states_per_period, mapping_state_idx, max_states_period, num_agents_est, num_obs_agent, num_types, edu_spec["start"], edu_spec["max"], edu_spec["share"], type_spec_shares, type_spec_shifts, num_paras, ) assert_allclose(py, f2py)