HT_extensive.solve(outputFlag=0, TimeLimit=time_limit)
    print('lower bound', HT_extensive.objBound)
    print('upper bound', HT_extensive.objVal)
    print('total time', HT_extensive.total_time)
    print('gap', HT_extensive.MIPGap)
if solver == 'SDDiP':
    HydroThermal.binarize(bin_stage=T)
    HT_sddp = SDDiP(HydroThermal)
    HT_sddp.solve(
        logFile=0,
        logToConsole=0,
        cuts=[cut],
        n_processes=1,
        n_steps=1,
        max_iterations=n_iterations,
    )
    result = Evaluation(HydroThermal)
    if T in [2, 3]:
        result.run(random_state=666, n_simulations=-1)
    else:
        result.run(random_state=666, n_simulations=3000)
    resultTrue = EvaluationTrue(HydroThermal)
    resultTrue.run(random_state=666, n_simulations=3000)
    print('lower bound', result.db)
    if T in [2, 3]:
        print('upper bound', result.epv)
    else:
        print('CI appr.', result.CI)
    print('gap', result.gap)
    print('CI true', resultTrue.CI)
Beispiel #2
0
                                    sharex=True)
     fig_mca.text(0.5, 0.01, 'stage', ha='center')
     fig_mca.text(0, 0.5, 'demand', va='center', rotation='vertical')
     for j_idx, j in enumerate(J):
         fig_mca = fan_plot(true[:, :, j_idx], ax=ax_mca[j_idx][0])
         fig_mca = fan_plot(simulation[:, :, j_idx], ax=ax_mca[j_idx][1])
     fig_mca.tight_layout()
     fig_mca.savefig("./result/airline_MCA.png", dpi=1200)
     fig_bound, ax_bound = plt.subplots(2, 1, figsize=(10, 5), sharey=True)
 for cut_index, cut in enumerate(['B', 'SB']):
     airline_sddp = SDDiP(airline)
     airline_sddp.solve(cuts=[cut],
                        n_processes=1,
                        n_steps=1,
                        max_iterations=100)
     result = Evaluation(airline)
     result.run(random_state=666, n_simulations=3000)
     resultTrue = EvaluationTrue(airline)
     resultTrue.run(random_state=666, n_simulations=3000)
     summary['model'].append(idx)
     summary['cut'].append(cut)
     summary['time'].append(airline_sddp.total_time)
     summary['gap'].append(result.gap)
     summary['bound'].append(result.db)
     summary['CI_approx_lower'].append(result.CI[0])
     summary['CI_approx_upper'].append(result.CI[1])
     summary['CI_true_lower'].append(resultTrue.CI[0])
     summary['CI_true_upper'].append(resultTrue.CI[1])
     if idx == 2:
         fig_bound = airline_sddp.plot_bounds(window=1,
                                              smooth=1,
AssetMgt.add_Markovian_uncertainty(g)
for t in range(T):
    m = AssetMgt[t]
    now, past = m.addStateVars(2, lb=0, obj=0)
    if t == 0:
        m.addConstr(now[0] + now[1] == 55)
    if t in [1, 2]:
        m.addConstr(past[0] + past[1] == now[0] + now[1],
                    uncertainty_dependent={
                        past[0]: 0,
                        past[1]: 1
                    })
    if t == 3:
        y = m.addVar(obj=1)
        w = m.addVar(obj=-4)
        m.addConstr(past[0] + past[1] - y + w == 80,
                    uncertainty_dependent={
                        past[0]: 0,
                        past[1]: 1
                    })
AssetMgt.discretize(
    n_Markov_states=25,
    n_sample_paths=10000,
)
# Extensive(AssetMgt).solve()
SDDP(AssetMgt).solve(max_iterations=400)
result = Evaluation(AssetMgt)
result.run(n_simulations=1000)
resultTrue = EvaluationTrue(AssetMgt)
resultTrue.run(n_simulations=1000)
Beispiel #4
0
    def evaluate_policy(self, n_simulations):

        evaluate = [False]
        # When evaluating the obtained policy from TS approach we sometimes get computational issues
        if self.markov:
            evaluate.append(True)

        for true_distribution in evaluate:  #[True,False]
            if true_distribution:
                result = EvaluationTrue(self.model_ip)
                string = '_true'
            else:
                result = Evaluation(self.model_ip)
                string = ''
            result.run(n_simulations=n_simulations,
                       query_stage_cost=True,
                       query=self.data.dat['query'])

            #I could add this to the dataframe
            self.data.evaluation['db_eval' + string] = result.db
            self.data.evaluation['CI_eval' + string] = result.CI
            self.data.evaluation['gap_eval' + string] = result.gap
            self.data.evaluation['pv2_eval' + string] = result.pv
            self.data.evaluation['epv_eval' + string] = result.epv

            decision_matrix = pd.DataFrame(index=list(range(n_simulations)),
                                           columns=self.data.dat['T_STAGES'])
            decision_matrix = decision_matrix.fillna('-')
            for i in range(n_simulations):
                for (t, a) in self.data.dat['x_act_combinations']:
                    if result.solution["x_act[{},{}]".format(t, a)].at[i,
                                                                       t] == 1:
                        decision_matrix.at[i, t] = a
                operating = True
                for t in self.data.dat['T_STAGES']:
                    if result.solution['y_sd'].at[i, t] == 1 and operating:
                        decision_matrix.at[i, t] = 'y_sd'
                        operating = False

            self.data.evaluation['decision_matrix' + string] = decision_matrix
            self.data.evaluation['prices' + string] = result.solution['price']
            if self.two_factor:
                self.data.evaluation['eq_fact' +
                                     string] = result.solution['eq_fact']
                self.data.evaluation['dev_fact' +
                                     string] = result.solution['dev_fact']

            #######################
            ### DECISION MATRIX ###
            #######################
        if self.print_decision_matrix:

            if self.markov:
                decision_matrix = self.data.evaluation['decision_matrix_true']
                prices = self.data.evaluation['prices_true']
            else:
                decision_matrix = self.data.evaluation['decision_matrix']
                prices = self.data.evaluation['prices']

            summary_decision_matrix = decision_matrix.groupby(
                decision_matrix.columns.tolist(), as_index=False).size()

            unique_solutions = decision_matrix.drop_duplicates()
            unique_solutions = unique_solutions.reset_index(drop=True)
            rows_to_instances = {i: []
                                 for i in range(len(unique_solutions))
                                 }  #rows are the unique solutions
            for index, row in decision_matrix.iterrows():
                for index2, row2 in unique_solutions.iterrows():
                    if list(row) == list(row2):
                        rows_to_instances[index2].append(index)
            unique_solutions['count'] = 0

            rows_dec_mat = list(summary_decision_matrix.index)
            for i in range(len(rows_dec_mat)):
                for j in range(len(unique_solutions)):
                    if list(summary_decision_matrix.iloc[i, 0:6]) == list(
                            unique_solutions.iloc[j, 0:6]):
                        unique_solutions['count'][j] = summary_decision_matrix[
                            'size'][i]

            ordering = {
                'new_wells8': 0,
                'new_wells4': 1,
                'sidetrack2': 2,
                'sidetrack1': 3,
                '-': 4,
                'y_sd': 5
            }
            unique_solutions['order'] = 0
            for i in [5, 4, 3, 2, 1, 0]:
                unique_solutions['order'] = [
                    ordering[j] for j in unique_solutions[i]
                ]
                unique_solutions = unique_solutions.sort_values(by='order',
                                                                ascending=True)

            order = list(unique_solutions.index)

            def manual_sorting(col):
                output = []
                for i in col:
                    for j in range(len(order)):
                        if i == order[j]:
                            output.append(j)
                return output

            vars = ['prices']
            statistics = [
                i + '_' + j for i in vars for j in ['mean', 'min', 'max']
            ]
            stat_df = {
                s: pd.DataFrame(index=range(len(unique_solutions)))
                for s in statistics
            }

            num_stages = len(decision_matrix.columns)
            for t in range(num_stages):  # initialize
                for stat in statistics:
                    stat_df[stat][str(t)] = 0.0

            for i in range(len(unique_solutions)):
                subset = prices.iloc[rows_to_instances[i], :]
                for t in range(num_stages):
                    var = 'prices'
                    stat_df[var + '_min'][str(t)][i] = subset.iloc[:, t].min()
                    stat_df[var + '_max'][str(t)][i] = subset.iloc[:, t].max()
                    stat_df[var + '_mean'][str(t)][i] = subset.iloc[:,
                                                                    t].mean()

            for stat in statistics:
                print(stat)
                stat_df[stat]['row_number'] = list(stat_df[stat].index)
                print((stat_df[stat].sort_values(by='row_number',
                                                 key=manual_sorting)))
Beispiel #5
0
    def solve(self,
              n_processes=1,
              n_steps=1,
              max_iterations=10000,
              max_stable_iterations=10000,
              max_time=1000000.0,
              tol=0.001,
              freq_evaluations=None,
              percentile=95,
              tol_diff=float("-inf"),
              random_state=None,
              freq_evaluations_true=None,
              freq_comparisons=None,
              n_simulations=3000,
              n_simulations_true=3000,
              freq_clean=None,
              logFile=1,
              logToConsole=1):
        """Solve approximation model.

        Parameters
        ----------

        n_processes: int, optional (default=1)
            The number of processes to run in parallel. Run serial SDDP if 1.
            If n_steps is 1, n_processes is coerced to be 1.

        n_steps: int, optional (default=1)
            The number of forward/backward steps to run in each cut iteration.
            It is coerced to be 1 if n_processes is 1.

        max_iterations: int, optional (default=10000)
            The maximum number of iterations to run SDDP.

        max_stable_iterations: int, optional (default=10000)
            The maximum number of iterations to have same deterministic bound

        tol: float, optional (default=1e-3)
            tolerance for convergence of bounds

        freq_evaluations: int, optional (default=None)
            The frequency of evaluating gap on approximation model. It will be
            ignored if risk averse

        percentile: float, optional (default=95)
            The percentile used to compute confidence interval

        diff: float, optional (default=-inf)
            The stablization threshold

        freq_comparisons: int, optional (default=None)
            The frequency of comparisons of policies

        n_simulations: int, optional (default=10000)
            The number of simluations to run when evaluating a policy
            on approximation model

        freq_clean: int/list, optional (default=None)
            The frequency of removing redundant cuts.
            If int, perform cleaning at the same frequency for all stages.
            If list, perform cleaning at different frequency for each stage;
            must be of length T-1 (the last stage does not have any cuts).

        random_state: int, RandomState instance or None, optional (default=None)
            Used in evaluations and comparisons. (In the forward step, there is
            an internal random_state which is not supposed to be changed.)
            If int, random_state is the seed used by the random number
            generator;
            If RandomState instance, random_state is the random number
            generator;
            If None, the random number generator is the RandomState
            instance used by numpy.random.

        logFile: binary, optional (default=1)
            Switch of logging to log file

        logToConsole: binary, optional (default=1)
            Switch of logging to console
        """
        MSP = self.MSP
        if freq_clean is not None:
            if isinstance(freq_clean, (numbers.Integral, numpy.integer)):
                freq_clean = [freq_clean] * (MSP.T - 1)
            if isinstance(freq_clean, ((abc.Sequence, numpy.ndarray))):
                if len(freq_clean) != MSP.T - 1:
                    raise ValueError("freq_clean list must be of length T-1!")
            else:
                raise TypeError(
                    "freq_clean must be int/list instead of {}!".format(
                        type(freq_clean)))
        if not MSP._flag_update:
            MSP._update()
        stable_iterations = 0
        total_time = 0
        a = time.time()
        gap = 1.0
        right_end_of_CI = float("inf")
        db_past = MSP.bound
        self.percentile = percentile
        if MSP.measure != "risk neutral":
            freq_evaluations = None
        # distinguish pv_sim from pv
        pv_sim_past = None

        if n_processes != 1:
            self.n_steps = n_steps
            self.n_processes = min(n_steps, n_processes)
            self.jobs = allocate_jobs(self.n_steps, self.n_processes)

        logger_sddp = LoggerSDDP(
            logFile=logFile,
            logToConsole=logToConsole,
            n_processes=self.n_processes,
            percentile=self.percentile,
        )
        logger_sddp.header()
        if freq_evaluations is not None or freq_comparisons is not None:
            logger_evaluation = LoggerEvaluation(
                n_simulations=n_simulations,
                percentile=percentile,
                logFile=logFile,
                logToConsole=logToConsole,
            )
            logger_evaluation.header()
        if freq_comparisons is not None:
            logger_comparison = LoggerComparison(
                n_simulations=n_simulations,
                percentile=percentile,
                logFile=logFile,
                logToConsole=logToConsole,
            )
            logger_comparison.header()
        try:
            while (self.iteration < max_iterations and total_time < max_time
                   and stable_iterations < max_stable_iterations and tol < gap
                   and tol_diff < right_end_of_CI):
                start = time.time()

                self._compute_cut_type()

                if self.n_processes == 1:
                    pv = self._SDDP_single()
                else:
                    pv = self._SDDP_multiprocessesing()

                m = (MSP.models[0]
                     if MSP.n_Markov_states == 1 else MSP.models[0][0])
                m.optimize()
                if m.status not in [2, 11]:
                    m.write_infeasible_model("backward_" +
                                             str(m._model.modelName) + ".lp")
                db = m.objBound
                self.db.append(db)
                MSP.db = db
                if self.n_processes != 1:
                    CI = compute_CI(pv, percentile)
                self.pv.append(pv)

                if self.iteration >= 1:
                    if db_past == db:
                        stable_iterations += 1
                    else:
                        stable_iterations = 0
                self.iteration += 1
                db_past = db

                end = time.time()
                elapsed_time = end - start
                total_time += elapsed_time

                if self.n_processes == 1:
                    logger_sddp.text(
                        iteration=self.iteration,
                        db=db,
                        pv=pv[0],
                        time=elapsed_time,
                    )
                else:
                    logger_sddp.text(
                        iteration=self.iteration,
                        db=db,
                        CI=CI,
                        time=elapsed_time,
                    )
                if (freq_evaluations is not None
                        and self.iteration % freq_evaluations == 0
                        or freq_comparisons is not None
                        and self.iteration % freq_comparisons == 0):
                    start = time.time()
                    evaluation = Evaluation(MSP)
                    evaluation.run(
                        n_simulations=n_simulations,
                        random_state=random_state,
                        query_stage_cost=False,
                        percentile=percentile,
                    )
                    pandas.DataFrame({
                        'pv': evaluation.pv
                    }).to_csv("evaluation.csv")
                    elapsed_time = time.time() - start
                    gap = evaluation.gap
                    if n_simulations == -1:
                        logger_evaluation.text(
                            iteration=self.iteration,
                            db=db,
                            pv=evaluation.epv,
                            gap=gap,
                            time=elapsed_time,
                        )
                    elif n_simulations == 1:
                        logger_evaluation.text(
                            iteration=self.iteration,
                            db=db,
                            pv=evaluation.pv,
                            gap=gap,
                            time=elapsed_time,
                        )
                    else:
                        logger_evaluation.text(
                            iteration=self.iteration,
                            db=db,
                            CI=evaluation.CI,
                            gap=gap,
                            time=elapsed_time,
                        )
                if (freq_comparisons is not None
                        and self.iteration % freq_comparisons == 0):
                    start = time.time()
                    pv_sim = evaluation.pv
                    if self.iteration / freq_comparisons >= 2:
                        diff = MSP.sense * (numpy.array(pv_sim_past) -
                                            numpy.array(pv_sim))
                        if n_simulations == -1:
                            diff_mean = numpy.mean(diff)
                            right_end_of_CI = diff_mean
                        else:
                            diff_CI = compute_CI(diff, self.percentile)
                            right_end_of_CI = diff_CI[1]
                        elapsed_time = time.time() - start
                        if n_simulations == -1:
                            logger_comparison.text(
                                iteration=self.iteration,
                                ref_iteration=self.iteration -
                                freq_comparisons,
                                diff=diff_mean,
                                time=elapsed_time,
                            )
                        else:
                            logger_comparison.text(
                                iteration=self.iteration,
                                ref_iteration=self.iteration -
                                freq_comparisons,
                                diff_CI=diff_CI,
                                time=elapsed_time,
                            )
                    pv_sim_past = pv_sim
                if freq_clean is not None:
                    clean_stages = [
                        t for t in range(1, MSP.T - 1)
                        if self.iteration % freq_clean[t] == 0
                    ]
                    if len(clean_stages) != 0:
                        self._remove_redundant_cut(clean_stages)
                # self._clean()
        except KeyboardInterrupt:
            stop_reason = "interruption by the user"
        # SDDP iteration stops
        MSP.db = self.db[-1]
        if self.iteration >= max_iterations:
            stop_reason = "iteration:{} has reached".format(max_iterations)
        if total_time >= max_time:
            stop_reason = "time:{} has reached".format(max_time)
        if stable_iterations >= max_stable_iterations:
            stop_reason = "stable iteration:{} has reached".format(
                max_stable_iterations)
        if gap <= tol:
            stop_reason = "convergence tolerance:{} has reached".format(tol)
        if right_end_of_CI <= tol_diff:
            stop_reason = "stablization threshold:{} has reached".format(
                tol_diff)

        b = time.time()
        logger_sddp.footer(reason=stop_reason)
        if freq_evaluations is not None or freq_comparisons is not None:
            logger_evaluation.footer()
        if freq_comparisons is not None:
            logger_comparison.footer()
        self.total_time = total_time
Beispiel #6
0
         )
         for j in range(N):
             m.addConstr(past[j] == capm[j], uncertainty_dependent={past[j]:j})
             m.addConstr(past[j] == idio[j], uncertainty={past[j]:f(alpha[j],sigma[j])})
         m.addConstr(now[N] == (1+rf) * past[N])
 AssetMgt.discretize(
     n_samples=100,
     method='input',
     Markov_states=Markov_states,
     transition_matrix=transition_matrix,
     random_state=888,
 )
 AssetMgt.set_AVaR(lambda_=lambda_, alpha_=0.25)
 AssetMgt_SDDP = SDDP(AssetMgt)
 AssetMgt_SDDP.solve(max_iterations=50, n_steps=3, n_processes=3)
 evaluation = Evaluation(AssetMgt)
 evaluation.run(n_simulations=1000, random_state=666)
 evaluationTrue = EvaluationTrue(AssetMgt)
 evaluationTrue.run(n_simulations=1000, random_state=666)
 result = {
     'mean':numpy.mean(evaluation.pv)-100,
     'std':numpy.std(evaluation.pv),
     'VAR': numpy.quantile(evaluation.pv,0.05)-100,
     'skewness': stats.skew(evaluation.pv),
     'kurtosis': 3+stats.kurtosis(evaluation.pv),
     'Sharpe Ratio':
         (numpy.mean(evaluation.pv)-100-0.005513771)/numpy.std(evaluation.pv)
 }
 evaluation_tab.append(pandas.Series(result))
 resultTrue = {
     'mean':numpy.mean(evaluationTrue.pv)-100,