Пример #1
0
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()
Пример #2
0
    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)
Пример #3
0
    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)