コード例 #1
0
ファイル: tsdro_decomposition.py プロジェクト: mtonbari/tsdro
    def solve_inner_dro(self, stage2_objvals):
        """
        Solve inner maximization over Wasserstein ball given first stage
        decisions.
        """
        dro_inner_model = Model()
        dro_inner_model.params.Method = 0  # method set to primal simplex
        q = dro_inner_model.addVars(stage2_objvals.keys(),
                                    self.samples.keys(),
                                    lb=0)
        lhs = LinExpr()
        for sample_name, sample in self.samples.items():
            curr_tot_prob = quicksum(q[s, sample_name]
                                     for s in stage2_objvals.keys())
            dro_inner_model.addLConstr(curr_tot_prob == 1)
            for scenario_name in stage2_objvals.keys():
                scenario = self.scenarios[scenario_name]
                sampleDev = sc.get_scenario_distance(scenario, sample,
                                                     self.lr_instance)
                lhs.addTerms(sampleDev * self.probs[sample_name],
                             q[scenario_name, sample_name])
        dro_inner_model.addLConstr(lhs, "<", self.wass_rad)

        objExpr = quicksum(q[scenario_name, sample_name] *
                           stage2_objvals[scenario_name]
                           for scenario_name in stage2_objvals.keys()
                           for sample_name in self.samples.keys())
        dro_inner_model.setObjective(objExpr, GRB.MAXIMIZE)
        dro_inner_model.setParam("OutputFlag", 0)
        return dro_inner_model, q
コード例 #2
0
    def construct_master(self, master_scenarios):
        """
        Construct master model.

        Included in the model are first stage decisions and constraints, and
        second stage decisions and constraints for each scenario in
        master_scenarios

        Parameters
        ----------
        master_scenarios : list of str
            List of scenario names to be initially included in the master
            model. 
        """
        lr_instance = self.tsdro.lr_instance

        self.master, self.stage1_vars = lr_instance.construct_stage1()
        if self.method == "RO":
            self.wass_mult = 0
        else:
            self.wass_mult = self.master.addVar(name="wass_multiplier", lb=0)
        self.epi_vars = self.master.addVars(self.tsdro.samples.keys(),
                                            lb=0,
                                            name="epi_vars")
        objexpr_stage1 = lr_instance.get_objective_stage1(self.stage1_vars)
        objexpr_stage2 = quicksum(self.tsdro.probs[sample_name] *
                                  self.epi_vars[sample_name]
                                  for sample_name in self.tsdro.samples.keys())

        self.objexpr_master = (objexpr_stage1 +
                               self.tsdro.wass_rad * self.wass_mult +
                               objexpr_stage2)
        self.master.setObjective(self.objexpr_master, GRB.MINIMIZE)

        for scenario_name in master_scenarios:
            scenario = self.tsdro.scenarios[scenario_name]
            curr_vars, _ = lr_instance.add_stage2(self.master,
                                                  self.stage1_vars, scenario,
                                                  scenario_name)
            for sample_name, sample in self.tsdro.samples.items():
                objexpr_stage2 = lr_instance.get_objective_stage2(
                    curr_vars, scenario)
                if scenario_name == sample_name or self.method == "RO":
                    scenario_distance = 0
                else:
                    scenario_distance = sc.get_scenario_distance(
                        scenario, sample, lr_instance)
                rhs = objexpr_stage2 - self.wass_mult * scenario_distance
                self.master.addLConstr(
                    self.epi_vars[sample_name],
                    ">",
                    rhs,
                    name=("epi_constr_" + str(scenario_name) + "_" +
                          str(sample_name)))
            self.stage2_vars[scenario_name] = curr_vars
        return
コード例 #3
0
ファイル: kadaptability.py プロジェクト: mtonbari/tsdro
 def getDisjunctionLHS(self, kAdaptVars, scenarioName, sampleName):
     scenario = self.tsdro.scenarios[scenarioName]
     sample = self.tsdro.samples[sampleName]
     beta = kAdaptVars.beta
     wassMult = kAdaptVars.wassMult
     scenario_distance = sc.get_scenario_distance(sample, scenario,
                                                  self.tsdro.lrInstance)
     lhs = LinExpr()
     lhs.addTerms(scenario_distance * self.tsdro.probs[sampleName], wassMult)
     lhs.addTerms(1, beta[sampleName])
     return lhs
コード例 #4
0
ファイル: kadaptability.py プロジェクト: mtonbari/tsdro
    def addConvexSubproblem(self, model, v):
        lrInstance = self.tsdro.lrInstance
        samples = self.tsdro.samples
        scenarios = self.tsdro.scenarios
        initialScenarioNames = self.tsdro.initialScenarioNames

        wassMult = model.addVar(lb=0, name="wass_multiplier")
        beta = model.addVars(samples.keys(), lb=-np.inf, ub=np.inf, name="beta")
        for scenarioName in initialScenarioNames:
            scenario = scenarios[scenarioName]
            for sampleName, sample in samples.items():
                scenario_distance = sc.get_scenario_distance(sample, scenario, lrInstance)
                lhs = LinExpr()
                lhs.addTerms(scenario_distance * self.tsdro.probs[sampleName], wassMult)
                lhs.addTerms(1, beta[sampleName])
                rhs = self.tsdro.probs[sampleName] * v[scenarios]
                constr_name = ("dro_"
                               + "sc" + str(scenarioName)
                               + "_sa" + str(sampleName)
                               + "_k" + str(k))
                model.addLConstr(lhs, ">", rhs, name= constr_name)
        return model, KAdaptVars(wassMult, beta, None, None)
コード例 #5
0
    def enumeration_separation(self,
                               stage1_vars,
                               sample_name,
                               limit=1,
                               enumerate_all=True):
        """
        Enumerate remaining scenarios and update master if violated constraint if found.

        Parameters
        ----------
        stage1_vars : location_routing.Stage1Vars dataclass
        sample_name : str
        limit : int
            Maximum number of scenarios that can be added to the master
        enumerate_all : bool
            If True, enumerate all scenarios and only add the scenario
            with the greatest violation.
        """
        sample = self.tsdro.samples[sample_name]
        scenarios = self.tsdro.scenarios
        lr_instance = self.tsdro.lr_instance
        curr_remaining = self.tsdro.remaining_scenario_names[sample_name]
        curr_remaining_copy = curr_remaining.copy()

        found_hyp = False
        count = 0
        max_violation_scenario_name = None
        max_violation = -np.inf
        for scenario_name in curr_remaining:
            scenario = scenarios[scenario_name]
            if scenario_name not in self.stage2_objvals:
                self.stage2_objvals[scenario_name] = self.get_stage2_costs(
                    stage1_vars, [scenario_name])

            if scenario_name == sample_name or self.method == "RO":
                scenario_distance = 0
                rhs_val = self.stage2_objvals[scenario_name]
            else:
                scenario_distance = sc.get_scenario_distance(
                    scenario, sample, lr_instance)
                rhs_val = (self.stage2_objvals[scenario_name] -
                           self.wass_mult.X * scenario_distance)
            if self.epi_vars[sample_name].X < rhs_val + 1e-7:
                found_hyp = True
                if not enumerate_all:
                    count += 1
                    if scenario_name not in self.master_scenarios:
                        tmp = lr_instance.add_stage2(self.master,
                                                     self.stage1_vars,
                                                     scenario, scenario_name)
                        self.stage2_vars[scenario_name] = tmp[0]
                        self.master_scenarios.append(scenario_name)
                    objexpr_stage2 = lr_instance.get_objective_stage2(
                        self.stage2_vars[scenario_name], scenario)
                    rhs = objexpr_stage2 - self.wass_mult * scenario_distance
                    self.master.addLConstr(self.epi_vars[sample_name], ">",
                                           rhs)
                    curr_remaining_copy.remove(scenario_name)
                else:
                    if rhs_val - self.epi_vars[sample_name].X > max_violation:
                        max_violation = rhs_val - self.epi_vars[sample_name].X
                        max_violation_scenario_name = scenario_name
            if count == limit:
                break
        if enumerate_all and found_hyp:
            scenario = scenarios[max_violation_scenario_name]
            if scenario_name == sample_name or self.method == "RO":
                scenario_distance = 0
            else:
                scenario_distance = sc.get_scenario_distance(
                    scenario, sample, lr_instance)
            if scenario_name not in self.master_scenarios:
                tmp = lr_instance.add_stage2(self.master, self.stage1_vars,
                                             scenario,
                                             max_violation_scenario_name)
                self.stage2_vars[max_violation_scenario_name] = tmp[0]
                self.master_scenarios.append(max_violation_scenario_name)
            objexpr_stage2 = lr_instance.get_objective_stage2(
                self.stage2_vars[max_violation_scenario_name], scenario)
            rhs = objexpr_stage2 - self.wass_mult * scenario_distance
            self.master.addLConstr(self.epi_vars[sample_name], ">", rhs)
            curr_remaining_copy.remove(max_violation_scenario_name)
        self.tsdro.remaining_scenario_names[sample_name] = curr_remaining_copy

        if count > 0:
            print(sample_name, "added", count, "scenarios.")
        return found_hyp