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
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
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
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()
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")
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()
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
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
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
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
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
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
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
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
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
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
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
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
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