def test_state_space_restrictions_by_traversing_forward( num_periods, num_types, edu_starts, edu_max): """Test for inadmissible states in the state space. The test is motivated by the addition of another restriction in https://github.com/OpenSourceEconomics/respy/pull/145. To ensure that similar errors do not happen again, this test takes all states in one period and indexes each of the four subsequent states. If a state in the next period got hit return one else 0. Repeating the same procedure for all periods, we get a list of hopefully of zeros and ones for each state which indicates whether the state was indexed or not. """ @njit def traverse_forward(states, indexer, indicator): for i in range(states.shape[0]): # Unpack parent state and get index. period, exp_a, exp_b, edu, choice_lagged, type_ = states[i] # Working in Occupation A in period + 1 k = indexer[period + 1, exp_a + 1, exp_b, edu, 0, type_] indicator[k] = 1 # Working in Occupation B in period +1 k = indexer[period + 1, exp_a, exp_b + 1, edu, 1, type_] indicator[k] = 1 # Schooling in period + 1. Note that adding an additional year of schooling # is only possible for those that have strictly less than the maximum level # of additional education allowed. This condition is necessary as there are # states which have reached maximum education. Incrementing education by one # would target an inadmissible state. if edu >= edu_max: pass else: k = indexer[period + 1, exp_a, exp_b, edu + 1, 2, type_] indicator[k] = 1 # Staying at home in period + 1 k = indexer[period + 1, exp_a, exp_b, edu, 3, type_] indicator[k] = 1 return indicator state_space = StateSpace(num_periods, num_types, edu_starts, edu_max) indicator = np.zeros(state_space.num_states) for period in range(num_periods - 1): states = state_space.get_attribute_from_period("states", period) indicator = traverse_forward(states, state_space.indexer, indicator) # Restrict indicator to states of the second period as the first is never indexed. indicator = indicator[state_space.states_per_period[0]:] assert (indicator == 1).all()
def test_4(self): """ Testing the return values for the total values in case of myopic individuals for one period. Note ---- The original test was designed to use Fortran rewards and calculate the total values and rewards ex post in Python and see whether they match. As both versions diverged in their implementation, we will implement the test with the Python version and check the equality of Fortran and Python outputs at all stages. """ constr = {"edu_spec": {"max": 99}} params_spec, options_spec = generate_random_model(myopic=True, point_constr=constr) # The equality below does not hold if schooling is an inadmissible state. respy_obj = RespyCls(params_spec, options_spec) respy_obj, _ = respy_obj.simulate() ( num_periods, num_types, optim_paras, edu_spec, mapping_state_idx, periods_emax, states_all, periods_rewards_systematic, states_number_period, ) = dist_class_attributes( respy_obj, "num_periods", "num_types", "optim_paras", "edu_spec", "mapping_state_idx", "periods_emax", "states_all", "periods_rewards_systematic", "states_number_period", ) # We have to create the state space and calculate the rewards in the Python # version as we later need the wages which are not part of # ``periods_rewards_systematic``. state_space = StateSpace(num_periods, num_types, edu_spec["start"], edu_spec["max"], optim_paras) # Check that rewards match _, _, pyth, _ = state_space._get_fortran_counterparts() # Set NaNs to -99. mask = np.isnan(periods_rewards_systematic) periods_rewards_systematic[mask] = MISSING_FLOAT assert_almost_equal(pyth, periods_rewards_systematic) period = np.random.choice(num_periods) draws = np.random.normal(size=4) # Internalize periods_emax state_space._create_attributes_from_fortran_counterparts(periods_emax) # Unpack necessary attributes rewards_period = state_space.get_attribute_from_period( "rewards", period) emaxs_period = state_space.get_attribute_from_period("emaxs", period)[:, :4] max_education_period = (state_space.get_attribute_from_period( "states", period)[:, 3] >= edu_spec["max"]) total_values, rewards_ex_post = get_continuation_value_and_ex_post_rewards( rewards_period[:, -2:], rewards_period[:, :4], emaxs_period, draws.reshape(1, -1), optim_paras["delta"], max_education_period, ) np.testing.assert_equal(total_values, rewards_ex_post)
def test_6(self): """ Further tests for the interpolation routines. """ params_spec, options_spec = generate_random_model() respy_obj = RespyCls(params_spec, options_spec) respy_obj = simulate_observed(respy_obj) # Extract class attributes ( periods_rewards_systematic, mapping_state_idx, seed_prob, periods_emax, num_periods, states_all, num_points_interp, edu_spec, num_draws_emax, is_myopic, is_debug, is_interpolated, optim_paras, optimizer_options, file_sim, num_types, ) = dist_class_attributes( respy_obj, "periods_rewards_systematic", "mapping_state_idx", "seed_prob", "periods_emax", "num_periods", "states_all", "num_points_interp", "edu_spec", "num_draws_emax", "is_myopic", "is_debug", "is_interpolated", "optim_paras", "optimizer_options", "file_sim", "num_types", ) shocks_cholesky = optim_paras["shocks_cholesky"] shocks_cov = shocks_cholesky.dot(shocks_cholesky.T) coeffs_common = optim_paras["coeffs_common"] coeffs_a = optim_paras["coeffs_a"] coeffs_b = optim_paras["coeffs_b"] delta = optim_paras["delta"] # Add some additional objects required for the interfaces to the functions. period = np.random.choice(num_periods) periods_draws_emax = create_draws(num_periods, num_draws_emax, seed_prob, is_debug) draws_emax_standard = periods_draws_emax[period, :, :] draws_emax_risk = transform_disturbances(draws_emax_standard, np.zeros(4), shocks_cholesky) # Initialize Python version and solve. state_space = StateSpace(num_periods, num_types, edu_spec["start"], edu_spec["max"], optim_paras) # Integrate periods_emax in state_space state_space.emaxs = np.column_stack(( np.zeros((state_space.num_states, 4)), periods_emax[~np.isnan(periods_emax) & (periods_emax != MISSING_FLOAT)], )) # Fill emaxs_a - emaxs_home in the requested period states_period = state_space.get_attribute_from_period("states", period) # Do not get the emaxs from the previous period if we are in the last one. if period != state_space.num_periods - 1: state_space.emaxs = get_emaxs_of_subsequent_period( states_period, state_space.indexer, state_space.emaxs, edu_spec["max"]) num_states = state_space.states_per_period[period] shifts = np.random.randn(4) # Slight modification of request which assures that the interpolation code is # working. num_points_interp = min(num_points_interp, num_states) # Get the IS_SIMULATED indicator for the subset of points which are used for the # predication model. is_simulated = get_simulated_indicator(num_points_interp, num_states, period, is_debug) # Unpack necessary attributes rewards_period = state_space.get_attribute_from_period( "rewards", period) emaxs_period = state_space.get_attribute_from_period("emaxs", period)[:, :4] max_education = (state_space.get_attribute_from_period( "states", period)[:, 3] >= edu_spec["max"]) # Construct the exogenous variables for all points of the state space. exogenous, max_emax = get_exogenous_variables(rewards_period, emaxs_period, shifts, optim_paras["delta"], max_education) # Align output between Python and Fortran version. py = (exogenous, max_emax) f90 = fort_debug.wrapper_get_exogenous_variables( period, num_periods, num_states, periods_rewards_systematic, shifts, mapping_state_idx, periods_emax, states_all, edu_spec["start"], edu_spec["max"], delta, coeffs_common, coeffs_a, coeffs_b, num_types, ) assert_almost_equal(py[0], f90[0]) assert_almost_equal(py[1], f90[1]) # Construct endogenous variable so that the prediction model can be fitted. endogenous = get_endogenous_variable( rewards_period, emaxs_period, max_emax, is_simulated, draws_emax_risk, optim_paras["delta"], max_education, ) f90 = fort_debug.wrapper_get_endogenous_variable( period, num_periods, num_states, periods_rewards_systematic, mapping_state_idx, periods_emax, states_all, is_simulated, num_draws_emax, max_emax, draws_emax_risk, edu_spec["start"], edu_spec["max"], shocks_cov, delta, coeffs_common, coeffs_a, coeffs_b, ) assert_almost_equal(endogenous, replace_missing_values(f90)) py = get_predictions(endogenous, exogenous, max_emax, is_simulated) f90 = fort_debug.wrapper_get_predictions( endogenous, exogenous, max_emax, is_simulated, num_points_interp, num_states, file_sim, False, ) # This assertion fails if a column is all zeros. if not exogenous.any(axis=0).any(): assert_array_almost_equal(py, f90)