Example #1
0
def _models_have_same_sense(models):
    ''' Check if every model in the provided dict has the same objective sense.

        Input:
            models (dict) -- Keys are scenario names, values are Pyomo
                ConcreteModel objects.
        Returns:
            is_minimizing (bool) -- True if and only if minimizing. None if the
                check fails.
            check (bool) -- True only if all the models have the same sense (or
                no models were provided)
        Raises:
            ValueError -- If any of the models has either none or multiple
                active objectives.
    '''
    if (len(models) == 0):
        return True, True
    senses = [
        find_active_objective(scenario, True).is_minimizing()
        for scenario in models.values()
    ]
    sense = senses[0]
    check = all(val == sense for val in senses)
    if (check):
        return (sense == pyo.minimize), check
    return None, check
Example #2
0
 def _compute_objective_term(self):
     total = 0.0
     for scenario in self._ph._scenario_tree._scenarios:
         instance = self._ph._instances[scenario._name]
         total += -scenario._probability * value(
             find_active_objective(instance))
     return total
Example #3
0
    def _extract_objective(self, mip):
        ''' Extract the original part of the provided MIP's objective function
            (no dual or prox terms), and create a copy containing the QP
            variables in place of the MIP variables.

            Args:
                mip (Pyomo ConcreteModel): MIP model for a scenario or bundle.

            Returns:
                obj (Pyomo Objective): objective function extracted
                    from the MIP
                new (Pyomo Expression): expression from the MIP model
                    objective with the MIP variables replaced by QP variables.
                    Does not inculde dual or prox terms.

            Notes:
                Acts on either a single-scenario model or a bundle
        '''
        mip_to_qp = mip.mip_to_qp
        obj = find_active_objective(mip, True)
        repn = generate_standard_repn(obj.expr, quadratic=True)
        if len(repn.nonlinear_vars) > 0:
            raise ValueError("FWPH does not support models with nonlinear objective functions")
        linear_vars = [mip_to_qp[id(var)] for var in repn.linear_vars]
        new = LinearExpression(
            constant=repn.constant, linear_coefs=repn.linear_coefs, linear_vars=linear_vars
        )
        if repn.quadratic_vars:
            quadratic_vars = (
                (mip_to_qp[id(x)], mip_to_qp[id(y)]) for x,y in repn.quadratic_vars
            )
            new += pyo.quicksum(
                (coef*x*y for coef,(x,y) in zip(repn.quadratic_coefs, quadratic_vars))
            )
        return obj, new
Example #4
0
    def _check_bound(self):
        opt = self.opt

        chached_ph_obj = dict()

        for k, s in opt.local_subproblems.items():
            phobj = find_active_objective(s, True)
            phobj.deactivate()
            chached_ph_obj[k] = phobj
            s._EF_Obj.activate()

        teeme = ("tee-rank0-solves" in opt.PHoptions
                 and opt.PHoptions["tee-rank0-solves"])
        opt.solve_loop(
            solver_options=opt.current_solver_options,
            dtiming=opt.PHoptions["display_timing"],
            gripe=True,
            disable_pyomo_signal_handling=False,
            tee=teeme,
            verbose=opt.PHoptions["verbose"],
        )

        local_obs = np.fromiter(
            (s._PySP_ob for s in opt.local_subproblems.values()),
            dtype="d",
            count=len(opt.local_subproblems))

        local_ob = np.empty(1)
        if opt.is_minimizing:
            local_ob[0] = local_obs.max()
        else:
            local_ob[0] = local_obs.min()

        global_ob = np.empty(1)

        if opt.is_minimizing:
            opt.mpicomm.Allreduce(local_ob, global_ob, op=mpi.MAX)
        else:
            opt.mpicomm.Allreduce(local_ob, global_ob, op=mpi.MIN)

        #print(f"CrossScenarioExtension OB: {global_ob[0]}")

        opt.spcomm.BestOuterBound = opt.spcomm.OuterBoundUpdate(
            global_ob[0], 'C')

        for k, s in opt.local_subproblems.items():
            s._EF_Obj.deactivate()
            chached_ph_obj[k].activate()
Example #5
0
 def write_loop(self):
     """ Bundles are special. Also: this code needs help
     from the ph object to be more efficient...
     """
     for sname, s in self.ph.local_scenarios.items():
         bundling = not hasattr(s, "_solver_plugin")
         fname = self.dirname + os.sep + sname + ".dag"
         with open(fname, "a") as f:
             f.write(str(self.ph._PHIter) + ",")
             if not bundling:
                 objfct = find_active_objective(s, True)
                 f.write(str(pyo.value(objfct)))
             else:
                 f.write("Bundling" + ",")
                 f.write(str(pyo.value(self.ph.saved_objs[sname])))
             f.write("\n")
Example #6
0
    def post_iter0(self):
        opt = self.opt
        # NOTE: the LShaped code negates the objective, so
        #       we do the same here for consistency
        if 'cross_scen_options' in opt.options and \
                'valid_eta_bound' in opt.options['cross_scen_options']:
            valid_eta_bound = opt.options['cross_scen_options'][
                'valid_eta_bound']
            if not opt.is_minimizing:
                _eta_init = {k: -v for k, v in valid_eta_bound.items()}
            else:
                _eta_init = valid_eta_bound
            _eta_bounds = lambda m, k: (_eta_init[k], None)
        else:
            lb = (-sys.maxsize - 1) * 1. / len(opt.all_scenario_names)
            _eta_init = lambda m, k: lb
            _eta_bounds = lambda m, k: (lb, None)

        # eta is attached to each subproblem, regardless of bundles
        bundling = opt.bundling
        for k, s in opt.local_subproblems.items():
            s.eta = pyo.Var(opt.all_scenario_names,
                            initialize=_eta_init,
                            bounds=_eta_bounds)
            if sputils.is_persistent(s._solver_plugin):
                for var in s.eta.values():
                    s._solver_plugin.add_var(var)
            if bundling:  ## create a refence to eta on each subproblem
                for sn in s.scen_list:
                    scenario = opt.local_scenarios[sn]
                    scenario.eta = {
                        k: s.eta[k]
                        for k in opt.all_scenario_names
                    }

        ## hold the PH object harmless
        self._disable_W_and_prox()

        for k, s in opt.local_subproblems.items():

            obj = find_active_objective(s)

            repn = generate_standard_repn(obj.expr, quadratic=True)
            if len(repn.nonlinear_vars) > 0:
                raise ValueError(
                    "CrossScenario does not support models with nonlinear objective functions"
                )

            if bundling:
                ## NOTE: this is slighly wasteful, in that for a bundle
                ##       the first-stage cost appears len(s.scen_list) times
                ##       If this really made a difference, we could use s.ref_vars
                ##       to do the substitution
                nonant_vardata_list = list()
                for sn in s.scen_list:
                    nonant_vardata_list.extend( \
                            opt.local_scenarios[sn]._PySPnode_list[0].nonant_vardata_list)
            else:
                nonant_vardata_list = s._PySPnode_list[0].nonant_vardata_list

            nonant_ids = set((id(var) for var in nonant_vardata_list))

            linear_coefs = list(repn.linear_coefs)
            linear_vars = list(repn.linear_vars)

            quadratic_coefs = list(repn.quadratic_coefs)

            # adjust coefficients by scenario/bundle probability
            scen_prob = s.PySP_prob
            for i, var in enumerate(repn.linear_vars):
                if id(var) not in nonant_ids:
                    linear_coefs[i] *= scen_prob

            for i, (x, y) in enumerate(repn.quadratic_vars):
                # only multiply through once
                if id(x) not in nonant_ids:
                    quadratic_coefs[i] *= scen_prob
                elif id(y) not in nonant_ids:
                    quadratic_coefs[i] *= scen_prob

            # NOTE: the LShaped code negates the objective, so
            #       we do the same here for consistency
            if not opt.is_minimizing:
                for i, coef in enumerate(linear_coefs):
                    linear_coefs[i] = -coef
                for i, coef in enumerate(quadratic_coefs):
                    quadratic_coefs[i] = -coef

            # add the other etas
            if bundling:
                these_scenarios = set(s.scen_list)
            else:
                these_scenarios = [k]

            eta_scenarios = list()
            for sn in opt.all_scenario_names:
                if sn not in these_scenarios:
                    linear_coefs.append(1)
                    linear_vars.append(s.eta[sn])
                    eta_scenarios.append(sn)

            expr = LinearExpression(constant=repn.constant,
                                    linear_coefs=linear_coefs,
                                    linear_vars=linear_vars)

            if repn.quadratic_vars:
                expr += pyo.quicksum((coef * x * y for coef, (
                    x, y) in zip(quadratic_coefs, repn.quadratic_vars)))

            s._EF_obj = pyo.Expression(expr=expr)

            if opt.is_minimizing:
                s._EF_Obj = pyo.Objective(expr=s._EF_obj, sense=pyo.minimize)
            else:
                s._EF_Obj = pyo.Objective(expr=-s._EF_obj, sense=pyo.maximize)
            s._EF_Obj.deactivate()

            # add cut constraint dicts
            s._benders_cuts = pyo.Constraint(pyo.Any)
            s._ib_constr = pyo.Constraint(pyo.Any)

        self._enable_W_and_prox()

        # try to get the initial eta LB cuts
        # (may not be available)
        opt.spcomm.get_from_cross_cuts()
Example #7
0
    def create_subproblem(self, scenario_name):
        """ the subproblem creation function passed into the
            BendersCutsGenerator 
        """
        instance = self.local_scenarios[scenario_name]

        nonant_list, nonant_ids = _get_nonant_ids(instance)

        # NOTE: since we use generate_standard_repn below, we need
        #       to unfix any nonants so they'll properly appear
        #       in the objective
        fixed_nonants = [var for var in nonant_list if var.fixed]
        for var in fixed_nonants:
            var.fixed = False

        # pulls the scenario objective expression, removes the first stage variables, and sets the new objective
        obj = find_active_objective(instance)

        if not hasattr(instance, "PySP_prob"):
            instance.PySP_prob = 1. / self.scenario_count
        PySP_prob = instance.PySP_prob

        repn = generate_standard_repn(obj.expr, quadratic=True)
        if len(repn.nonlinear_vars) > 0:
            raise ValueError(
                "LShaped does not support models with nonlinear objective functions"
            )

        linear_vars = list()
        linear_coefs = list()
        quadratic_vars = list()
        quadratic_coefs = list()
        ## we'll assume the constant is part of stage 1 (wlog it is), just
        ## like the first-stage bits of the objective
        constant = repn.constant

        ## only keep the second stage variables in the objective
        for coef, var in zip(repn.linear_coefs, repn.linear_vars):
            id_var = id(var)
            if id_var not in nonant_ids:
                linear_vars.append(var)
                linear_coefs.append(PySP_prob * coef)
        for coef, (x, y) in zip(repn.quadratic_coefs, repn.quadratic_vars):
            id_x = id(x)
            id_y = id(y)
            if id_x not in nonant_ids or id_y not in nonant_ids:
                quadratic_coefs.append(PySP_prob * coef)
                quadratic_vars.append((x, y))

        # checks if model sense is max, if so negates the objective
        if not self.is_minimizing:
            for i, coef in enumerate(linear_coefs):
                linear_coefs[i] = -coef
            for i, coef in enumerate(quadratic_coefs):
                quadratic_coefs[i] = -coef

        expr = LinearExpression(constant=constant,
                                linear_coefs=linear_coefs,
                                linear_vars=linear_vars)
        if quadratic_coefs:
            expr += pyo.quicksum(
                (coef * x * y
                 for coef, (x, y) in zip(quadratic_coefs, quadratic_vars)))

        instance.del_component(obj)

        # set subproblem objective function
        instance.obj = pyo.Objective(expr=expr, sense=pyo.minimize)

        ## need to do this here for validity if computing the eta bound
        if self.relax_master:
            # relaxes any integrality constraints for the subproblem
            RelaxIntegerVars().apply_to(instance)

        if self.compute_eta_bound:
            for var in fixed_nonants:
                var.fixed = True
            opt = pyo.SolverFactory(self.options["sp_solver"])
            if self.options["sp_solver_options"]:
                for k, v in self.options["sp_solver_options"].items():
                    opt.options[k] = v

            if sputils.is_persistent(opt):
                opt.set_instance(instance)
                res = opt.solve(tee=False)
            else:
                res = opt.solve(instance, tee=False)

            eta_lb = res.Problem[0].Lower_bound

            self.valid_eta_lb[scenario_name] = eta_lb

        # if not done above
        if not self.relax_master:
            # relaxes any integrality constraints for the subproblem
            RelaxIntegerVars().apply_to(instance)

        # iterates through constraints and removes first stage constraints from the model
        # the id dict is used to improve the speed of identifying the stage each variables belongs to
        for constr_data in list(
                itertools.chain(
                    instance.component_data_objects(SOSConstraint,
                                                    active=True,
                                                    descend_into=True),
                    instance.component_data_objects(Constraint,
                                                    active=True,
                                                    descend_into=True))):
            if _first_stage_only(constr_data, nonant_ids):
                _del_con(constr_data)

        # creates the sub map to remove first stage variables from objective expression
        complicating_vars_map = pyo.ComponentMap()
        subproblem_to_master_vars_map = pyo.ComponentMap()

        # creates the complicating var map that connects the first stage variables in the sub problem to those in
        # the master problem -- also set the bounds on the subproblem master vars to be none for better cuts
        for var, mvar in zip(nonant_list, self.master_vars):
            if var.name not in mvar.name:  # mvar.name may be part of a bundle
                raise Exception(
                    "Error: Complicating variable mismatch, sub-problem variables changed order"
                )
            complicating_vars_map[mvar] = var
            subproblem_to_master_vars_map[var] = mvar

            # these are already enforced in the master
            # don't need to be enfored in the subproblems
            var.setlb(None)
            var.setub(None)
            var.fixed = False

        # this is for interefacing with PH code
        instance._subproblem_to_master_vars_map = subproblem_to_master_vars_map

        if self.store_subproblems:
            self.subproblems[scenario_name] = instance

        return instance, complicating_vars_map
Example #8
0
    def _create_master_with_scenarios(self):

        ef_scenarios = self.master_scenarios

        ## we want the correct probabilities to be set when
        ## calling create_EF
        if len(ef_scenarios) > 1:

            def scenario_creator_wrapper(name, **creator_options):
                scenario = self.scenario_creator(name, **creator_options)
                if not hasattr(scenario, 'PySP_prob'):
                    scenario.PySP_prob = 1. / len(self.all_scenario_names)
                return scenario

            master = sputils.create_EF(ef_scenarios,
                                       scenario_creator_wrapper,
                                       creator_options={
                                           'node_names': None,
                                           'cb_data': self.cb_data
                                       })

            nonant_list, nonant_ids = _get_nonant_ids_EF(master)
        else:
            master = self.scenario_creator(ef_scenarios[0],
                                           node_names=None,
                                           cb_data=self.cb_data)
            if not hasattr(master, 'PySP_prob'):
                master.PySP_prob = 1. / len(self.all_scenario_names)

            nonant_list, nonant_ids = _get_nonant_ids(master)

        self.master_vars = nonant_list

        # creates the eta variables for scenarios that are NOT selected to be
        # included in the master problem
        eta_indx = [
            scenario_name for scenario_name in self.all_scenario_names
            if scenario_name not in self.master_scenarios
        ]
        self._add_master_etas(master, eta_indx)

        obj = find_active_objective(master)

        repn = generate_standard_repn(obj.expr, quadratic=True)
        if len(repn.nonlinear_vars) > 0:
            raise ValueError(
                "LShaped does not support models with nonlinear objective functions"
            )
        linear_vars = list(repn.linear_vars)
        linear_coefs = list(repn.linear_coefs)
        quadratic_coefs = list(repn.quadratic_coefs)

        # adjust coefficients by scenario/bundle probability
        scen_prob = master.PySP_prob
        for i, var in enumerate(repn.linear_vars):
            if id(var) not in nonant_ids:
                linear_coefs[i] *= scen_prob

        for i, (x, y) in enumerate(repn.quadratic_vars):
            # only multiply through once
            if id(x) not in nonant_ids:
                quadratic_coefs[i] *= scen_prob
            elif id(y) not in nonant_ids:
                quadratic_coefs[i] *= scen_prob

        # NOTE: the LShaped code negates the objective, so
        #       we do the same here for consistency
        if not self.is_minimizing:
            for i, coef in enumerate(linear_coefs):
                linear_coefs[i] = -coef
            for i, coef in enumerate(quadratic_coefs):
                quadratic_coefs[i] = -coef

        # add the etas
        for var in master.eta.values():
            linear_vars.append(var)
            linear_coefs.append(1)

        expr = LinearExpression(constant=repn.constant,
                                linear_coefs=linear_coefs,
                                linear_vars=linear_vars)
        if repn.quadratic_vars:
            expr += pyo.quicksum(
                (coef * x * y
                 for coef, (x,
                            y) in zip(quadratic_coefs, repn.quadratic_vars)))

        master.del_component(obj)

        # set master objective function
        master.obj = pyo.Objective(expr=expr, sense=pyo.minimize)

        self.master = master
Example #9
0
    def _create_master_no_scenarios(self):

        # using the first scenario as a basis
        master = self.scenario_creator(self.all_scenario_names[0],
                                       node_names=None,
                                       cb_data=self.cb_data)

        if self.relax_master:
            RelaxIntegerVars().apply_to(master)

        nonant_list, nonant_ids = _get_nonant_ids(master)

        self.master_vars = nonant_list

        for constr_data in list(
                itertools.chain(
                    master.component_data_objects(SOSConstraint,
                                                  active=True,
                                                  descend_into=True),
                    master.component_data_objects(Constraint,
                                                  active=True,
                                                  descend_into=True))):
            if not _first_stage_only(constr_data, nonant_ids):
                _del_con(constr_data)

        # delete the second stage variables
        for var in list(
                master.component_data_objects(Var,
                                              active=True,
                                              descend_into=True)):
            if id(var) not in nonant_ids:
                _del_var(var)

        self._add_master_etas(master, self.all_scenario_names)

        # pulls the current objective expression, adds in the eta variables,
        # and removes the second stage variables from the expression
        obj = find_active_objective(master)

        repn = generate_standard_repn(obj.expr, quadratic=True)
        if len(repn.nonlinear_vars) > 0:
            raise ValueError(
                "LShaped does not support models with nonlinear objective functions"
            )

        linear_vars = list()
        linear_coefs = list()
        quadratic_vars = list()
        quadratic_coefs = list()
        ## we'll assume the constant is part of stage 1 (wlog it is), just
        ## like the first-stage bits of the objective
        constant = repn.constant

        ## only keep the first stage variables in the objective
        for coef, var in zip(repn.linear_coefs, repn.linear_vars):
            id_var = id(var)
            if id_var in nonant_ids:
                linear_vars.append(var)
                linear_coefs.append(coef)
        for coef, (x, y) in zip(repn.quadratic_coefs, repn.quadratic_vars):
            id_x = id(x)
            id_y = id(y)
            if id_x in nonant_ids and id_y in nonant_ids:
                quadratic_coefs.append(coef)
                quadratic_vars.append((x, y))

        # checks if model sense is max, if so negates the objective
        if not self.is_minimizing:
            for i, coef in enumerate(linear_coefs):
                linear_coefs[i] = -coef
            for i, coef in enumerate(quadratic_coefs):
                quadratic_coefs[i] = -coef

        # add the etas
        for var in master.eta.values():
            linear_vars.append(var)
            linear_coefs.append(1)

        expr = LinearExpression(constant=constant,
                                linear_coefs=linear_coefs,
                                linear_vars=linear_vars)
        if quadratic_coefs:
            expr += pyo.quicksum(
                (coef * x * y
                 for coef, (x, y) in zip(quadratic_coefs, quadratic_vars)))

        master.del_component(obj)

        # set master objective function
        master.obj = pyo.Objective(expr=expr, sense=pyo.minimize)

        self.master = master
Example #10
0
   def partialLagrangeParametric(args=None):
      print("lagrangeParam begins ")
      blanks = "                          "  # used for formatting print statements
      class Object(object): pass
      Result = Object()

# options used
      IndVarName = options.indicator_var_name
      CCStageNum = options.stage_num
      alphaTol = options.alpha_tol
      MaxMorePR = options.MaxMorePR # option to include up to this many PR points above F^* with all delta fixed
      outputFilePrefix = options.outputFilePrefix

# We write ScenarioList = name, probability
#          PRoptimal    = probability, min-cost, [selections]
#          PRmore       = probability, min-cost, [selections]
# ================ sorted by probability ========================
#
# These can be read to avoid re-computing points

      ph = PHFromScratch(options)
      Result.ph = ph
      rootnode = ph._scenario_tree._stages[0]._tree_nodes[0]   # use rootnode to loop over scenarios

      if find_active_objective(ph._scenario_tree._scenarios[0]._instance,safety_checks=True).is_minimizing():
         print("We are solving a MINIMIZATION problem.\n")
      else:
         print("We are solving a MAXIMIZATION problem.\n")

# initialize
      ScenarioList = []
      lambdaval = 0.
      lagrUtil.Set_ParmValue(ph,
                             options.lambda_parm_name,
                             lambdaval)

      # IMPORTANT: Preprocess the scenario instances
      #            before fixing variables, otherwise they
      #            will be preprocessed out of the expressions
      #            and the output_fixed_variable_bounds option
      #            will have no effect when we update the
      #            fixed variable values (and then assume we
      #            do not need to preprocess again because
      #            of this option).
      ph._preprocess_scenario_instances()

      lagrUtil.FixAllIndicatorVariables(ph, IndVarName, 0)
      for scenario in rootnode._scenarios:
         ScenarioList.append((scenario._name,
                              scenario._probability))

      # sorts from min to max probability
      ScenarioList.sort(key=operator.itemgetter(1))
      with open(outputFilePrefix+'ScenarioList.csv','w') as outFile:
         for scenario in ScenarioList:
            outFile.write(scenario[0]+ ", " +str(scenario[1])+"\n")
      Result.ScenarioList = ScenarioList

      print("lambda= "+str(lambdaval)+" ...run begins "+str(len(ScenarioList))+" scenarios")
      SolStat, zL = lagrUtil.solve_ph_code(ph, options)
      print("\t...ends")
      bL = Compute_ExpectationforVariable(ph,
                                          IndVarName,
                                          CCStageNum)
      if bL > 0:
         print("** bL = "+str(bL)+"  > 0")
         return Result

      print("Initial cost = "+str(zL)+"  for bL = "+str(bL))

      lagrUtil.FixAllIndicatorVariables(ph, IndVarName, 1)

      print("lambda= "+str(lambdaval)+" ...run begins")
      SolStat, zU = lagrUtil.solve_ph_code(ph, options)
      print("\t...ends")
      bU = Compute_ExpectationforVariable(ph,
                                          IndVarName,
                                          CCStageNum)
      if bU < 1:
            print("** bU = "+str(bU)+"  < 1")

      lagrUtil.FreeAllIndicatorVariables(ph, IndVarName)

      Result.lbz = [ [0,bL,zL], [None,bU,zU] ]
      Result.selections = [[], ScenarioList]
      NumIntervals = 1
      print("initial gap = "+str(1-zL/zU)+" \n")
      print("End of test; this is only a test.")

      return Result
Example #11
0
File: ef.py Project: Pyomo/pyomo
    def solve(self,
              check_status=True,
              exception_on_failure=True,
              output_solver_log=False,
              symbolic_solver_labels=False,
              keep_solver_files=False,
              io_options=None):
        # TODO: Does this import need to be delayed because
        #       it is in a plugins subdirectory
        from pyomo.solvers.plugins.solvers.persistent_solver import \
            PersistentSolver

        if self.instance is None:
            raise RuntimeError(
                "The extensive form instance has not been constructed."
                "Call the build_ef() method to construct it.")

        start_time = time.time()
        if self.get_option("verbose"):
            print("Queuing extensive form solve")

        self.objective = None
        self.gap = None
        self.bound = None
        self.termination_condition = None
        self.termination_message = None
        self.solver_status = None
        self.solution_status = None
        self.solver_results = None
        self.time = None
        self.pyomo_time = None

        if isinstance(self._solver, PersistentSolver):
            self._solver.compile_instance(
                self.instance,
                symbolic_solver_labels=symbolic_solver_labels)

        solve_kwds = {}
        solve_kwds['load_solutions'] = False
        if keep_solver_files:
            solve_kwds['keepfiles'] = True
        if symbolic_solver_labels:
            solve_kwds['symbolic_solver_labels'] = True
        if output_solver_log:
            solve_kwds['tee'] = True

        solver_options = self.get_option("solver_options")
        if len(solver_options) > 0:
            if type(solver_options) is tuple:
                solve_kwds["options"] = {}
                for name_val in solver_options:
                    assert "=" in name_val
                    name, val = name_val.split("=")
                    solve_kwds["options"][name.strip()] = val.strip()
            else:
                solve_kwds["options"] = solver_options

        if io_options is not None:
            solve_kwds.update(io_options)

        self.objective_sense = \
            find_active_objective(self.instance).sense

        if (not self.get_option("disable_warmstart")) and \
           (self._solver.warm_start_capable()):
            action_handle = self._solver_manager.queue(self.instance,
                                                       opt=self._solver,
                                                       warmstart=True,
                                                       **solve_kwds)
        else:
            action_handle = self._solver_manager.queue(self.instance,
                                                       opt=self._solver,
                                                       **solve_kwds)

        if self.get_option("verbose"):
            print("Waiting for extensive form solve")
        results = self._solver_manager.wait_for(action_handle)

        if self.get_option("verbose"):
            print("Done with extensive form solve - loading results")

        if self.get_option("output_solver_results"):
            print("Results for ef:")
            results.write(num=1)

        self.solver_results = results
        if hasattr(results.solver,"user_time") and \
           (not isinstance(results.solver.user_time,
                           UndefinedData)) and \
           (results.solver.user_time is not None):
            # the solve time might be a string, or might
            # not be - we eventually would like more
            # consistency on this front from the solver
            # plugins.
            self.time = \
                float(results.solver.user_time)
        elif hasattr(results.solver,"time"):
            self.time = \
                float(results.solver.time)
        else:
            self.time = None

        if hasattr(results,"pyomo_solve_time"):
            self.pyomo_time = \
                results.pyomo_solve_time
        else:
            self.pyomo_time = None

        self.termination_condition = \
            results.solver.termination_condition
        self.termination_message = None
        if hasattr(results.solver,"termination_message"):
            self.termination_message = results.solver.termination_message
        elif hasattr(results.solver,"message"):
            self.termination_message = results.solver.message
        self.solver_status = \
            results.solver.status

        if len(results.solution) > 0:
            assert len(results.solution) == 1

            results_sm = results._smap
            self.instance.solutions.load_from(results)

            solution0 = results.solution(0)
            if hasattr(solution0, "gap") and \
               (solution0.gap is not None) and \
               (not isinstance(solution0.gap,
                               UndefinedData)):
                self.gap = float(solution0.gap)
            else:
                self.gap = None

            self.solution_status = solution0.status

            if self.get_option("verbose"):
                print("Storing solution in scenario tree")

            for scenario in self._manager.scenario_tree.scenarios:
                scenario.update_solution_from_instance()
            self._manager.scenario_tree.snapshotSolutionFromScenarios()
            self.objective = self._manager.scenario_tree.\
                             findRootNode().\
                             computeExpectedNodeCost()
            if self.gap is not None:
                if self.objective_sense == pyomo.core.base.minimize:
                    self.bound = self.objective - self.gap
                else:
                    self.bound = self.objective + self.gap

        else:

            self.objective = None
            self.gap = None
            self.bound = None
            self.solution_status = None

        failure = False

        if check_status:
            if not ((self.solution_status == SolutionStatus.optimal) or \
                    (self.solution_status == SolutionStatus.feasible)):
                failure = True
                if self.get_option("verbose") or \
                   exception_on_failure:
                    msg = ("EF solve failed solution status check:\n"
                           "Solver Status: %s\n"
                           "Termination Condition: %s\n"
                           "Solution Status: %s\n"
                           % (self.solver_status,
                              self.termination_condition,
                              self.solution_status))
                    if self.get_option("verbose"):
                        print(msg)
                    if exception_on_failure:
                        raise RuntimeError(msg)
        else:
            if self.get_option("verbose"):
                print("EF solve completed. Skipping status check.")

        if self.get_option("verbose") or self.get_option("output_times"):
            print("Time to solve and load results for the "
                  "extensive form=%.2f seconds"
                  % (time.time()-start_time))

        return failure
Example #12
0
    def partialLagrangeParametric(args=None):
        print("lagrangeParam begins ")
        blanks = "                          "  # used for formatting print statements

        class Object(object):
            pass

        Result = Object()

        # options used
        IndVarName = options.indicator_var_name
        CCStageNum = options.stage_num
        alphaTol = options.alpha_tol
        MaxMorePR = options.MaxMorePR  # option to include up to this many PR points above F^* with all delta fixed
        outputFilePrefix = options.outputFilePrefix

        # We write ScenarioList = name, probability
        #          PRoptimal    = probability, min-cost, [selections]
        #          PRmore       = probability, min-cost, [selections]
        # ================ sorted by probability ========================
        #
        # These can be read to avoid re-computing points

        ph = PHFromScratch(options)
        Result.ph = ph
        rootnode = ph._scenario_tree._stages[0]._tree_nodes[
            0]  # use rootnode to loop over scenarios

        if find_active_objective(ph._scenario_tree._scenarios[0]._instance,
                                 safety_checks=True).is_minimizing():
            print("We are solving a MINIMIZATION problem.\n")
        else:
            print("We are solving a MAXIMIZATION problem.\n")

# initialize
        ScenarioList = []
        lambdaval = 0.
        lagrUtil.Set_ParmValue(ph, options.lambda_parm_name, lambdaval)

        # IMPORTANT: Preprocess the scenario instances
        #            before fixing variables, otherwise they
        #            will be preprocessed out of the expressions
        #            and the output_fixed_variable_bounds option
        #            will have no effect when we update the
        #            fixed variable values (and then assume we
        #            do not need to preprocess again because
        #            of this option).
        ph._preprocess_scenario_instances()

        lagrUtil.FixAllIndicatorVariables(ph, IndVarName, 0)
        for scenario in rootnode._scenarios:
            ScenarioList.append((scenario._name, scenario._probability))

        # sorts from min to max probability
        ScenarioList.sort(key=operator.itemgetter(1))
        with open(outputFilePrefix + 'ScenarioList.csv', 'w') as outFile:
            for scenario in ScenarioList:
                outFile.write(scenario[0] + ", " + str(scenario[1]) + "\n")
        Result.ScenarioList = ScenarioList

        print("lambda= " + str(lambdaval) + " ...run begins " +
              str(len(ScenarioList)) + " scenarios")
        SolStat, zL = lagrUtil.solve_ph_code(ph, options)
        print("\t...ends")
        bL = Compute_ExpectationforVariable(ph, IndVarName, CCStageNum)
        if bL > 0:
            print("** bL = " + str(bL) + "  > 0")
            return Result

        print("Initial cost = " + str(zL) + "  for bL = " + str(bL))

        lagrUtil.FixAllIndicatorVariables(ph, IndVarName, 1)

        print("lambda= " + str(lambdaval) + " ...run begins")
        SolStat, zU = lagrUtil.solve_ph_code(ph, options)
        print("\t...ends")
        bU = Compute_ExpectationforVariable(ph, IndVarName, CCStageNum)
        if bU < 1:
            print("** bU = " + str(bU) + "  < 1")

        lagrUtil.FreeAllIndicatorVariables(ph, IndVarName)

        Result.lbz = [[0, bL, zL], [None, bU, zU]]
        Result.selections = [[], ScenarioList]
        NumIntervals = 1
        print("initial gap = " + str(1 - zL / zU) + " \n")
        print("End of test; this is only a test.")

        return Result
Example #13
0
    def LagrangeParametric(args=None):
        class Object(object):
            pass

        Result = Object()
        Result.status = 'LagrangeParam begins ' + datetime_string(
        ) + '...running new ph'
        ph = None

        blanks = "                          "  # used for formatting print statements
        # options used
        betaMin = options.beta_min
        betaMax = options.beta_max
        betaTol = options.beta_tol
        gapTol = options.Lagrange_gap
        minProb = options.min_prob
        maxIntervals = options.max_intervals
        maxTime = options.max_time
        IndVarName = options.indicator_var_name
        multName = options.lambda_parm_name
        CCStageNum = options.stage_num
        csvPrefix = options.csvPrefix
        verbosity = options.verbosity
        verbosity = 2  # override for debug (= 3 to get super-debug)
        HGdebug = 0  # special debug (not public)
        # local...may become option
        optTol = gapTol
        ####################################################################
        STARTTIME = time.time()

        Result.status = "options set"
        if verbosity > 1:
            print("From LagrangeParametric, status = %s\tSTARTTIME = %s" \
                    % (str(getattr(Result,'status')), str(STARTTIME)))

        ph = PHFromScratch(options)
        Result.ph = ph
        rootnode = ph._scenario_tree._stages[0]._tree_nodes[
            0]  # use rootnode to loop over scenarios
        ReferenceInstance = ph._instances[
            rootnode._scenarios[0]._name]  # arbitrary scenario

        if find_active_objective(ph._scenario_tree._scenarios[0]._instance,
                                 safety_checks=True).is_minimizing():
            sense = 'min'
        else:
            sense = 'max'

        scenario_count = len(full_scenario_tree._stages[-1]._tree_nodes)
        if options.verbosity > 0:
            print("%s %s scenarios" % (str(sense), str(scenario_count)))

        # initialize
        Result.status = 'starting at ' + datetime_string()
        if verbosity > 0:
            print(Result.status)
        ScenarioList = []
        lambdaval = 0.
        lagrUtil.Set_ParmValue(ph, multName, lambdaval)

        # IMPORTANT: Preprocess the scenario instances
        #            before fixing variables, otherwise they
        #            will be preprocessed out of the expressions
        #            and the output_fixed_variable_bounds option
        #            will have no effect when we update the
        #            fixed variable values (and then assume we
        #            do not need to preprocess again because
        #            of this option).
        ph._preprocess_scenario_instances()

        sumprob = 0.
        minprob = 1.
        maxprob = 0.
        # fixed = 0 to get PR point at b=0
        lagrUtil.FixAllIndicatorVariables(ph, IndVarName, 0)
        for scenario in rootnode._scenarios:
            instance = ph._instances[scenario._name]
            sname = scenario._name
            sprob = scenario._probability
            sumprob = sumprob + sprob
            minprob = min(minprob, sprob)
            maxprob = max(maxprob, sprob)
            ScenarioList.append([sname, sprob])

        ScenarioList.sort(
            key=operator.itemgetter(1))  # sorts from min to max probability
        if verbosity > 0:
            print("probabilities sum to %f range: %f to %f" %
                  (sumprob, minprob, maxprob))
        Result.ScenarioList = ScenarioList

        # Write ScenarioList = name, probability in csv file sorted by probability
        outName = csvPrefix + 'ScenarioList.csv'
        print("writing to %s" % outName)
        with open(outName, 'w') as outFile:
            for scenario in ScenarioList:
                outFile.write(scenario[0] + ", " + str(scenario[1]) + '\n')
        Result.ScenarioList = ScenarioList

        addstatus = 'Scenario List written to ' + csvPrefix + 'ScenarioList.csv'
        Result.status = Result.status + '\n' + addstatus
        if verbosity > 0:
            print(addstatus)

        if verbosity > 0:
            print("solve begins %s" % datetime_string())
            print("\t- lambda = %f" % lambdaval)
        SolStat, zL = lagrUtil.solve_ph_code(ph, options)
        if verbosity > 0:
            print("solve ends %s" % datetime_string())
            print("\t- status = %s" % str(SolStat))
            print("\t- zL = %s" % str(zL))

        bL = Compute_ExpectationforVariable(ph, IndVarName, CCStageNum)
        if bL > 0:
            print("** bL = %s > 0 (all %s = 0)" % (str(bL), str(IndVarName)))
            return Result

        if verbosity > 0:
            print("Initial optimal obj = %s for bL = %s" % (str(zL), str(bL)))

        # fixed = 1 to get PR point at b=1
        lagrUtil.FixAllIndicatorVariables(ph, IndVarName, 1)

        if verbosity > 0:
            print("solve begins %s" % datetime_string())
            print("\t- lambda = %s" % str(lambdaval))
        SolStat, zU = lagrUtil.solve_ph_code(ph, options)
        if verbosity > 0:
            print("solve ends %s" % datetime_string())
            print("\t- status = %s" % str(SolStat))
            print("\t- zU = %s" % str(zU))
        if not SolStat[0:2] == 'ok':
            print(str(SolStat[0:3]) + " is not 'ok'")
            addstatus = "** Solution is non-optimal...aborting"
            print(addstatus)
            Result.status = Result.status + "\n" + addstatus
            return Result

        bU = Compute_ExpectationforVariable(ph, IndVarName, CCStageNum)
        if bU < 1. - betaTol and verbosity > 0:
            print("** Warning:  bU = %s  < 1" % str(bU))

### enumerate points in PR space (all but one scenario)
#      Result.lbz = [ [0,bL,zL], [None,bU,zU] ]
#      for scenario in rootnode._scenarios:
#         sname = scenario._name
#         instance = ph._instances[sname]
#         print "excluding scenario",sname
#         getattr(instance,IndVarName).value = 0
#         print sname,"value =",getattr(instance,IndVarName).value,getattr(instance,IndVarName).fixed
#         SolStat, z = lagrUtil.solve_ph_code(ph, options)
#         b = Compute_ExpectationforVariable(ph, IndVarName, CCStageNum)
#         print "solve ends with status =",SolStat,"(b, z) =",b,z
#         getattr(instance,IndVarName).value = 1
#         Result.lbz.append([None,b,z])
#         for t in instance.TimePeriods:
#           print "Global at",t,"=",instance.posGlobalLoadGenerateMismatch[t].value, \
#                '-',instance.negGlobalLoadGenerateMismatch[t].value,"=",\
#                    instance.GlobalLoadGenerateMismatch[t].value,\
#               "\tDemand =",instance.TotalDemand[t].value, ",",\
#                "Reserve =",instance.ReserveRequirement[t].value
#
#      PrintPRpoints(Result.lbz)
#      return Result
#### end enumeration
########################################################################

        if verbosity > 1:
            print("We have bU = %s ...about to free all %s for %d scenarios" % \
                   (str(bU), str(IndVarName), len(ScenarioList)))

        # free scenario selection variable
        lagrUtil.FreeAllIndicatorVariables(ph, IndVarName)

        if verbosity > 1:
            print("\tall %s freed; elapsed time = %f" %
                  (str(IndVarName), time.time() - STARTTIME))

# initialize with the two endpoints
        Result.lbz = [[0., bL, zL], [None, bU, zU]]
        Result.selections = [[], ScenarioList]
        NumIntervals = 1
        if verbosity > 0:
            print("Initial relative Lagrangian gap = %f maxIntervals = %d" %
                  (1 - zL / zU, maxIntervals))
            if verbosity > 1:
                print("entering while loop %s" % datetime_string())
            print("\n")

############ main loop to search intervals #############
########################################################
        while NumIntervals < maxIntervals:
            lapsedTime = time.time() - STARTTIME
            if lapsedTime > maxTime:
                addstatus = '** max time reached ' + str(lapsedTime)
                print(addstatus)
                Result.status = Result.status + '\n' + addstatus
                break
            if verbosity > 1:
                print("Top of while with %d intervals elapsed time = %f" %
                      (NumIntervals, lapsedTime))
                PrintPRpoints(Result.lbz)

            lambdaval = None
            ### loop over PR points to find first unfathomed interval to search ###
            for PRpoint in range(1, len(Result.lbz)):
                if Result.lbz[PRpoint][0] == None:
                    # multiplier = None means interval with upper endpoint at PRpoint not fathomed
                    bL = Result.lbz[PRpoint - 1][1]
                    zL = Result.lbz[PRpoint - 1][2]
                    bU = Result.lbz[PRpoint][1]
                    zU = Result.lbz[PRpoint][2]
                    lambdaval = (zU - zL) / (bU - bL)
                    break

#############################
# Exited from the for loop
            if verbosity > 1:
                print("exited for loop with PRpoint = %s ...lambdaval = %s" %
                      (PRpoint, lambdaval))
            if lambdaval == None: break  # all intervals are fathomed

            if verbosity > 1: PrintPRpoints(Result.lbz)
            if verbosity > 0:
                print("Searching for b in [%s, %s] with %s = %f" % (str(
                    round(bL, 4)), str(round(bU, 4)), multName, lambdaval))

# search interval (bL,bU)
            lagrUtil.Set_ParmValue(ph, multName, lambdaval)
            if verbosity > 0:
                print("solve begins %s" % datetime_string())
                print("\t- %s = %f" % (multName, lambdaval))

            #########################################################
            SolStat, Lagrangian = lagrUtil.solve_ph_code(ph, options)
            #########################################################
            if not SolStat[0:2] == 'ok':
                addstatus = "** Solution status " + SolStat + " is not optimal"
                print(addstatus)
                Result.status = Result.status + "\n" + addstatus
                return Result

            b = Compute_ExpectationforVariable(ph, IndVarName, CCStageNum)
            z = Lagrangian + lambdaval * b
            if verbosity > 0:
                print("solve ends %s" % datetime_string())
                print("\t- Lagrangian = %f" % Lagrangian)
                print("\t- b = %s" % str(b))
                print("\t- z = %s" % str(z))
                print("\n")

# We have PR point (b,z), which may be new or one of the endpoints
##################################################################

######### Begin tolerance tests ##########
# Test that b is in [bL,bU]
            if verbosity > 1: print("\ttesting b")
            if b < bL - betaTol or b > bU + betaTol:
                addstatus = "** fatal error: probability (= " + str(b) + \
                    ") is outside interval, (" + str(bL) + ", " + str(bU) + ")"
                addstatus = addstatus + "\n\t(tolerance = " + str(
                    betaTol) + ")"
                print(addstatus + '\n')
                Result.status = Result.status + addstatus
                return Result
# Test that z is in [zL,zU]
            if verbosity > 1: print("\ttesting z")
            # using optTol as absolute tolerance (not relative)
            #   ...if we reconsider, need to allow negative z-values
            if z < zL - optTol or z > zU + optTol:
                addstatus = "** fatal error: obj (= " + str(z) + \
                    ") is outside interval, (" + str(zL) + ", " + str(zU) + ")"
                print(addstatus + '\n')
                Result.status = Result.status + addstatus
                return Result

# Ok, we have (b,z) in [(bL,zL), (bU,zU)], at least within tolerances

            oldLagrangian = zL - lambdaval * bL
            # ensure lambdaval set such that endpoints have same Lagrangian value
            # (this is probably unnecessary, but check anyway)
            if abs(oldLagrangian -
                   (zU - lambdaval * bU)) > optTol * abs(oldLagrangian):
                addstatus = "** fatal error: Lagrangian at (bL,zL) = " + \
                    str(oldLagrangian) + " not= " + str(zU-lambdaval*bU) + \
                    "\n\t(optTol = " + str(optTol) + ")"
                Result.status = Result.status + addstatus
                return Result

# no more fatal error tests...need to know if (b,z) is endpoint or new

            if verbosity > 1: print("No anomalies...testing if b = bL or bU")

            # Test if endpoint is an alternative optimum of Lagrangian
            # ...using optTol as *relative* tolerance
            # (could use other reference values -- eg, avg or max of old and new Lagrangian values)
            refValue = max(min(abs(oldLagrangian), abs(Lagrangian)), 1.)
            alternativeOpt = abs(oldLagrangian -
                                 Lagrangian) <= optTol * refValue

            # alternativeOpt = True means we computed point (b,z) is alternative optimum such that:
            #   case 1: (b,z) = endpoint, in which case we simply fathom [bL,bU] by setting PRpoint
            #            to [lambdaval,bU,zU] (the numeric value of multiplier means fathomed)
            #   case 2: (b,z) is new PR point on line segment, in which case we split into
            #           [bL,b] and [b,bU], with both fathomed

            if verbosity > 1:
                print("oldLagrangian = %s" % str(oldLagrangian))
                if alternativeOpt:
                    print(":= Lagrangian = %s" % str(Lagrangian))
                else:
                    print("> Lagrangian = %s" % str(Lagrangian))

            if alternativeOpt:
                # setting multiplier of (bU,zU) to a numeric fathoms the interval [bL,bU]
                Result.lbz[PRpoint][0] = lambdaval

# test if (b,z) is an endpoint
            newPRpoint = abs(b - bL) > betaTol and abs(b - bU) > betaTol
            if not newPRpoint:
                # ...(b,z) is NOT an endpoint (or sufficiently close), so split and fathom
                if verbosity > 1:
                    print("\tnot an endpoint\tlbz = %s" %
                          str(Result.lbz[PRpoint]))
                if verbosity > 0:
                    print("Lagangian solution is new PR point on line segment of (" \
                       + str(bL) + ", " + str(bU) +")")
                    print(
                        "\tsplitting (bL,bU) into (bL,b) and (b,bU), both fathomed"
                    )
# note:  else ==> b = bL or bU, so we do nothing, having already fathomed [bL,bU]

# (b,z) is new PR point, so split interval (still in while loop)
##########################################
# alternative optimum ==> split & fathom: (bL,b), (b,bU)
            if verbosity > 1:
                print("\talternativeOpt %s newPRpoint = %s" %
                      (alternativeOpt, newPRpoint))
            if newPRpoint:
                NumIntervals += 1
                if alternativeOpt:
                    if verbosity > 1:
                        print("\tInsert [lambdaval,b,z] at %f" % PRpoint)
                    Result.lbz = Insert([lambdaval, b, z], PRpoint, Result.lbz)
                    addstatus = "Added PR point on line segment of envelope"
                    if verbosity > 0: print(addstatus + '\n')
                else:
                    if verbosity > 1:
                        print("\tInsert [None,b,z] at %f" % PRpoint)
                    Result.lbz = Insert([None, b, z], PRpoint, Result.lbz)
                    addstatus = "new envelope extreme point added (interval split, not fathomed)"
                Result.status = Result.status + "\n" + addstatus

                if verbosity > 1:
                    print("...after insertion:")
                    PrintPRpoints(Result.lbz)

# get the selections of new point (ie, scenarios for which delta=1)
                Selections = []
                for scenario in ScenarioList:
                    instance = ph._instances[scenario[0]]
                    if getattr(instance, IndVarName).value == 1:
                        Selections.append(scenario)
                Result.selections = Insert(Selections, PRpoint,
                                           Result.selections)

                if verbosity > 0:
                    print("Interval "+str(PRpoint)+", ["+str(bL)+", "+str(bU)+ \
                      "] split at ("+str(b)+", "+str(z)+")")
                    print("\tnew PR point has " + str(len(Selections)) +
                          " selections")

                if verbosity > 1:
                    print("test that selections list aligned with lbz")
                if not len(Result.lbz) == len(Result.selections):
                    print("** fatal error: lbz not= selections")
                    PrintPRpoints(Result.lbz)
                    print("Result.selections:")
                    for i in range(Result.selections):
                        print("%d %f" % (i, Result.selections[i]))
                    return Result

# ok, we have split and/or fathomed interval
            if NumIntervals >= maxIntervals:
                # we are about to leave while loop due to...
                addstatus = "** terminating because number of intervals = " + \
                        str(NumIntervals) + " >= max = " + str(maxIntervals)
                if verbosity > 0: print(addstatus + '\n')
                Result.status = Result.status + "\n" + addstatus

# while loop continues
            if verbosity > 1:
                print("bottom of while loop")
                PrintPRpoints(Result.lbz)

###################################################
# end while NumIntervals < maxIntervals:
#     ^ this is indentation of while loop
################ end while loop ###################

        if verbosity > 1: print("\nend while loop...setting multipliers")
        for i in range(1, len(Result.lbz)):
            db = Result.lbz[i][1] - Result.lbz[i - 1][1]
            dz = Result.lbz[i][2] - Result.lbz[i - 1][2]
            if dz > 0:
                Result.lbz[i][0] = dz / db
            else:
                #print "dz =",dz," at ",i,": ",Result.lbz[i]," -",Result.lbz[i-1]
                Result.lbz[i][0] = 0
        if verbosity > 0: PrintPRpoints(Result.lbz)

        addstatus = '\nLagrange multiplier search ends' + datetime_string()
        if verbosity > 0:
            print(addstatus + '\n')
        Result.status = Result.status + addstatus

        outName = csvPrefix + "PRoptimal.csv"
        with open(outName, 'w') as outFile:
            if verbosity > 0:
                print("writing PR points to " + outName + '\n')
            for lbz in Result.lbz:
                outFile.write(str(lbz[1]) + ", " + str(lbz[2]) + '\n')

        outName = csvPrefix + "OptimalSelections.csv"
        with open(outName, 'w') as outFile:
            if verbosity > 0:
                print("writing optimal selections for each PR point to " +
                      csvPrefix + 'PRoptimal.csv\n')
            for selections in Result.selections:
                char = ""
                thisSelection = ""
                for slist in selections:
                    if slist:
                        thisSelection = thisSelection + char + slist[0]
                        char = ","
                outFile.write(thisSelection + '\n')

        if verbosity > 0:
            print("\nReturning status:\n %s \n=======================" %
                  Result.status)

################################
        if verbosity > 2:
            print("\nAbout to return...Result attributes: %d" %
                  len(inspect.getmembers(Result)))
            for attr in inspect.getmembers(Result):
                print(attr[0])
            print("\n===========================================")
# LagrangeParametric ends here
        return Result
Example #14
0
   def LagrangeMorePR(args=None):
      print("lagrangeMorePR begins %s" % datetime_string())
      blanks = "                          "  # used for formatting print statements
      class Object(object): pass
      Result = Object()

# options used
      betaTol       = options.beta_tol          # tolerance used to separate b-values
      IndVarName    = options.indicator_var_name
      multName      = options.lambda_parm_name
      CCStageNum    = options.stage_num
      MaxMorePR     = options.max_number         # max PR points to be generated (above F^* with all delta fixed)
      MaxTime       = options.max_time           # max time before terminate
      csvPrefix = options.csvPrefix          # input filename prefix (eg, case name)
      probFileName  = options.probFileName       # name of file containing probabilities
##HG override
#      options.verbosity = 2
      verbosity     = options.verbosity

      Result.status = 'starting '+datetime_string()
      STARTTIME = time.time()

      ph = PHFromScratch(options)
      rootnode = ph._scenario_tree._stages[0]._tree_nodes[0]   # use rootnode to loop over scenarios

      if find_active_objective(ph._scenario_tree._scenarios[0]._instance,safety_checks=True).is_minimizing():
         print("We are solving a MINIMIZATION problem.")
      else:
         print("We are solving a MAXIMIZATION problem.")

# initialize
      ScenarioList = []
      with open(csvPrefix+"ScenarioList.csv",'r') as inputFile:
         for line in inputFile.readlines():
            L = line.split(',')
            ScenarioList.append([L[0],float(L[1])])

      addstatus = str(len(ScenarioList))+' scenarios read from file: ' + csvPrefix+'ScenarioList.csv'
      if verbosity > 0: print(addstatus)
      Result.status = Result.status + '\n' + addstatus

      PRoptimal = []
      with open(csvPrefix+"PRoptimal.csv",'r') as inputFile:
         for line in inputFile.readlines():
            bzS = line.split(',')
            PRoptimal.append( [None, float(bzS[0]), float(bzS[1])] )

      addstatus = str(len(PRoptimal))+' PR points read from file: '+ csvPrefix+'PRoptimal.csv (envelope function)'
      if verbosity > 0:
         print(addstatus)
      Result.status = Result.status + '\n' + addstatus
# ensure PR points on envelope function are sorted by probability
      PRoptimal.sort(key=operator.itemgetter(1))

      PRoptimal[0][0] = 0   # initial lambda (for b=0)
      for p in range(1,len(PRoptimal)):
         dz = PRoptimal[p][2] - PRoptimal[p-1][2]
         db = PRoptimal[p][1] - PRoptimal[p-1][1]
         PRoptimal[p][0] = dz/db
      if verbosity > 0:
         PrintPRpoints(PRoptimal)
      Result.PRoptimal = PRoptimal

      lambdaval = 0.
      lagrUtil.Set_ParmValue(ph, options.lambda_parm_name,lambdaval)

      # IMPORTANT: Preprocess the scenario instances
      #            before fixing variables, otherwise they
      #            will be preprocessed out of the expressions
      #            and the output_fixed_variable_bounds option
      #            will have no effect when we update the
      #            fixed variable values (and then assume we
      #            do not need to preprocess again because
      #            of this option).
      ph._preprocess_scenario_instances()

## read scenarios to select for each PR point on envelope function
      with open(csvPrefix+"OptimalSelections.csv",'r') as inputFile:
         OptimalSelections = []
         for line in inputFile.readlines():
            if len(line) == 0: break # eof
            selections = line.split(',')
            L = len(selections)
            Ls = len(selections[L-1])
            selections[L-1] = selections[L-1][0:Ls-1]
            if verbosity > 1:
               print(str(selections))
            OptimalSelections.append(selections)

      Result.OptimalSelections = OptimalSelections

      addstatus = str(len(OptimalSelections)) + ' Optimal selections read from file: ' \
            + csvPrefix + 'OptimalSelections.csv'
      Result.status = Result.status + '\n' + addstatus

      if len(OptimalSelections) == len(PRoptimal):
         if verbosity > 0:
            print(addstatus)
      else:
         addstatus = addstatus + '\n** Number of selections not equal to number of PR points'
         print(addstatus)
         Result.status = Result.status + '\n' + addstatus
         print(str(OptimalSelections))
         print((PRoptimal))
         return Result

#####################################################################################

# get probabilities
      if probFileName is None:
# ...generate from widest gap regions
         PRlist = FindPRpoints(options, PRoptimal)
      else:
# ...read probabilities
         probList = []
         with open(probFileName,'r') as inputFile:
            if verbosity > 0:
               print("reading from probList = "+probFileName)
            for line in inputFile.readlines():  # 1 probability per line
               if len(line) == 0:
                  break
               prob = float(line)
               probList.append(prob)

         if verbosity > 0:
            print("\t "+str(len(probList))+" probabilities")
         if verbosity > 1:
            print(str(probList))
         PRlist = GetPoints(options, PRoptimal, probList)
         if verbosity > 1:
            print("PRlist:")
            for interval in PRlist:
               print(str(interval))

# We now have PRlist = [[i, b], ...], where b is in PRoptimal interval (i-1,i)
      addstatus = str(len(PRlist)) + ' probabilities'
      if verbosity > 0:
         print(addstatus)
      Result.status = Result.status + '\n' + addstatus

#####################################################################################

      lapsedTime = time.time() - STARTTIME
      addstatus = 'Initialize complete...lapsed time = ' + str(lapsedTime)
      if verbosity > 1:
         print(addstatus)
      Result.status = Result.status + '\n' + addstatus

#####################################################################################

      if verbosity > 1:
        print("\nlooping over Intervals to generate PR points by flipping heuristic")
      Result.morePR = []
      for interval in PRlist:
         lapsedTime = time.time() - STARTTIME
         if lapsedTime > MaxTime:
            addstatus = '** lapsed time = ' + str(lapsedTime) + ' > max time = ' + str(MaxTime)
            if verbosity > 0: print(addstatus)
            Result.status = Result.status + '\n' + addstatus
            break

         i = interval[0] # = PR point index
         b = interval[1] # = target probability to reach by flipping from upper endpoint
         bU = PRoptimal[i][1]   # = upper endpoint
         bL = PRoptimal[i-1][1] # = lower endpoint
         if verbosity > 1:
            print( "target probability = "+str(b)+" < bU = PRoptimal[" + str(i) + "][1]" \
                 " and > bL = PRoptimal["+str(i-1)+"][1]")
         if b < bL or b > bU:
            addstatus = '** probability = '+str(b) + ', not in gap interval: (' \
                + str(bL) + ', ' + str(bU) + ')'
            print(addstatus)
            print(str(PRoptimal))
            print(str(PRlist))
            Result.status = Result.status + '\n' + addstatus
            return Result

         if verbosity > 1:
            print( "i = "+str(i)+" : Starting with bU = "+str(bU)+" having "+ \
                str(len(OptimalSelections[i]))+ " selections:")
            print(str(OptimalSelections[i]))

# first fix all scenarios = 0
         for sname, sprob in ScenarioList:
            scenario = ph._scenario_tree.get_scenario(sname)
            lagrUtil.FixIndicatorVariableOneScenario(ph,
                                                     scenario,
                                                     IndVarName,
                                                     0)

# now fix optimal selections = 1
         for sname in OptimalSelections[i]:
            scenario = ph._scenario_tree.get_scenario(sname)
            lagrUtil.FixIndicatorVariableOneScenario(ph,
                                                     scenario,
                                                     IndVarName,
                                                     1)

# flip scenario selections from bU until we reach b (target probability)
         bNew = bU
         for sname, sprob in ScenarioList:
            scenario = ph._scenario_tree.get_scenario(sname)
            if bNew - sprob < b:
               continue
            instance = ph._instances[sname]
            if getattr(instance, IndVarName).value == 0:
               continue
            bNew = bNew - sprob
            # flipped scenario selection
            lagrUtil.FixIndicatorVariableOneScenario(ph,
                                                     scenario,
                                                     IndVarName,
                                                     0)
            if verbosity > 1:
               print("\tflipped "+sname+" with prob = "+str(sprob)+" ...bNew = "+str(bNew))

         if verbosity > 1:
            print("\tflipped selections reach "+str(bNew)+" >= target = "+str(b)+" (bL = "+str(bL)+")")
         if bNew <= bL + betaTol or bNew >= bU - betaTol:
            if verbosity > 0:
               print("\tNot generating PR point...flipping from bU failed")
            continue # to next interval in list

 # ready to solve to get cost for fixed scenario selections associated with probability = bNew

         if verbosity > 1:
# check that scenarios are fixed as they should be
            totalprob = 0.
            for scenario in ScenarioList:
               sname = scenario[0]
               sprob = scenario[1]
               instance = ph._instances[sname]
               print("fix "+sname+" = "+str(getattr(instance,IndVarName).value)+\
                  " is "+str(getattr(instance,IndVarName).fixed)+" probability = "+str(sprob))
               if getattr(instance,IndVarName).value == 1:
                  totalprob = totalprob + sprob
               lambdaval = getattr(instance, multName).value
            print("\ttotal probability = %f" % totalprob)

# solve (all delta fixed); lambda=0, so z = Lagrangian
         if verbosity > 0:
            print("solve begins %s" % datetime_string())
            print("\t- lambda = %f" % lambdaval)
         SolStat, z = lagrUtil.solve_ph_code(ph, options)
         b = Compute_ExpectationforVariable(ph, IndVarName, CCStageNum)
         if verbosity > 0:
            print("solve ends %s" % datetime_string())
            print("\t- SolStat = %s" % str(SolStat))
            print("\t- b = %s" % str(b))
            print("\t- z = %s" % str(z))
            print("(adding to more PR points)")

         Result.morePR.append([None,b,z])
         if verbosity > 1:
            PrintPRpoints(Result.morePR)
      ######################################################
      # end loop over target probabilities

      with open(csvPrefix+"PRmore.csv",'w') as outFile:
         for point in Result.morePR:
            outFile.write(str(point[1])+','+str(point[2]))

      addstatus = str(len(Result.morePR)) + ' PR points written to file: '+ csvPrefix + 'PRmore.csv'
      if verbosity > 0: print(addstatus)
      Result.status = Result.status + '\n' + addstatus
      addstatus = 'lapsed time = ' + putcommas(time.time() - STARTTIME)
      if verbosity > 0: print(addstatus)
      Result.status = Result.status + '\n' + addstatus

      return Result
Example #15
0
    def SDM(self, model_name):
        '''  Algorithm 2 in Boland et al. (with small tweaks)
        '''
        mip = self.local_subproblems[model_name]
        qp = self.local_QP_subproblems[model_name]

        # Set the QP dual weights to the correct values If we are bundling, we
        # initialize the QP dual weights to be the dual weights associated with
        # the first scenario in the bundle (this should be okay, because each
        # scenario in the bundle has the same dual weights, analytically--maybe
        # a numerical problem).
        arb_scen_mip = self.local_scenarios[mip.scen_list[0]] \
                       if self.bundling else mip
        for (node_name, ix) in arb_scen_mip._nonant_indexes:
            qp._Ws[node_name, ix]._value = \
                arb_scen_mip._Ws[node_name, ix].value

        alpha = self.FW_options['FW_weight']
        # Algorithm 3 line 6
        xt = {
            ndn_i: (1 - alpha) * pyo.value(arb_scen_mip._xbars[ndn_i]) +
            alpha * pyo.value(xvar)
            for ndn_i, xvar in arb_scen_mip._nonant_indexes.items()
        }

        for itr in range(self.FW_options['FW_iter_limit']):
            # Algorithm 2 line 4
            mip_source = mip.scen_list if self.bundling else [model_name]
            for scenario_name in mip_source:
                scen_mip = self.local_scenarios[scenario_name]
                for ndn_i, nonant in scen_mip._nonant_indexes.items():
                    x_source = xt[ndn_i] if itr==0 \
                               else nonant._value
                    scen_mip._Ws[ndn_i]._value = (
                        qp._Ws[ndn_i]._value + scen_mip._PHrho[ndn_i]._value *
                        (x_source - scen_mip._xbars[ndn_i]._value))

            # Algorithm 2 line 5
            if (sputils.is_persistent(mip._solver_plugin)):
                mip_obj = find_active_objective(mip, True)
                mip._solver_plugin.set_objective(mip_obj)
            mip_results = mip._solver_plugin.solve(mip)
            self._check_solve(mip_results, model_name + ' (MIP)')

            # Algorithm 2 lines 6--8
            obj = find_active_objective(mip, True)
            if (itr == 0):
                dual_bound = pyo.value(obj)

            # Algorithm 2 line 9 (compute \Gamma^t)
            val0 = pyo.value(obj)
            new = replace_expressions(obj.expr, mip.mip_to_qp)
            val1 = pyo.value(new)
            obj.expr = replace_expressions(new, qp.qp_to_mip)
            if abs(val0) > 1e-9:
                stop_check = (val1 - val0) / abs(
                    val0)  # \Gamma^t in Boland, but normalized
            else:
                stop_check = val1 - val0  # \Gamma^t in Boland
            stop_check_tol = self.FW_options["stop_check_tol"]\
                             if "stop_check_tol" in self.FW_options else 1e-4
            if (self.is_minimizing and stop_check < -stop_check_tol):
                print(
                    'Warning (fwph): convergence quantity Gamma^t = '
                    '{sc:.2e} (should be non-negative)'.format(sc=stop_check))
                print('Try decreasing the MIP gap tolerance and re-solving')
            elif (not self.is_minimizing and stop_check > stop_check_tol):
                print(
                    'Warning (fwph): convergence quantity Gamma^t = '
                    '{sc:.2e} (should be non-positive)'.format(sc=stop_check))
                print('Try decreasing the MIP gap tolerance and re-solving')

            self._add_QP_column(model_name)
            if (sputils.is_persistent(qp._QP_solver_plugin)):
                qp_obj = find_active_objective(qp, True)
                qp._QP_solver_plugin.set_objective(qp_obj)
            qp_results = qp._QP_solver_plugin.solve(qp)
            self._check_solve(qp_results, model_name + ' (QP)')

            if (stop_check < self.FW_options['FW_conv_thresh']):
                break

        # Re-set the mip._Ws so that the QP objective
        # is correct in the next major iteration
        mip_source = mip.scen_list if self.bundling else [model_name]
        for scenario_name in mip_source:
            scen_mip = self.local_scenarios[scenario_name]
            for (node_name, ix) in scen_mip._nonant_indexes:
                scen_mip._Ws[node_name, ix]._value = \
                    qp._Ws[node_name, ix]._value

        return dual_bound
Example #16
0
   def LagrangeMorePR(args=None):
      print("lagrangeMorePR begins %s" % datetime_string())
      blanks = "                          "  # used for formatting print statements
      class Object(object): pass
      Result = Object()

# options used
      betaTol       = options.beta_tol          # tolerance used to separate b-values
      IndVarName    = options.indicator_var_name
      multName      = options.lambda_parm_name
      CCStageNum    = options.stage_num
      MaxMorePR     = options.max_number         # max PR points to be generated (above F^* with all delta fixed)
      MaxTime       = options.max_time           # max time before terminate
      csvPrefix = options.csvPrefix          # input filename prefix (eg, case name)
      probFileName  = options.probFileName       # name of file containing probabilities
##HG override
#      options.verbosity = 2
      verbosity     = options.verbosity

      Result.status = 'starting '+datetime_string()
      STARTTIME = time.time()

      ph = PHFromScratch(options)
      rootnode = ph._scenario_tree._stages[0]._tree_nodes[0]   # use rootnode to loop over scenarios

      if find_active_objective(ph._scenario_tree._scenarios[0]._instance,safety_checks=True).is_minimizing():
         print("We are solving a MINIMIZATION problem.")
      else:
         print("We are solving a MAXIMIZATION problem.")

# initialize
      ScenarioList = []
      with open(csvPrefix+"ScenarioList.csv",'r') as inputFile:
         for line in inputFile.readlines():
            L = line.split(',')
            ScenarioList.append([L[0],float(L[1])])

      addstatus = str(len(ScenarioList))+' scenarios read from file: ' + csvPrefix+'ScenarioList.csv'
      if verbosity > 0: print(addstatus)
      Result.status = Result.status + '\n' + addstatus

      PRoptimal = []
      with open(csvPrefix+"PRoptimal.csv",'r') as inputFile:
         for line in inputFile.readlines():
            bzS = line.split(',')
            PRoptimal.append( [None, float(bzS[0]), float(bzS[1])] )

      addstatus = str(len(PRoptimal))+' PR points read from file: '+ csvPrefix+'PRoptimal.csv (envelope function)'
      if verbosity > 0:
         print(addstatus)
      Result.status = Result.status + '\n' + addstatus
# ensure PR points on envelope function are sorted by probability
      PRoptimal.sort(key=operator.itemgetter(1))

      PRoptimal[0][0] = 0   # initial lambda (for b=0)
      for p in range(1,len(PRoptimal)):
         dz = PRoptimal[p][2] - PRoptimal[p-1][2]
         db = PRoptimal[p][1] - PRoptimal[p-1][1]
         PRoptimal[p][0] = dz/db
      if verbosity > 0:
         PrintPRpoints(PRoptimal)
      Result.PRoptimal = PRoptimal

      lambdaval = 0.
      lagrUtil.Set_ParmValue(ph, options.lambda_parm_name,lambdaval)

      # IMPORTANT: Preprocess the scenario instances
      #            before fixing variables, otherwise they
      #            will be preprocessed out of the expressions
      #            and the output_fixed_variable_bounds option
      #            will have no effect when we update the
      #            fixed variable values (and then assume we
      #            do not need to preprocess again because
      #            of this option).
      ph._preprocess_scenario_instances()

## read scenarios to select for each PR point on envelope function
      with open(csvPrefix+"OptimalSelections.csv",'r') as inputFile:
         OptimalSelections = []
         for line in inputFile.readlines():
            if len(line) == 0: break # eof
            selections = line.split(',')
            L = len(selections)
            Ls = len(selections[L-1])
            selections[L-1] = selections[L-1][0:Ls-1]
            if verbosity > 1:
               print(str(selections))
            OptimalSelections.append(selections)

      Result.OptimalSelections = OptimalSelections

      addstatus = str(len(OptimalSelections)) + ' Optimal selections read from file: ' \
            + csvPrefix + 'OptimalSelections.csv'
      Result.status = Result.status + '\n' + addstatus

      if len(OptimalSelections) == len(PRoptimal):
         if verbosity > 0:
            print(addstatus)
      else:
         addstatus = addstatus + '\n** Number of selections not equal to number of PR points'
         print(addstatus)
         Result.status = Result.status + '\n' + addstatus
         print(str(OptimalSelections))
         print((PRoptimal))
         return Result

#####################################################################################

# get probabilities
      if probFileName is None:
# ...generate from widest gap regions
         PRlist = FindPRpoints(options, PRoptimal)
      else:
# ...read probabilities
         probList = []
         with open(probFileName,'r') as inputFile:
            if verbosity > 0:
               print("reading from probList = "+probFileName)
            for line in inputFile.readlines():  # 1 probability per line
               if len(line) == 0:
                  break
               prob = float(line)
               probList.append(prob)

         if verbosity > 0:
            print("\t "+str(len(probList))+" probabilities")
         if verbosity > 1:
            print(str(probList))
         PRlist = GetPoints(options, PRoptimal, probList)
         if verbosity > 1:
            print("PRlist:")
            for interval in PRlist:
               print(str(interval))

# We now have PRlist = [[i, b], ...], where b is in PRoptimal interval (i-1,i)
      addstatus = str(len(PRlist)) + ' probabilities'
      if verbosity > 0:
         print(addstatus)
      Result.status = Result.status + '\n' + addstatus

#####################################################################################

      lapsedTime = time.time() - STARTTIME
      addstatus = 'Initialize complete...lapsed time = ' + str(lapsedTime)
      if verbosity > 1:
         print(addstatus)
      Result.status = Result.status + '\n' + addstatus

#####################################################################################

      if verbosity > 1:
        print("\nlooping over Intervals to generate PR points by flipping heuristic")
      Result.morePR = []
      for interval in PRlist:
         lapsedTime = time.time() - STARTTIME
         if lapsedTime > MaxTime:
            addstatus = '** lapsed time = ' + str(lapsedTime) + ' > max time = ' + str(MaxTime)
            if verbosity > 0: print(addstatus)
            Result.status = Result.status + '\n' + addstatus
            break

         i = interval[0] # = PR point index
         b = interval[1] # = target probability to reach by flipping from upper endpoint
         bU = PRoptimal[i][1]   # = upper endpoint
         bL = PRoptimal[i-1][1] # = lower endpoint
         if verbosity > 1:
            print( "target probability = "+str(b)+" < bU = PRoptimal[" + str(i) + "][1]" \
                 " and > bL = PRoptimal["+str(i-1)+"][1]")
         if b < bL or b > bU:
            addstatus = '** probability = '+str(b) + ', not in gap interval: (' \
                + str(bL) + ', ' + str(bU) + ')'
            print(addstatus)
            print(str(PRoptimal))
            print(str(PRlist))
            Result.status = Result.status + '\n' + addstatus
            return Result

         if verbosity > 1:
            print( "i = "+str(i)+" : Starting with bU = "+str(bU)+" having "+ \
                str(len(OptimalSelections[i]))+ " selections:")
            print(str(OptimalSelections[i]))

# first fix all scenarios = 0
         for sname, sprob in ScenarioList:
            scenario = ph._scenario_tree.get_scenario(sname)
            lagrUtil.FixIndicatorVariableOneScenario(ph,
                                                     scenario,
                                                     IndVarName,
                                                     0)

# now fix optimal selections = 1
         for sname in OptimalSelections[i]:
            scenario = ph._scenario_tree.get_scenario(sname)
            lagrUtil.FixIndicatorVariableOneScenario(ph,
                                                     scenario,
                                                     IndVarName,
                                                     1)

# flip scenario selections from bU until we reach b (target probability)
         bNew = bU
         for sname, sprob in ScenarioList:
            scenario = ph._scenario_tree.get_scenario(sname)
            if bNew - sprob < b:
               continue
            instance = ph._instances[sname]
            if getattr(instance, IndVarName).value == 0:
               continue
            bNew = bNew - sprob
            # flipped scenario selection
            lagrUtil.FixIndicatorVariableOneScenario(ph,
                                                     scenario,
                                                     IndVarName,
                                                     0)
            if verbosity > 1:
               print("\tflipped "+sname+" with prob = "+str(sprob)+" ...bNew = "+str(bNew))

         if verbosity > 1:
            print("\tflipped selections reach "+str(bNew)+" >= target = "+str(b)+" (bL = "+str(bL)+")")
         if bNew <= bL + betaTol or bNew >= bU - betaTol:
            if verbosity > 0:
               print("\tNot generating PR point...flipping from bU failed")
            continue # to next interval in list

 # ready to solve to get cost for fixed scenario selections associated with probability = bNew

         if verbosity > 1:
# check that scenarios are fixed as they should be
            totalprob = 0.
            for scenario in ScenarioList:
               sname = scenario[0]
               sprob = scenario[1]
               instance = ph._instances[sname]
               print("fix "+sname+" = "+str(getattr(instance,IndVarName).value)+\
                  " is "+str(getattr(instance,IndVarName).fixed)+" probability = "+str(sprob))
               if getattr(instance,IndVarName).value == 1:
                  totalprob = totalprob + sprob
               lambdaval = getattr(instance, multName).value
            print("\ttotal probability = %f" % totalprob)

# solve (all delta fixed); lambda=0, so z = Lagrangian
         if verbosity > 0:
            print("solve begins %s" % datetime_string())
            print("\t- lambda = %f" % lambdaval)
         SolStat, z = lagrUtil.solve_ph_code(ph, options)
         b = Compute_ExpectationforVariable(ph, IndVarName, CCStageNum)
         if verbosity > 0:
            print("solve ends %s" % datetime_string())
            print("\t- SolStat = %s" % str(SolStat))
            print("\t- b = %s" % str(b))
            print("\t- z = %s" % str(z))
            print("(adding to more PR points)")

         Result.morePR.append([None,b,z])
         if verbosity > 1:
            PrintPRpoints(Result.morePR)
      ######################################################
      # end loop over target probabilities

      with open(csvPrefix+"PRmore.csv",'w') as outFile:
         for point in Result.morePR:
            outFile.write(str(point[1])+','+str(point[2]))

      addstatus = str(len(Result.morePR)) + ' PR points written to file: '+ csvPrefix + 'PRmore.csv'
      if verbosity > 0: print(addstatus)
      Result.status = Result.status + '\n' + addstatus
      addstatus = 'lapsed time = ' + putcommas(time.time() - STARTTIME)
      if verbosity > 0: print(addstatus)
      Result.status = Result.status + '\n' + addstatus

      return Result
Example #17
0
    def APH_main(self, spcomm=None, finalize=True):
        """Execute the APH algorithm.
        Args:
            spcomm (SPCommunitator object): for intra or inter communications
            finalize (bool, optional, default=True):
                        If True, call self.post_loops(), if False, do not,
                        and return None for Eobj

        Returns:
            conv, Eobj, trivial_bound: 
                        The first two CANNOT BE EASILY INTERPRETED. 
                        Eobj is the expected,  weighted objective with 
                        proximal term. It is not directly useful.
                        The trivial bound is computed after iter 0
        NOTE:
            You need an xhat finder either in denoument or in an extension.
        """
        # Prep needs to be before iter 0 for bundling
        # (It could be split up)
        self.PH_Prep(attach_duals=False, attach_prox=False)

        # Begin APH-specific Prep
        for sname, scenario in self.local_scenarios.items():
            # ys is plural of y
            scenario._ys = pyo.Param(scenario._nonant_indexes.keys(),
                                     initialize=0.0,
                                     mutable=True)
            scenario._ybars = pyo.Param(scenario._nonant_indexes.keys(),
                                        initialize=0.0,
                                        mutable=True)
            scenario._zs = pyo.Param(scenario._nonant_indexes.keys(),
                                     initialize=0.0,
                                     mutable=True)
            # lag: we will support lagging back only to the last solve
            # IMPORTANT: pyomo does not support a second reference so no:
            # scenario._zs_foropt = scenario._zs

            if self.use_lag:
                scenario._zs_foropt = pyo.Param(
                    scenario._nonant_indexes.keys(),
                    initialize=0.0,
                    mutable=True)
                scenario._Ws_foropt = pyo.Param(
                    scenario._nonant_indexes.keys(),
                    initialize=0.0,
                    mutable=True)

            objfct = find_active_objective(scenario, True)

            if self.use_lag:
                for (ndn, i), xvar in scenario._nonant_indexes.items():
                    # proximal term
                    objfct.expr +=  scenario._PHprox_on[(ndn,i)] * \
                        (scenario._PHrho[(ndn,i)] /2.0) * \
                        (xvar - scenario._zs_foropt[(ndn,i)]) * \
                        (xvar - scenario._zs_foropt[(ndn,i)])
                    # W term
                    scenario._PHW_on[ndn, i] * scenario._Ws_foropt[ndn,
                                                                   i] * xvar
            else:
                for (ndn, i), xvar in scenario._nonant_indexes.items():
                    # proximal term
                    objfct.expr +=  scenario._PHprox_on[(ndn,i)] * \
                        (scenario._PHrho[(ndn,i)] /2.0) * \
                        (xvar - scenario._zs[(ndn,i)]) * \
                        (xvar - scenario._zs[(ndn,i)])
                    # W term
                    scenario._PHW_on[ndn, i] * scenario._Ws[ndn, i] * xvar

        # End APH-specific Prep

        self.subproblem_creation(self.PHoptions["verbose"])

        trivial_bound = self.Iter0()

        self.setup_Lens()
        self.setup_dispatchrecord()

        sleep_secs = self.PHoptions["async_sleep_secs"]

        lkwargs = None  # nothing beyond synchro
        listener_gigs = {
            "FirstReduce": (self.listener_side_gig, lkwargs),
            "SecondReduce": None
        }
        self.synchronizer = listener_util.Synchronizer(
            comms=self.comms,
            Lens=self.Lens,
            work_fct=self.APH_iterk,
            rank=self.rank,
            sleep_secs=sleep_secs,
            asynch=True,
            listener_gigs=listener_gigs)
        args = [spcomm] if spcomm is not None else [fullcomm]
        kwargs = None  # {"PH_extensions": PH_extensions}
        self.synchronizer.run(args, kwargs)

        if finalize:
            Eobj = self.post_loops()
        else:
            Eobj = None

        print(f"Debug: here's the dispatch record for rank={self.rank_global}")
        for k, v in self.dispatchrecord.items():
            print(k, v)
            print()
        print("End dispatch record")

        return self.conv, Eobj, trivial_bound
Example #18
0
 def _compute_objective_term(self):
     total = 0.0
     for scenario in self._ph._scenario_tree._scenarios:
         instance = self._ph._instances[scenario._name]
         total += -scenario._probability*value(find_active_objective(instance)) 
     return total
Example #19
0
   def LagrangeParametric(args=None):
      class Object(object): pass
      Result = Object()
      Result.status = 'LagrangeParam begins '+ datetime_string() + '...running new ph'
      ph = None

      blanks = "                          "  # used for formatting print statements
# options used
      betaMin       = options.beta_min
      betaMax       = options.beta_max
      betaTol       = options.beta_tol
      gapTol        = options.Lagrange_gap
      minProb       = options.min_prob
      maxIntervals  = options.max_intervals
      maxTime       = options.max_time
      IndVarName    = options.indicator_var_name
      multName      = options.lambda_parm_name
      CCStageNum    = options.stage_num
      csvPrefix     = options.csvPrefix
      verbosity     = options.verbosity
      verbosity = 2 # override for debug (= 3 to get super-debug)
      HGdebug = 0   # special debug (not public)
# local...may become option
      optTol = gapTol
####################################################################
      STARTTIME = time.time()

      Result.status = "options set"
      if verbosity > 1:
        print("From LagrangeParametric, status = %s\tSTARTTIME = %s" \
                % (str(getattr(Result,'status')), str(STARTTIME)))

      ph = PHFromScratch(options)
      Result.ph = ph
      rootnode = ph._scenario_tree._stages[0]._tree_nodes[0]   # use rootnode to loop over scenarios
      ReferenceInstance = ph._instances[rootnode._scenarios[0]._name]  # arbitrary scenario

      if find_active_objective(ph._scenario_tree._scenarios[0]._instance,safety_checks=True).is_minimizing():
         sense = 'min'
      else:
         sense = 'max'

      scenario_count = len(full_scenario_tree._stages[-1]._tree_nodes)
      if options.verbosity > 0: print("%s %s scenarios" % (str(sense),str(scenario_count)))

# initialize
      Result.status = 'starting at '+datetime_string()
      if verbosity > 0:
         print(Result.status)
      ScenarioList = []
      lambdaval = 0.
      lagrUtil.Set_ParmValue(ph, multName,lambdaval)

      # IMPORTANT: Preprocess the scenario instances
      #            before fixing variables, otherwise they
      #            will be preprocessed out of the expressions
      #            and the output_fixed_variable_bounds option
      #            will have no effect when we update the
      #            fixed variable values (and then assume we
      #            do not need to preprocess again because
      #            of this option).
      ph._preprocess_scenario_instances()

      sumprob = 0.
      minprob = 1.
      maxprob = 0.
      # fixed = 0 to get PR point at b=0
      lagrUtil.FixAllIndicatorVariables(ph, IndVarName, 0)
      for scenario in rootnode._scenarios:
         instance = ph._instances[scenario._name]
         sname = scenario._name
         sprob = scenario._probability
         sumprob = sumprob + sprob
         minprob = min(minprob,sprob)
         maxprob = max(maxprob,sprob)
         ScenarioList.append([sname,sprob])

      ScenarioList.sort(key=operator.itemgetter(1))   # sorts from min to max probability
      if verbosity > 0:
         print("probabilities sum to %f range: %f to %f" % (sumprob,minprob,maxprob))
      Result.ScenarioList = ScenarioList

# Write ScenarioList = name, probability in csv file sorted by probability
      outName = csvPrefix + 'ScenarioList.csv'
      print("writing to %s" % outName)
      with open(outName,'w') as outFile:
         for scenario in ScenarioList:
            outFile.write(scenario[0]+", "+str(scenario[1])+'\n')
      Result.ScenarioList = ScenarioList

      addstatus = 'Scenario List written to ' + csvPrefix+'ScenarioList.csv'
      Result.status = Result.status + '\n' + addstatus
      if verbosity > 0:
         print(addstatus)

      if verbosity > 0:
         print("solve begins %s" % datetime_string())
         print("\t- lambda = %f" % lambdaval)
      SolStat, zL = lagrUtil.solve_ph_code(ph, options)
      if verbosity > 0:
         print("solve ends %s" % datetime_string())
         print("\t- status = %s" % str(SolStat))
         print("\t- zL = %s" % str(zL))

      bL = Compute_ExpectationforVariable(ph, IndVarName, CCStageNum)
      if bL > 0:
         print("** bL = %s > 0 (all %s = 0)" % (str(bL), str(IndVarName)))
         return Result

      if verbosity > 0:  print("Initial optimal obj = %s for bL = %s" % (str(zL), str(bL)))

      # fixed = 1 to get PR point at b=1
      lagrUtil.FixAllIndicatorVariables(ph, IndVarName, 1)

      if verbosity > 0:
        print("solve begins %s" % datetime_string())
        print("\t- lambda = %s" % str(lambdaval))
      SolStat, zU = lagrUtil.solve_ph_code(ph, options)
      if verbosity > 0:
        print("solve ends %s" % datetime_string())
        print("\t- status = %s" % str(SolStat))
        print("\t- zU = %s" % str(zU))
      if not SolStat[0:2] == 'ok':
         print(str(SolStat[0:3])+" is not 'ok'")
         addstatus = "** Solution is non-optimal...aborting"
         print(addstatus)
         Result.status = Result.status + "\n" + addstatus
         return Result

      bU = Compute_ExpectationforVariable(ph, IndVarName, CCStageNum)
      if bU < 1.- betaTol and verbosity > 0:
         print("** Warning:  bU = %s  < 1" % str(bU))

### enumerate points in PR space (all but one scenario)
#      Result.lbz = [ [0,bL,zL], [None,bU,zU] ]
#      for scenario in rootnode._scenarios:
#         sname = scenario._name
#         instance = ph._instances[sname]
#         print "excluding scenario",sname
#         getattr(instance,IndVarName).value = 0
#         print sname,"value =",getattr(instance,IndVarName).value,getattr(instance,IndVarName).fixed
#         SolStat, z = lagrUtil.solve_ph_code(ph, options)
#         b = Compute_ExpectationforVariable(ph, IndVarName, CCStageNum)
#         print "solve ends with status =",SolStat,"(b, z) =",b,z
#         getattr(instance,IndVarName).value = 1
#         Result.lbz.append([None,b,z])
#         for t in instance.TimePeriods:
#           print "Global at",t,"=",instance.posGlobalLoadGenerateMismatch[t].value, \
#                '-',instance.negGlobalLoadGenerateMismatch[t].value,"=",\
#                    instance.GlobalLoadGenerateMismatch[t].value,\
#               "\tDemand =",instance.TotalDemand[t].value, ",",\
#                "Reserve =",instance.ReserveRequirement[t].value
#
#      PrintPRpoints(Result.lbz)
#      return Result
#### end enumeration
########################################################################

      if verbosity > 1:
         print("We have bU = %s ...about to free all %s for %d scenarios" % \
                (str(bU), str(IndVarName), len(ScenarioList)))

      # free scenario selection variable
      lagrUtil.FreeAllIndicatorVariables(ph, IndVarName)

      if verbosity > 1:
         print("\tall %s freed; elapsed time = %f" % (str(IndVarName), time.time() - STARTTIME))

# initialize with the two endpoints
      Result.lbz = [ [0.,bL,zL], [None,bU,zU] ]
      Result.selections = [[], ScenarioList]
      NumIntervals = 1
      if verbosity > 0:
         print("Initial relative Lagrangian gap = %f maxIntervals = %d" % (1-zL/zU, maxIntervals))
         if verbosity > 1:
            print("entering while loop %s" % datetime_string())
         print("\n")

############ main loop to search intervals #############
########################################################
      while NumIntervals < maxIntervals:
         lapsedTime = time.time() - STARTTIME
         if lapsedTime > maxTime:
            addstatus = '** max time reached ' + str(lapsedTime)
            print(addstatus)
            Result.status = Result.status + '\n' + addstatus
            break
         if verbosity > 1:
            print("Top of while with %d intervals elapsed time = %f" % (NumIntervals, lapsedTime))
            PrintPRpoints(Result.lbz)

         lambdaval = None
### loop over PR points to find first unfathomed interval to search ###
         for PRpoint in range(1,len(Result.lbz)):
            if Result.lbz[PRpoint][0] == None:
# multiplier = None means interval with upper endpoint at PRpoint not fathomed
               bL = Result.lbz[PRpoint-1][1]
               zL = Result.lbz[PRpoint-1][2]
               bU = Result.lbz[PRpoint][1]
               zU = Result.lbz[PRpoint][2]
               lambdaval = (zU - zL) / (bU - bL)
               break

#############################
# Exited from the for loop
         if verbosity > 1:
            print("exited for loop with PRpoint = %s ...lambdaval = %s" % (PRpoint, lambdaval))
         if lambdaval == None: break # all intervals are fathomed

         if verbosity > 1: PrintPRpoints(Result.lbz)
         if verbosity > 0:
            print("Searching for b in [%s, %s] with %s = %f" % (str(round(bL,4)), str(round(bU,4)), multName, lambdaval))

# search interval (bL,bU)
         lagrUtil.Set_ParmValue(ph, multName,lambdaval)
         if verbosity > 0:
            print("solve begins %s" % datetime_string())
            print("\t- %s = %f" % (multName, lambdaval))

         #########################################################
         SolStat, Lagrangian = lagrUtil.solve_ph_code(ph, options)
         #########################################################
         if not SolStat[0:2] == 'ok':
            addstatus = "** Solution status " + SolStat + " is not optimal"
            print(addstatus)
            Result.status = Result.status + "\n" + addstatus
            return Result

         b = Compute_ExpectationforVariable(ph, IndVarName, CCStageNum)
         z = Lagrangian + lambdaval*b
         if verbosity > 0:
            print("solve ends %s" % datetime_string())
            print("\t- Lagrangian = %f" % Lagrangian)
            print("\t- b = %s" % str(b))
            print("\t- z = %s" % str(z))
            print("\n")

# We have PR point (b,z), which may be new or one of the endpoints
##################################################################

######### Begin tolerance tests ##########
# Test that b is in [bL,bU]
         if verbosity > 1: print("\ttesting b")
         if b < bL - betaTol or b > bU + betaTol:
            addstatus = "** fatal error: probability (= " + str(b) + \
                ") is outside interval, (" + str(bL) + ", " + str(bU) + ")"
            addstatus = addstatus + "\n\t(tolerance = " + str(betaTol) + ")"
            print(addstatus+'\n')
            Result.status = Result.status + addstatus
            return Result
# Test that z is in [zL,zU]
         if verbosity > 1: print("\ttesting z")
# using optTol as absolute tolerance (not relative)
#   ...if we reconsider, need to allow negative z-values
         if z < zL - optTol or z > zU + optTol:
            addstatus = "** fatal error: obj (= " + str(z) + \
                ") is outside interval, (" + str(zL) + ", " + str(zU) + ")"
            print(addstatus+'\n')
            Result.status = Result.status + addstatus
            return Result

# Ok, we have (b,z) in [(bL,zL), (bU,zU)], at least within tolerances

         oldLagrangian = zL - lambdaval*bL
# ensure lambdaval set such that endpoints have same Lagrangian value
# (this is probably unnecessary, but check anyway)
         if abs(oldLagrangian - (zU - lambdaval*bU)) > optTol*abs(oldLagrangian):
            addstatus = "** fatal error: Lagrangian at (bL,zL) = " + \
                str(oldLagrangian) + " not= " + str(zU-lambdaval*bU) + \
                "\n\t(optTol = " + str(optTol) + ")"
            Result.status = Result.status + addstatus
            return Result

# no more fatal error tests...need to know if (b,z) is endpoint or new

         if verbosity > 1: print("No anomalies...testing if b = bL or bU")

# Test if endpoint is an alternative optimum of Lagrangian
# ...using optTol as *relative* tolerance
# (could use other reference values -- eg, avg or max of old and new Lagrangian values)
         refValue =  max( min( abs(oldLagrangian), abs(Lagrangian) ), 1.)
         alternativeOpt = abs( oldLagrangian - Lagrangian ) <= optTol*refValue

# alternativeOpt = True means we computed point (b,z) is alternative optimum such that:
#   case 1: (b,z) = endpoint, in which case we simply fathom [bL,bU] by setting PRpoint
#            to [lambdaval,bU,zU] (the numeric value of multiplier means fathomed)
#   case 2: (b,z) is new PR point on line segment, in which case we split into
#           [bL,b] and [b,bU], with both fathomed

         if verbosity > 1:
            print("oldLagrangian = %s" % str(oldLagrangian))
            if alternativeOpt: print(":= Lagrangian = %s" % str(Lagrangian ))
            else: print("> Lagrangian = %s" % str(Lagrangian))

         if alternativeOpt:
# setting multiplier of (bU,zU) to a numeric fathoms the interval [bL,bU]
            Result.lbz[PRpoint][0] = lambdaval

# test if (b,z) is an endpoint
         newPRpoint = abs(b-bL) > betaTol and abs(b-bU) > betaTol
         if not newPRpoint:
# ...(b,z) is NOT an endpoint (or sufficiently close), so split and fathom
            if verbosity > 1:
               print("\tnot an endpoint\tlbz = %s" % str(Result.lbz[PRpoint]))
            if verbosity > 0:
               print("Lagangian solution is new PR point on line segment of (" \
                  + str(bL) + ", " + str(bU) +")")
               print("\tsplitting (bL,bU) into (bL,b) and (b,bU), both fathomed")
# note:  else ==> b = bL or bU, so we do nothing, having already fathomed [bL,bU]

# (b,z) is new PR point, so split interval (still in while loop)
##########################################
# alternative optimum ==> split & fathom: (bL,b), (b,bU)
         if verbosity > 1:
            print("\talternativeOpt %s newPRpoint = %s" % (alternativeOpt, newPRpoint))
         if newPRpoint:
            NumIntervals += 1
            if alternativeOpt:
               if verbosity > 1: print("\tInsert [lambdaval,b,z] at %f" % PRpoint)
               Result.lbz = Insert([lambdaval,b,z],PRpoint,Result.lbz)
               addstatus = "Added PR point on line segment of envelope"
               if verbosity > 0: print(addstatus+'\n')
            else:
               if verbosity > 1: print("\tInsert [None,b,z] at %f" % PRpoint)
               Result.lbz = Insert([None,b,z],PRpoint,Result.lbz)
               addstatus = "new envelope extreme point added (interval split, not fathomed)"
            Result.status = Result.status + "\n" + addstatus

            if verbosity > 1:
               print("...after insertion:")
               PrintPRpoints(Result.lbz)

# get the selections of new point (ie, scenarios for which delta=1)
            Selections = []
            for scenario in ScenarioList:
               instance = ph._instances[scenario[0]]
               if getattr(instance,IndVarName).value == 1:
                  Selections.append(scenario)
            Result.selections = Insert(Selections,PRpoint,Result.selections)

            if verbosity > 0:
               print("Interval "+str(PRpoint)+", ["+str(bL)+", "+str(bU)+ \
                 "] split at ("+str(b)+", "+str(z)+")")
               print("\tnew PR point has "+str(len(Selections))+" selections")

            if verbosity > 1: print("test that selections list aligned with lbz")
            if not len(Result.lbz) == len(Result.selections):
               print("** fatal error: lbz not= selections")
               PrintPRpoints(Result.lbz)
               print("Result.selections:")
               for i in range(Result.selections): print("%d %f" % (i,Result.selections[i]))
               return Result

# ok, we have split and/or fathomed interval
         if NumIntervals >= maxIntervals:
# we are about to leave while loop due to...
            addstatus = "** terminating because number of intervals = " + \
                    str(NumIntervals) + " >= max = " + str(maxIntervals)
            if verbosity > 0: print(addstatus+'\n')
            Result.status = Result.status + "\n" + addstatus

# while loop continues
         if verbosity > 1:
            print("bottom of while loop")
            PrintPRpoints(Result.lbz)

###################################################
# end while NumIntervals < maxIntervals:
#     ^ this is indentation of while loop
################ end while loop ###################

      if verbosity > 1:  print("\nend while loop...setting multipliers")
      for i in range(1,len(Result.lbz)):
         db = Result.lbz[i][1] - Result.lbz[i-1][1]
         dz = Result.lbz[i][2] - Result.lbz[i-1][2]
         if dz > 0:
            Result.lbz[i][0] = dz/db
         else:
            #print "dz =",dz," at ",i,": ",Result.lbz[i]," -",Result.lbz[i-1]
            Result.lbz[i][0] = 0
      if verbosity > 0: PrintPRpoints(Result.lbz)

      addstatus = '\nLagrange multiplier search ends'+datetime_string()
      if verbosity > 0:
         print(addstatus+'\n')
      Result.status = Result.status + addstatus

      outName = csvPrefix + "PRoptimal.csv"
      with open(outName,'w') as outFile:
         if verbosity > 0:
            print("writing PR points to "+outName+'\n')
         for lbz in Result.lbz:
            outFile.write(str(lbz[1])+ ", " +str(lbz[2])+'\n')

      outName = csvPrefix + "OptimalSelections.csv"
      with open(outName,'w') as outFile:
         if verbosity > 0:
            print("writing optimal selections for each PR point to "+csvPrefix+'PRoptimal.csv\n')
         for selections in Result.selections:
            char = ""
            thisSelection = ""
            for slist in selections:
               if slist:
                  thisSelection = thisSelection + char + slist[0]
                  char = ","
            outFile.write(thisSelection+'\n')

      if verbosity > 0:
         print("\nReturning status:\n %s \n=======================" % Result.status)

################################
      if verbosity > 2:
         print("\nAbout to return...Result attributes: %d" % len(inspect.getmembers(Result)))
         for attr in inspect.getmembers(Result): print(attr[0])
         print("\n===========================================")
# LagrangeParametric ends here
      return Result
Example #20
0
File: ef.py Project: CanLi1/pyomo-1
    def solve(self,
              check_status=True,
              exception_on_failure=True,
              output_solver_log=False,
              symbolic_solver_labels=False,
              keep_solver_files=False,
              io_options=None):
        # TODO: Does this import need to be delayed because
        #       it is in a plugins subdirectory
        from pyomo.solvers.plugins.solvers.persistent_solver import \
            PersistentSolver

        if self.instance is None:
            raise RuntimeError(
                "The extensive form instance has not been constructed."
                "Call the build_ef() method to construct it.")

        start_time = time.time()
        if self.get_option("verbose"):
            print("Queuing extensive form solve")

        self.objective = None
        self.gap = None
        self.bound = None
        self.termination_condition = None
        self.termination_message = None
        self.solver_status = None
        self.solution_status = None
        self.solver_results = None
        self.time = None
        self.pyomo_time = None

        if isinstance(self._solver, PersistentSolver):
            self._solver.compile_instance(
                self.instance, symbolic_solver_labels=symbolic_solver_labels)

        solve_kwds = {}
        solve_kwds['load_solutions'] = False
        if keep_solver_files:
            solve_kwds['keepfiles'] = True
        if symbolic_solver_labels:
            solve_kwds['symbolic_solver_labels'] = True
        if output_solver_log:
            solve_kwds['tee'] = True

        solver_options = self.get_option("solver_options")
        if len(solver_options) > 0:
            if type(solver_options) is tuple:
                solve_kwds["options"] = {}
                for name_val in solver_options:
                    assert "=" in name_val
                    name, val = name_val.split("=")
                    solve_kwds["options"][name.strip()] = val.strip()
            else:
                solve_kwds["options"] = solver_options

        if io_options is not None:
            solve_kwds.update(io_options)

        self.objective_sense = \
            find_active_objective(self.instance).sense

        if (not self.get_option("disable_warmstart")) and \
           (self._solver.warm_start_capable()):
            action_handle = self._solver_manager.queue(self.instance,
                                                       opt=self._solver,
                                                       warmstart=True,
                                                       **solve_kwds)
        else:
            action_handle = self._solver_manager.queue(self.instance,
                                                       opt=self._solver,
                                                       **solve_kwds)

        if self.get_option("verbose"):
            print("Waiting for extensive form solve")
        results = self._solver_manager.wait_for(action_handle)

        if self.get_option("verbose"):
            print("Done with extensive form solve - loading results")

        if self.get_option("output_solver_results"):
            print("Results for ef:")
            results.write(num=1)

        self.solver_results = results
        if hasattr(results.solver,"user_time") and \
           (not isinstance(results.solver.user_time,
                           UndefinedData)) and \
           (results.solver.user_time is not None):
            # the solve time might be a string, or might
            # not be - we eventually would like more
            # consistency on this front from the solver
            # plugins.
            self.time = \
                float(results.solver.user_time)
        elif hasattr(results.solver, "time"):
            self.time = \
                float(results.solver.time)
        else:
            self.time = None

        if hasattr(results, "pyomo_solve_time"):
            self.pyomo_time = \
                results.pyomo_solve_time
        else:
            self.pyomo_time = None

        self.termination_condition = \
            results.solver.termination_condition
        self.termination_message = None
        if hasattr(results.solver, "termination_message"):
            self.termination_message = results.solver.termination_message
        elif hasattr(results.solver, "message"):
            self.termination_message = results.solver.message
        self.solver_status = \
            results.solver.status

        if len(results.solution) > 0:
            assert len(results.solution) == 1

            results_sm = results._smap
            self.instance.solutions.load_from(results)

            solution0 = results.solution(0)
            if hasattr(solution0, "gap") and \
               (solution0.gap is not None) and \
               (not isinstance(solution0.gap,
                               UndefinedData)):
                self.gap = float(solution0.gap)
            else:
                self.gap = None

            self.solution_status = solution0.status

            if self.get_option("verbose"):
                print("Storing solution in scenario tree")

            for scenario in self._manager.scenario_tree.scenarios:
                scenario.update_solution_from_instance()
            self._manager.scenario_tree.snapshotSolutionFromScenarios()
            self.objective = self._manager.scenario_tree.\
                             findRootNode().\
                             computeExpectedNodeCost()
            if self.gap is not None:
                if self.objective_sense == pyomo.core.base.minimize:
                    self.bound = self.objective - self.gap
                else:
                    self.bound = self.objective + self.gap

        else:

            self.objective = None
            self.gap = None
            self.bound = None
            self.solution_status = None

        failure = False

        if check_status:
            if not ((self.solution_status == SolutionStatus.optimal) or \
                    (self.solution_status == SolutionStatus.feasible)):
                failure = True
                if self.get_option("verbose") or \
                   exception_on_failure:
                    msg = ("EF solve failed solution status check:\n"
                           "Solver Status: %s\n"
                           "Termination Condition: %s\n"
                           "Solution Status: %s\n" %
                           (self.solver_status, self.termination_condition,
                            self.solution_status))
                    if self.get_option("verbose"):
                        print(msg)
                    if exception_on_failure:
                        raise RuntimeError(msg)
        else:
            if self.get_option("verbose"):
                print("EF solve completed. Skipping status check.")

        if self.get_option("verbose") or self.get_option("output_times"):
            print("Time to solve and load results for the "
                  "extensive form=%.2f seconds" % (time.time() - start_time))

        return failure