예제 #1
0
def test_regression_simulation(inputs):
    init_dict = random_init(inputs)
    df, unobs, utilities, num_states = simulate(init_dict["simulation"])
    num_buses = init_dict["simulation"]["buses"]
    num_periods = init_dict["simulation"]["periods"]
    beta = init_dict["simulation"]["beta"]
    params = np.array(init_dict["simulation"]["params"])
    probs = np.array(init_dict["simulation"]["known probs"])
    v_disc_ = [0.0, 0.0]
    v_disc = discount_utility(
        v_disc_, num_buses, num_periods, num_periods, utilities, beta
    )
    trans_mat = create_transition_matrix(num_states, probs)
    costs = myopic_costs(num_states, lin_cost, params)
    v_calc = calc_fixp(num_states, trans_mat, costs, beta)
    un_ob_av = 0
    for bus in range(num_buses):
        un_ob_av += unobs[bus, 0, 0]
    un_ob_av = un_ob_av / num_buses
    assert_allclose(v_disc[1] / (v_calc[0] + un_ob_av), 1, rtol=1e-02)
예제 #2
0
def get_worst_trans(init_dict, roh, num_states, max_it=1000, min_state=0):
    beta = init_dict["beta"]
    x_0 = np.array(init_dict["known probs"])
    dim = x_0.shape[0]
    params = np.array(init_dict["params"])
    costs = myopic_costs(num_states, lin_cost, params)
    eq_constr = {"type": "eq", "fun": lambda x: 1 - np.sum(x)}
    ineq_constr = {
        "type": "ineq",
        "fun": lambda x: roh - np.sum(np.multiply(x, np.log(np.divide(x, x_0)))),
    }
    res = opt.minimize(
        select_fixp,
        args=(min_state, num_states, costs, beta, max_it),
        x0=x_0,
        bounds=[(1e-6, 1)] * dim,
        method="SLSQP",
        constraints=[eq_constr, ineq_constr],
    )
    worst_trans = np.array(res["x"])
    return worst_trans
예제 #3
0
def plot_convergence(init_dict):
    beta = init_dict["simulation"]["beta"]

    df, unobs, utilities, num_states = simulate(init_dict["simulation"])

    costs = myopic_costs(num_states, lin_cost,
                         init_dict["simulation"]["params"])
    trans_probs = np.array(init_dict["simulation"]["known probs"])
    trans_mat = create_transition_matrix(num_states, trans_probs)
    ev = calc_fixp(num_states, trans_mat, costs, beta)
    num_buses = init_dict["simulation"]["buses"]
    num_periods = init_dict["simulation"]["periods"]
    gridsize = init_dict["plot"]["gridsize"]
    num_points = int(num_periods / gridsize)

    v_exp = np.full(num_points, calc_ev_0(ev, unobs, num_buses))

    v_start = np.zeros(num_points)
    v_disc = discount_utility(v_start, num_buses, gridsize, num_periods,
                              utilities, beta)

    periods = np.arange(0, num_periods, gridsize)

    ax = plt.figure(figsize=(14, 6))

    ax1 = ax.add_subplot(111)

    ax1.set_ylim([0, 1.3 * v_disc[-1]])

    ax1.set_ylabel(r"Value at time 0")
    ax1.set_xlabel(r"Periods")

    ax1.plot(periods, v_disc, color="blue")
    ax1.plot(periods, v_exp, color="orange")

    plt.tight_layout()
    os.makedirs("figures", exist_ok=True)
    plt.savefig("figures/figure_1.png", dpi=300)
예제 #4
0
def test_myopic_costs(inputs, outputs):
    assert_array_almost_equal(
        myopic_costs(inputs["nstates"], inputs["cost_fct"], inputs["params"]),
        outputs["myop_costs"],
    )
예제 #5
0
beta = init_dict["simulation"]["beta"]
init_dict["simulation"]["states"] = 90

v_exp_known = []
v_exp_real = []
v_disc = []
roh_plot = []
for roh in np.arange(0, 4, 0.1):
    roh_plot += [roh]
    init_dict["simulation"]["roh"] = roh
    worst_trans = get_worst_trans(init_dict["simulation"])
    init_dict["simulation"]["real probs"] = worst_trans

    df, unobs, utilities, num_states = simulate(init_dict["simulation"])

    costs = myopic_costs(num_states, lin_cost, init_dict["simulation"]["params"])

    num_buses = init_dict["simulation"]["buses"]
    num_periods = init_dict["simulation"]["periods"]
    gridsize = init_dict["plot"]["gridsize"]

    real_trans_probs = np.array(init_dict["simulation"]["real probs"])
    real_trans_mat = create_transition_matrix(num_states, real_trans_probs)
    ev_real = calc_fixp(num_states, real_trans_mat, costs, beta)

    known_trans_probs = np.array(init_dict["simulation"]["known probs"])
    known_trans_mat = create_transition_matrix(num_states, known_trans_probs)
    ev_known = calc_fixp(num_states, known_trans_mat, costs, beta)

    v_calc = 0
    for i in range(num_buses):
예제 #6
0
def simulate_strategy(known_trans, increments, num_buses, num_periods, params,
                      beta, unobs, maint_func):
    """
    This function manages the simulation process. It initializes the auxiliary
    variables and calls therefore the subfuctions from estimation auxiliary. It then
    calls the decision loop, written for numba. As the state size of the fixed point
    needs to be a lot larger than the actual state, the size is doubled, if the loop
    hasn't run yet through all the periods.

    :param known_trans: A numpy array containing the transition probabilities the agent
                        assumes.
    :param increments:  A two dimensional numpy array containing for each bus in each
                        period a random drawn state increase as integer.
    :param num_buses:   The number of buses to be simulated.
    :type num_buses:    int
    :param num_periods: The number of periods to be simulated.
    :type num_periods:  int
    :param params:      A numpy array containing the parameters shaping the cost
                        function.
    :param beta:        The discount factor.
    :type beta:         float
    :param unobs:       A three dimensional numpy array containing for each bus,
                        for each period for the decision to maintain or replace the
                        bus engine a random drawn utility as float.
    :param maint_func:  The maintenance cost function. Only linear implemented so
                        far.

    :return: The function returns the following objects:

        :states:           : A two dimensional numpy array containing for each bus in
                             each period the state as an integer.
        :decisions:        : A two dimensional numpy array containing for each bus in
                             each period the decision as an integer.
        :utilities:        : A two dimensional numpy array containing for each bus in
                             each period the utility as a float.
        :num_states: (int) : The size of the state space.
    """
    num_states = int(200)
    start_period = int(0)
    states = np.zeros((num_buses, num_periods), dtype=int)
    decisions = np.zeros((num_buses, num_periods), dtype=int)
    utilities = np.zeros((num_buses, num_periods), dtype=float)
    while start_period < num_periods - 1:
        num_states = 2 * num_states
        known_trans_mat = create_transition_matrix(num_states, known_trans)
        costs = myopic_costs(num_states, maint_func, params)
        ev = calc_fixp(num_states, known_trans_mat, costs, beta)
        states, decisions, utilities, start_period = simulate_strategy_loop(
            num_buses,
            states,
            decisions,
            utilities,
            costs,
            ev,
            increments,
            num_states,
            start_period,
            num_periods,
            beta,
            unobs,
        )
    return states, decisions, utilities, num_states
예제 #7
0
def simulate(init_dict):
    """
    The main function to simulate a decision process in the theoretical framework of
    John Rust's 1987 paper. It reads the inputs from the initiation dictionary and
    draws the random variables. It then calls the main subfunction with all the
    relevant parameters. So far, the feature of a agent's misbelief on the underlying
    transition probabilities is not implemented.

    :param init_dict: A dictionary containing the following variables as keys:

        :seed: (Digits)      : The seed determines random draws.
        :buses: (int)        : Number of buses to be simulated.
        :beta: (float)       : Discount factor.
        :periods: (int)      : Number of periods to be simulated.
        :probs:              : A list or array of the true underlying transition
                               probabilities.
        :params:             : A list or array of the cost parameters shaping the cost
                               function.
        :maint_func: (string): The type of cost function, as string. Only linear
                               implemented so far.

    :return: The function returns the following objects:

        :df:         : A pandas dataframe containing for each observation the period,
                       state, decision and a Bus ID.
        :unobs:      : A three dimensional numpy array containing for each bus,
                       for each period random drawn utility for the decision to
                       maintain or replace the bus engine.
        :utilities:  : A two dimensional numpy array containing for each bus in each
                       period the utility as a float.
        :num_states: : A integer documenting the size of the state space.
    """
    np.random.seed(init_dict["seed"])
    num_buses = init_dict["buses"]
    beta = init_dict["beta"]
    num_periods = init_dict["periods"]
    if "real probs" in init_dict.keys():
        real_trans = np.array(init_dict["real probs"])
    else:
        real_trans = np.array(init_dict["known probs"])
    known_trans = np.array(init_dict["known probs"])
    params = np.array(init_dict["params"])
    if init_dict["maint_func"] == "linear":
        maint_func = lin_cost
    else:
        maint_func = lin_cost
    unobs = np.random.gumbel(loc=-mp.euler, size=[num_buses, num_periods, 2])
    increments = np.random.choice(len(real_trans),
                                  size=(num_buses, num_periods),
                                  p=real_trans)
    if "ev_known" in init_dict.keys():
        # If there is already ev given, the auxiliary function is skipped and the
        # simulation is executed with no further increases of the state space. This
        # option is perfect if only one parameter in the setting is varied and
        # therefore the highest achievable state can be guessed.
        ev_known = np.array(init_dict["ev_known"])
        num_states = int(len(ev_known))
        costs = myopic_costs(num_states, lin_cost, params)
        states = np.zeros((num_buses, num_periods), dtype=int)
        decisions = np.zeros((num_buses, num_periods), dtype=int)
        utilities = np.zeros((num_buses, num_periods), dtype=float)
        states, decisions, utilities = simulate_strategy_loop_known(
            num_buses,
            states,
            decisions,
            utilities,
            costs,
            ev_known,
            increments,
            num_periods,
            beta,
            unobs,
        )
    else:
        states, decisions, utilities, num_states = simulate_strategy(
            known_trans,
            increments,
            num_buses,
            num_periods,
            params,
            beta,
            unobs,
            maint_func,
        )

    df = pd.DataFrame({
        "state": states.flatten(),
        "decision": decisions.flatten()
    })
    df["period"] = np.arange(num_periods).repeat(num_buses).astype(int)
    bus_id = np.array([])
    for i in range(1, num_buses + 1):
        bus_id = np.append(bus_id, np.full(num_periods, i, dtype=int))
    df["Bus_ID"] = bus_id
    return df, unobs, utilities, num_states