def _apply_solver(self): start_time = time.time() # # Transform instance # xfrm = TransformationFactory('mpec.simple_nonlinear') xfrm.apply_to(self._instance) # # Solve with a specified solver # solver = self.options.solver if not self.options.solver: #pragma:nocover self.options.solver = solver = 'ipopt' # use the with block here so that deactivation of the # solver plugin always occurs thereby avoiding memory # leaks caused by plugins! with pyomo.opt.SolverFactory(solver) as opt: self.results = [] epsilon_final = self.options.get('epsilon_final', 1e-7) epsilon = self.options.get('epsilon_initial', epsilon_final) while (True): self._instance.mpec_bound.value = epsilon # # **NOTE: It would be better to override _presolve on the # base class of this solver as you might be # missing a number of keywords that were passed # into the solve method (e.g., none of the # io_options are getting relayed to the subsolver # here). # res = opt.solve(self._instance, tee=self._tee, timelimit=self._timelimit) self.results.append(res) epsilon /= 10.0 if epsilon < epsilon_final: break # # Reclassify the Complementarity components # from pyomo.mpec import Complementarity for cuid in self._instance._transformation_data['mpec.simple_nonlinear'].compl_cuids: cobj = cuid.find_component(self._instance) cobj.parent_block().reclassify_component_type(cobj, Complementarity) # # Update timing # stop_time = time.time() self.wall_time = stop_time - start_time # # Return the sub-solver return condition value and log # return pyutilib.misc.Bunch(rc=getattr(opt,'_rc', None), log=getattr(opt,'_log',None))
def _apply_solver(self): start_time = time.time() # # Transform instance # xfrm = TransformationFactory('mpec.simple_disjunction') xfrm.apply_to(self._instance) xfrm = TransformationFactory('gdp.bigm') xfrm.apply_to(self._instance, default_bigM=self.options.get('bigM',10**6)) # # Solve with a specified solver # solver = self.options.solver if not self.options.solver: #pragma:nocover self.options.solver = solver = 'glpk' # use the with block here so that deactivation of the # solver plugin always occurs thereby avoiding memory # leaks caused by plugins! with pyomo.opt.SolverFactory(solver) as opt: # # **NOTE: It would be better to override _presolve on the # base class of this solver as you might be # missing a number of keywords that were passed # into the solve method (e.g., none of the # io_options are getting relayed to the subsolver # here). # self.results = opt.solve(self._instance, tee=self._tee, timelimit=self._timelimit) # # Reclassify the Complementarity components # from pyomo.mpec import Complementarity for cuid in self._instance._transformation_data['mpec.simple_disjunction'].compl_cuids: cobj = cuid.find_component(self._instance) cobj.parent_block().reclassify_component_type(cobj, Complementarity) # # Transform the result back into the original model # ##self._instance.solutions.load_from(self.results, ignore_invalid_labels=True) # # Update timing # stop_time = time.time() self.wall_time = stop_time - start_time # # Return the sub-solver return condition value and log # return pyutilib.misc.Bunch(rc=getattr(opt,'_rc', None), log=getattr(opt,'_log',None))
def _apply_solver(self): start_time = time.time() # # Transform the instance # xfrm = TransformationFactory('bilevel.linear_mpec') xfrm.apply_to(self._instance) xfrm = TransformationFactory('mpec.simple_nonlinear') xfrm.apply_to(self._instance, mpec_bound=self.options.get('mpec_bound',1e-7)) # # Solve with a specified solver # solver = self.options.solver if not self.options.solver: solver = 'glpk' # use the with block here so that deactivation of the # solver plugin always occurs thereby avoiding memory # leaks caused by plugins! with pyomo.opt.SolverFactory(solver) as opt: # self.results = [] # # **NOTE: It would be better to override _presolve on the # base class of this solver as you might be # missing a number of keywords that were passed # into the solve method (e.g., none of the # io_options are getting relayed to the subsolver # here). # self.results.append(opt.solve(self._instance, tee=self._tee, timelimit=self._timelimit)) # # Load the result back into the original model # ##self._instance.load(self.results[0], ignore_invalid_labels=True) # stop_time = time.time() self.wall_time = stop_time - start_time # # Deactivate the block that contains the optimality conditions, # and reactivate SubModel # submodel = self._instance._transformation_data['bilevel.linear_mpec'].submodel_cuid.find_component(self._instance) for (name, data) in submodel.component_map(active=False).items(): if not isinstance(data,Var) and not isinstance(data,Set): data.activate() # TODO: delete this subblock self._instance._transformation_data['bilevel.linear_mpec'].block_cuid.find_component(self._instance).deactivate() # # Return the sub-solver return condition value and log # return pyutilib.misc.Bunch(rc=getattr(opt,'_rc', None), log=getattr(opt,'_log',None))
def initialize_model(m,nfe): u_profile = {0:-0.06} m.u_input = Suffix(direction=Suffix.LOCAL) m.u_input[m.u]=u_profile sim = Simulator(m,package='scipy') tsim, profiles = sim.simulate(numpoints=100, varying_inputs=m.u_input) discretizer = TransformationFactory('dae.collocation') discretizer.apply_to(m, nfe=nfe, ncp=1, scheme='LAGRANGE-RADAU') sim.initialize_model()
def apply(self, **kwds): instance = kwds.pop('instance') # Not sure why the ModifyInstance callback started passing the # model along with the instance. We will ignore it. model = kwds.pop('model', None) xform = TransformationFactory('gdp.chull') return xform.apply_to(instance, **kwds)
def initialize_model(m,n_sim,n_nfe,n_ncp): vp_profile = {0:0.75} vt_profile = {0:0.75} m.u_input = Suffix(direction=Suffix.LOCAL) m.u_input[m.vp] = vp_profile m.u_input[m.vt] = vt_profile sim = Simulator(m, package='scipy') tsim, profiles = sim.simulate(numpoints=n_sim, varying_inputs=m.u_input) discretizer = TransformationFactory('dae.collocation') discretizer.apply_to(m,nfe=n_nfe,ncp=n_ncp,scheme='LAGRANGE-RADAU') sim.initialize_model()
def _apply_solver(self): start_time = time.time() # # Cache the instance # xfrm = TransformationFactory('bilevel.linear_mpec') xfrm.apply_to(self._instance) xfrm = TransformationFactory('mpec.simple_disjunction') xfrm.apply_to(self._instance) xfrm = TransformationFactory('gdp.bigm') xfrm.apply_to(self._instance, default_bigM=100000) # # Solve with a specified solver # solver = self.options.solver if not self.options.solver: solver = 'glpk' # use the with block here so that deactivation of the # solver plugin always occurs thereby avoiding memory # leaks caused by plugins! with pyomo.opt.SolverFactory(solver) as opt: # self.results = [] # # **NOTE: It would be better to override _presolve on the # base class of this solver as you might be # missing a number of keywords that were passed # into the solve method (e.g., none of the # io_options are getting relayed to the subsolver # here). # self.results.append(opt.solve(self._instance, tee=self._tee, timelimit=self._timelimit)) # stop_time = time.time() self.wall_time = stop_time - start_time # # Deactivate the block that contains the optimality conditions, # and reactivate SubModel # self._instance._transformation_data['bilevel.linear_mpec'].submodel_cuid.find_component(self._instance).activate() self._instance._transformation_data['bilevel.linear_mpec'].block_cuid.find_component(self._instance).deactivate() # # Return the sub-solver return condition value and log # return pyutilib.misc.Bunch(rc=getattr(opt,'_rc', None), log=getattr(opt,'_log',None))
def _apply_solver(self): start_time = time.time() if not self.options.bigM: self._bigM = 999 else: self._bigM = self.options.bigM # # Cache the instance # xfrm = TransformationFactory('bilevel.linear_mpec') xfrm.apply_to(self._instance) xfrm = TransformationFactory('mpec.simple_disjunction') xfrm.apply_to(self._instance) xfrm = TransformationFactory('gdp.bigm') xfrm.apply_to(self._instance, bigM=self.options.get('bigM',self._bigM)) # ##self._instance.pprint() xfrm = TransformationFactory('gdp.bilinear') xfrm.apply_to(self._instance) xfrm = TransformationFactory('gdp.bigm') #xfrm.apply_to(self._instance, bigM=self.options.get('bigM',self._bigM)) xfrm.apply_to(self._instance, bigM=8888) ##self._instance.pprint() # # Solve with a specified solver # solver = self.options.solver if not solver: solver = 'glpk' # use the with block here so that deactivation of the # solver plugin always occurs thereby avoiding memory # leaks caused by plugins! with pyomo.opt.SolverFactory(solver) as opt: # self.results = [] # # **NOTE: It would be better to override _presolve on the # base class of this solver as you might be # missing a number of keywords that were passed # into the solve method (e.g., none of the # io_options are getting relayed to the subsolver # here). # self.results.append(opt.solve(self._instance, tee=self._tee, timelimit=self._timelimit, symbolic_solver_labels=False, keepfiles=False )) # stop_time = time.time() self.wall_time = stop_time - start_time #self._instance.pprint() #self._instance.display() # # Deactivate the block that contains the optimality conditions, # and reactivate SubModel # submodel = self._instance._transformation_data['bilevel.linear_mpec'].submodel_cuid.find_component(self._instance) for (name, data) in submodel.component_map(active=False).items(): if not isinstance(data,Var) and not isinstance(data,Set): data.activate() # # TODO: delete this subblock # TODO: Remove bilinear and bigM blocks # self._instance._transformation_data['bilevel.linear_mpec'].block_cuid.find_component(self._instance).deactivate() # # Return the sub-solver return condition value and log # return Bunch(rc=getattr(opt,'_rc', None), log=getattr(opt,'_log',None))
def _setup_subproblems(self, instance, bigM): # create transformation block transBlockName, transBlock = self._add_relaxation_block( instance, '_pyomo_gdp_cuttingplane_relaxation') # We store a list of all vars so that we can efficiently # generate maps among the subproblems transBlock.all_vars = list(v for v in instance.component_data_objects( Var, descend_into=(Block, Disjunct), sort=SortComponents.deterministic) if not v.is_fixed()) # we'll store all the cuts we add together transBlock.cuts = Constraint(Any) # get bigM and hull relaxations bigMRelaxation = TransformationFactory('gdp.bigm') hullRelaxation = TransformationFactory('gdp.hull') relaxIntegrality = TransformationFactory('core.relax_integrality') # # Generalte the Hull relaxation (used for the separation # problem to generate cutting planes # instance_rHull = hullRelaxation.create_using(instance) # This relies on relaxIntegrality relaxing variables on deactivated # blocks, which should be fine. relaxIntegrality.apply_to(instance_rHull) # # Reformulate the instance using the BigM relaxation (this will # be the final instance returned to the user) # bigMRelaxation.apply_to(instance, bigM=bigM) # # Generate the continuous relaxation of the BigM transformation # instance_rBigM = relaxIntegrality.create_using(instance) # # Add the xstar parameter for the Hull problem # transBlock_rHull = instance_rHull.component(transBlockName) # # this will hold the solution to rbigm each time we solve it. We # add it to the transformation block so that we don't have to # worry about name conflicts. transBlock_rHull.xstar = Param(range(len(transBlock.all_vars)), mutable=True, default=None) transBlock_rBigM = instance_rBigM.component(transBlockName) # # Generate the mapping between the variables on all the # instances and the xstar parameter # var_info = tuple( (v, transBlock_rBigM.all_vars[i], transBlock_rHull.all_vars[i], transBlock_rHull.xstar[i]) for i, v in enumerate(transBlock.all_vars)) # # Add the separation objective to the hull subproblem # self._add_separation_objective(var_info, transBlock_rHull) return instance_rBigM, instance_rHull, var_info, transBlockName
def _apply_solver(self): start_time = time.time() # # Cache the instance # xfrm = TransformationFactory('pao.bilevel.linear_dual') xfrm.apply_to(self._instance, use_dual_objective=self.use_dual_objective) # # Verify whether the model is linear # nonlinear = False for odata in chain(self._instance.component_objects(Objective, active=True), \ self._instance.component_objects(Constraint, active=True, descend_into=True)): if type(odata) == IndexedConstraint: for _name, _odata in odata.items(): nonlinear = _odata.expr.polynomial_degree() != 1 if nonlinear: break else: nonlinear = odata.expr.polynomial_degree() != 1 if nonlinear: # Stop after the first occurrence in the objective or one of the constraints break # # Apply an additional transformation to remap bilinear terms # if nonlinear: gdp_xfrm = TransformationFactory("gdp.bilinear") gdp_xfrm.apply_to(self._instance) mip_xfrm = TransformationFactory("gdp.bigm") mip_xfrm.apply_to(self._instance, bigM=self.options.get('bigM', 10)) # # Solve with a specified solver # solver = self.options.solver if not self.options.solver: #pragma:nocover solver = 'glpk' # with pyomo.opt.SolverFactory(solver) as opt: self.results = [] # # #opt.options['mipgap'] = self.options.get('mipgap', 0.001) results = opt.solve(self._instance, tee=self._tee, timelimit=self._timelimit) self.results.append(results) if results.solver.termination_condition not in safe_termination_conditions: raise Exception( 'Problem encountered during solve, termination_condition {}' .format(results.solver.termination_condition)) # # If the problem was bilinear, then reactivate the original data # if nonlinear: i = 0 for v in self._instance.bilinear_data_.vlist.itervalues(): if abs(v.value) <= 1e-7: self._instance.bilinear_data_.vlist_boolean[i] = 0 else: self._instance.bilinear_data_.vlist_boolean[i] = 1 i = i + 1 # self._instance.bilinear_data_.deactivate() if self.resolve_subproblem: # # Transform the result back into the original model # tdata = self._instance._transformation_data[ 'pao.bilevel.linear_dual'] count = 0 for name_ in tdata.submodel: submodel = self._instance.find_component(name_) if submodel.active: count += 1 if count > 1: raise Exception( 'Problem encountered during solve, more than one subproblem provided.' ) unfixed_tdata = list() # Copy variable values and fix them for v in tdata.fixed: if not v.fixed: if v.is_binary(): v.value = round( self._instance.find_component(v).value) if v.is_integer(): v.value = round( self._instance.find_component(v).value) else: v.value = self._instance.find_component(v).value v.fixed = True unfixed_tdata.append(v) # Reclassify the SubModel components and resolve for name_ in tdata.submodel: submodel = self._instance.find_component(name_) submodel.activate() for data in submodel.component_map(active=False).values(): if not isinstance(data, Var) and not isinstance( data, Set): data.activate() _dual_name = name_ + '_dual' _parent = submodel.parent_block() if type(_parent) == _BlockData: _dual_name = _dual_name.replace(_parent.name + ".", "") dual_submodel = getattr(_parent, _dual_name) dual_submodel.deactivate() pyomo.common.PyomoAPIFactory( 'pyomo.repn.compute_standard_repn')({}, model=submodel) _submodel_name = name_.replace(_parent.name + ".", "") _parent.reclassify_component_type( _submodel_name, Block) else: dual_submodel = self._instance.find_component( _dual_name) dual_submodel.deactivate() pyomo.common.PyomoAPIFactory( 'pyomo.repn.compute_standard_repn')({}, model=submodel) self._instance.reclassify_component_type(name_, Block) # # Use the with block here so that deactivation of the # solver plugin always occurs thereby avoiding memory # leaks caused by plugins! # with pyomo.opt.SolverFactory(solver) as opt_inner: # # **NOTE: It would be better to override _presolve on the # base class of this solver as you might be # missing a number of keywords that were passed # into the solve method (e.g., none of the # io_options are getting relayed to the subsolver # here). # #opt_inner.options['mipgap'] = self.options.get('mipgap', 0.001) results = opt_inner.solve(self._instance, tee=self._tee, timelimit=self._timelimit) self.results.append(results) # Unfix variables for v in tdata.fixed: if v in unfixed_tdata: v.fixed = False # check that the solutions list is not empty if self._instance.solutions.solutions: self._instance.solutions.select(0, ignore_fixed_vars=True) # stop_time = time.time() self.wall_time = stop_time - start_time self.results_obj = self._setup_results_obj() # # Reactivate top level objective # and reclassify the submodel # for odata in self._instance.component_map(Objective).values(): odata.activate() # # Return the sub-solver return condition value and log # return pyutilib.misc.Bunch(rc=getattr(opt, '_rc', None), log=getattr(opt, '_log', None))
def _setup_subproblems(self, instance, bigM): # create transformation block transBlockName, transBlock = self._add_relaxation_block( instance, '_pyomo_gdp_cuttingplane_relaxation') # We store a list of all vars so that we can efficiently # generate maps among the subproblems transBlock.all_vars = list(v for v in instance.component_data_objects( Var, descend_into=(Block, Disjunct), sort=SortComponents.deterministic) if not v.is_fixed()) # we'll store all the cuts we add together transBlock.cuts = Constraint(Any) # get bigM and chull relaxations bigMRelaxation = TransformationFactory('gdp.bigm') chullRelaxation = TransformationFactory('gdp.chull') relaxIntegrality = TransformationFactory('core.relax_integrality') # HACK: for the current writers, we need to also apply gdp.reclassify so # that the indicator variables stay where they are in the big M model # (since that is what we are eventually going to solve after we add our # cuts). reclassify = TransformationFactory('gdp.reclassify') # # Generalte the CHull relaxation (used for the separation # problem to generate cutting planes # instance_rCHull = chullRelaxation.create_using(instance) # This relies on relaxIntegrality relaxing variables on deactivated # blocks, which should be fine. reclassify.apply_to(instance_rCHull) relaxIntegrality.apply_to(instance_rCHull) # # Reformulate the instance using the BigM relaxation (this will # be the final instance returned to the user) # bigMRelaxation.apply_to(instance, bigM=bigM) reclassify.apply_to(instance) # # Generate the continuous relaxation of the BigM transformation # instance_rBigM = relaxIntegrality.create_using(instance) # # Add the xstar parameter for the CHull problem # transBlock_rCHull = instance_rCHull.component(transBlockName) # # this will hold the solution to rbigm each time we solve it. We # add it to the transformation block so that we don't have to # worry about name conflicts. transBlock_rCHull.xstar = Param( range(len(transBlock.all_vars)), mutable=True, default=None) transBlock_rBigM = instance_rBigM.component(transBlockName) # # Generate the mapping between the variables on all the # instances and the xstar parameter # var_info = tuple( (v, transBlock_rBigM.all_vars[i], transBlock_rCHull.all_vars[i], transBlock_rCHull.xstar[i]) for i,v in enumerate(transBlock.all_vars)) # # Add the separation objective to the chull subproblem # self._add_separation_objective(var_info, transBlock_rCHull) return instance_rBigM, instance_rCHull, var_info, transBlockName
def solve_linear_GDP(linear_GDP_model, solve_data, config): """Solves the linear GDP model and attempts to resolve solution issues.""" m = linear_GDP_model GDPopt = m.GDPopt_utils # Transform disjunctions _bigm = TransformationFactory('gdp.bigm') _bigm.handlers[Port] = False _bigm.apply_to(m) preprocessing_transformations = [ # # Propagate variable bounds # 'contrib.propagate_eq_var_bounds', # # Detect fixed variables # 'contrib.detect_fixed_vars', # # Propagate fixed variables # 'contrib.propagate_fixed_vars', # # Remove zero terms in linear expressions # 'contrib.remove_zero_terms', # # Remove terms in equal to zero summations # 'contrib.propagate_zero_sum', # # Transform bound constraints # 'contrib.constraints_to_var_bounds', # # Detect fixed variables # 'contrib.detect_fixed_vars', # # Remove terms in equal to zero summations # 'contrib.propagate_zero_sum', # Remove trivial constraints 'contrib.deactivate_trivial_constraints', ] if config.mip_presolve: try: fbbt(m, integer_tol=config.integer_tolerance) for xfrm in preprocessing_transformations: TransformationFactory(xfrm).apply_to(m) except InfeasibleConstraintException: config.logger.debug("MIP preprocessing detected infeasibility.") mip_result = MasterProblemResult() mip_result.feasible = False mip_result.var_values = list(v.value for v in GDPopt.variable_list) mip_result.pyomo_results = SolverResults() mip_result.pyomo_results.solver.termination_condition = tc.error mip_result.disjunct_values = list(disj.indicator_var.value for disj in GDPopt.disjunct_list) return mip_result # Deactivate extraneous IMPORT/EXPORT suffixes getattr(m, 'ipopt_zL_out', _DoNothing()).deactivate() getattr(m, 'ipopt_zU_out', _DoNothing()).deactivate() # Create solver, check availability if not SolverFactory(config.mip_solver).available(): raise RuntimeError("MIP solver %s is not available." % config.mip_solver) # Callback immediately before solving MIP master problem config.call_before_master_solve(m, solve_data) try: with SuppressInfeasibleWarning(): mip_args = dict(config.mip_solver_args) elapsed = get_main_elapsed_time(solve_data.timing) remaining = max(config.time_limit - elapsed, 1) if config.mip_solver == 'gams': mip_args['add_options'] = mip_args.get('add_options', []) mip_args['add_options'].append('option reslim=%s;' % remaining) elif config.mip_solver == 'multisolve': mip_args['time_limit'] = min( mip_args.get('time_limit', float('inf')), remaining) results = SolverFactory(config.mip_solver).solve(m, **mip_args) except RuntimeError as e: if 'GAMS encountered an error during solve.' in str(e): config.logger.warning( "GAMS encountered an error in solve. Treating as infeasible.") mip_result = MasterProblemResult() mip_result.feasible = False mip_result.var_values = list(v.value for v in GDPopt.variable_list) mip_result.pyomo_results = SolverResults() mip_result.pyomo_results.solver.termination_condition = tc.error mip_result.disjunct_values = list(disj.indicator_var.value for disj in GDPopt.disjunct_list) return mip_result else: raise terminate_cond = results.solver.termination_condition if terminate_cond is tc.infeasibleOrUnbounded: # Linear solvers will sometimes tell me that it's infeasible or # unbounded during presolve, but fails to distinguish. We need to # resolve with a solver option flag on. results, terminate_cond = distinguish_mip_infeasible_or_unbounded( m, config) if terminate_cond is tc.unbounded: # Solution is unbounded. Add an arbitrary bound to the objective and resolve. # This occurs when the objective is nonlinear. The nonlinear objective is moved # to the constraints, and deactivated for the linear master problem. obj_bound = 1E15 config.logger.warning( 'Linear GDP was unbounded. ' 'Resolving with arbitrary bound values of (-{0:.10g}, {0:.10g}) on the objective. ' 'Check your initialization routine.'.format(obj_bound)) main_objective = next(m.component_data_objects(Objective, active=True)) GDPopt.objective_bound = Constraint(expr=(-obj_bound, main_objective.expr, obj_bound)) with SuppressInfeasibleWarning(): results = SolverFactory(config.mip_solver).solve( m, **config.mip_solver_args) terminate_cond = results.solver.termination_condition # Build and return results object mip_result = MasterProblemResult() mip_result.feasible = True mip_result.var_values = list(v.value for v in GDPopt.variable_list) mip_result.pyomo_results = results mip_result.disjunct_values = list(disj.indicator_var.value for disj in GDPopt.disjunct_list) if terminate_cond is tc.optimal or terminate_cond is tc.locallyOptimal: pass elif terminate_cond is tc.infeasible: config.logger.info( 'Linear GDP is now infeasible. ' 'GDPopt has finished exploring feasible discrete configurations.') mip_result.feasible = False elif terminate_cond is tc.maxTimeLimit: # TODO check that status is actually ok and everything is feasible config.logger.info( 'Unable to optimize linear GDP problem within time limit. ' 'Using current solver feasible solution.') elif (terminate_cond is tc.other and results.solution.status is SolutionStatus.feasible): # load the solution and suppress the warning message by setting # solver status to ok. config.logger.info('Linear GDP solver reported feasible solution, ' 'but not guaranteed to be optimal.') else: raise ValueError('GDPopt unable to handle linear GDP ' 'termination condition ' 'of %s. Solver message: %s' % (terminate_cond, results.solver.message)) return mip_result
def _apply_solver(self): start_time = time.time() # # Cache the instance # xfrm = TransformationFactory('bilevel.linear_dual') xfrm.apply_to(self._instance) # # Verify whether the objective is linear # nonlinear = False for odata in self._instance.component_objects(Objective, active=True): nonlinear = odata.expr.polynomial_degree() != 1 # Stop after the first objective break # # Apply an additional transformation to remap bilinear terms # if nonlinear: gdp_xfrm = TransformationFactory("gdp.bilinear") gdp_xfrm.apply_to(self._instance) mip_xfrm = TransformationFactory("gdp.bigm") mip_xfrm.apply_to(self._instance, bigM=self.options.get('bigM', 100000)) # # Solve with a specified solver # solver = self.options.solver if not self.options.solver: solver = 'glpk' # use the with block here so that deactivation of the # solver plugin always occurs thereby avoiding memory # leaks caused by plugins! with pyomo.opt.SolverFactory(solver) as opt: self.results = [] # # **NOTE: It would be better to override _presolve on the # base class of this solver as you might be # missing a number of keywords that were passed # into the solve method (e.g., none of the # io_options are getting relayed to the subsolver # here). # self.results.append( opt.solve(self._instance, tee=self._tee, timelimit=self._timelimit)) #print("POST-SOLVE - BEGIN") #self._instance.write("tmp.lp", io_options={"symbolic_solver_labels":True}) #self._instance.pprint() #self._instance.display() #print("POST-SOLVE - END") # # If the problem was bilinear, then reactivate the original data # if nonlinear: i = 0 for v in self._instance.bilinear_data_.vlist.itervalues(): #print(v) #print(v.name) #print(type(v)) #print(v.value) if abs(v.value) <= 1e-7: self._instance.bilinear_data_.vlist_boolean[i] = 0 else: self._instance.bilinear_data_.vlist_boolean[i] = 1 i = i + 1 # self._instance.bilinear_data_.deactivate() # # Transform the result back into the original model # tdata = self._instance._transformation_data['bilevel.linear_dual'] unfixed_cuids = set() # Copy variable values and fix them for vuid in tdata.fixed: for index_, data_ in vuid.find_component_on( self._instance).iteritems(): if not data_.fixed: data_.value = self._instance.find_component( data_).value data_.fixed = True unfixed_cuids.add(ComponentUID(data_)) # Reclassify the SubModel components and resolve for name_ in tdata.submodel: submodel = getattr(self._instance, name_) submodel.activate() for (name, data) in submodel.component_map(active=False).items(): if not isinstance(data, Var) and not isinstance(data, Set): data.activate() dual_submodel = getattr(self._instance, name_ + '_dual') dual_submodel.deactivate() pyomo.common.PyomoAPIFactory( 'pyomo.repn.compute_standard_repn')({}, model=submodel) self._instance.reclassify_component_type(name_, Block) # use the with block here so that deactivation of the # solver plugin always occurs thereby avoiding memory # leaks caused by plugins! with pyomo.opt.SolverFactory(solver) as opt_inner: # # **NOTE: It would be better to override _presolve on the # base class of this solver as you might be # missing a number of keywords that were passed # into the solve method (e.g., none of the # io_options are getting relayed to the subsolver # here). # results = opt_inner.solve(self._instance, tee=self._tee, timelimit=self._timelimit) #select=None) # Unfix variables for vuid in tdata.fixed: for index_, data_ in vuid.find_component_on( self._instance).iteritems(): if ComponentUID(data_) in unfixed_cuids: data_.fixed = False # self._instance.solutions.select(0, ignore_fixed_vars=True) self.results.append(results) # stop_time = time.time() self.wall_time = stop_time - start_time self.results_obj = self._setup_results_obj() # # Reactivate top level objective # and reclassify the submodel # for oname, odata in self._instance.component_map( Objective).items(): odata.activate() # TODO: rework the Block logic to allow for searching SubModel objects for variables, etc. #data_.parent_component().parent_block().reclassify_component_type(name_, SubModel) # # Return the sub-solver return condition value and log # return pyutilib.misc.Bunch(rc=getattr(opt, '_rc', None), log=getattr(opt, '_log', None))
def get_dual_values(solver, model): if id(model) not in get_dual_values.discrete_stage2_vars: # 1st attempt to get duals: we need to see if the model has # discrete variables (solvers won't give duals if there are # still active discrete variables) try: get_dual_values.discrete_stage2_vars[id(model)] = False return get_dual_values(solver, model) except: get_dual_values.discrete_stage2_vars[id(model)] = True # Find the discrete variables to populate the list return get_dual_values(solver, model) duals = {} _con = model._interscenario_plugin.fixed_variables_constraint if get_dual_values.discrete_stage2_vars[id(model)]: # Fix all discrete variables xfrm = TransformationFactory('core.relax_discrete') if PYOMO_4_0: xfrm.apply(model, inplace=True) else: xfrm.apply_to(model) # Note: preprocessing is only necessary if we are changing a # fixed/freed variable. if FALLBACK_ON_BRUTE_FORCE_PREPROCESS: model.preprocess() else: _map = {} preprocess_block_constraints( model._interscenario_plugin, idMap=_map) #SOLVE results = solver.solve(model, warmstart=True) ss = results.solver.status tc = results.solver.termination_condition #self.timeInSolver += results['Solver'][0]['Time'] if ss == SolverStatus.ok and tc in _acceptable_termination_conditions: state = '' elif tc in _infeasible_termination_conditions: state = 'INFEASIBLE' else: state = 'NONOPTIMAL' if state: logger.warning( "Resolving subproblem model with relaxed second-stage " "discrete variables failed (%s). " "Dual values not available." % (state,) ) else: # Get the duals if PYOMO_4_0: model.load(results) else: model.solutions.load_from(results) #model.dual.pprint() for varid in model._interscenario_plugin.STAGE1VAR: duals[varid] = model.dual[_con[varid]] # Free the discrete second-stage variables if PYOMO_4_0: xfrm.apply(model, inplace=True, undo=True) else: xfrm.apply_to(model, undo=True) else: # return the duals for varid in model._interscenario_plugin.STAGE1VAR: duals[varid] = model.dual[_con[varid]] return duals
def _apply_solver(self): start_time = time.time() # # Cache the instance # xfrm = TransformationFactory('bilevel.linear_dual') xfrm.apply_to(self._instance) # # Verify whether the objective is linear # nonlinear=False for odata in self._instance.component_objects(Objective, active=True): nonlinear = odata.expr.polynomial_degree() != 1 # Stop after the first objective break # # Apply an additional transformation to remap bilinear terms # if nonlinear: gdp_xfrm = TransformationFactory("gdp.bilinear") gdp_xfrm.apply_to(self._instance) mip_xfrm = TransformationFactory("gdp.bigm") mip_xfrm.apply_to(self._instance, default_bigM=self.options.get('bigM',100000)) # # Solve with a specified solver # solver = self.options.solver if not self.options.solver: solver = 'glpk' # use the with block here so that deactivation of the # solver plugin always occurs thereby avoiding memory # leaks caused by plugins! with pyomo.opt.SolverFactory(solver) as opt: self.results = [] # # **NOTE: It would be better to override _presolve on the # base class of this solver as you might be # missing a number of keywords that were passed # into the solve method (e.g., none of the # io_options are getting relayed to the subsolver # here). # self.results.append(opt.solve(self._instance, tee=self._tee, timelimit=self._timelimit)) #print("POST-SOLVE - BEGIN") #self._instance.write("tmp.lp", io_options={"symbolic_solver_labels":True}) #self._instance.pprint() #self._instance.display() #print("POST-SOLVE - END") # # If the problem was bilinear, then reactivate the original data # if nonlinear: i = 0 for v in self._instance.bilinear_data_.vlist.itervalues(): #print(v) #print(v.cname()) #print(type(v)) #print(v.value) if abs(v.value) <= 1e-7: self._instance.bilinear_data_.vlist_boolean[i] = 0 else: self._instance.bilinear_data_.vlist_boolean[i] = 1 i = i + 1 # self._instance.bilinear_data_.deactivate() # # Transform the result back into the original model # tdata = self._instance._transformation_data['bilevel.linear_dual'] unfixed_cuids = set() # Copy variable values and fix them for vuid in tdata.fixed: for index_, data_ in vuid.find_component_on(self._instance).iteritems(): if not data_.fixed: data_.value = self._instance.find_component(data_).value data_.fixed = True unfixed_cuids.add(ComponentUID(data_)) # Reclassify the SubModel components and resolve for name_ in tdata.submodel: submodel = getattr(self._instance, name_) submodel.activate() for (name, data) in submodel.component_map(active=False).items(): if not isinstance(data,Var) and not isinstance(data,Set): data.activate() dual_submodel = getattr(self._instance, name_+'_dual') dual_submodel.deactivate() pyomo.util.PyomoAPIFactory('pyomo.repn.compute_canonical_repn')({}, model=submodel) self._instance.reclassify_component_type(name_, Block) # use the with block here so that deactivation of the # solver plugin always occurs thereby avoiding memory # leaks caused by plugins! with pyomo.opt.SolverFactory(solver) as opt_inner: # # **NOTE: It would be better to override _presolve on the # base class of this solver as you might be # missing a number of keywords that were passed # into the solve method (e.g., none of the # io_options are getting relayed to the subsolver # here). # results = opt_inner.solve(self._instance, tee=self._tee, timelimit=self._timelimit) #select=None) # Unfix variables for vuid in tdata.fixed: for index_, data_ in vuid.find_component_on(self._instance).iteritems(): if ComponentUID(data_) in unfixed_cuids: data_.fixed = False # self._instance.solutions.select(0, ignore_fixed_vars=True) self.results.append(results) # stop_time = time.time() self.wall_time = stop_time - start_time self.results_obj = self._setup_results_obj() # # Reactivate top level objective # and reclassify the submodel # for oname, odata in self._instance.component_map(Objective).items(): odata.activate() # TODO: rework the Block logic to allow for searching SubModel objects for variables, etc. #data_.parent_component().parent_block().reclassify_component_type(name_, SubModel) # # Return the sub-solver return condition value and log # return pyutilib.misc.Bunch(rc=getattr(opt,'_rc', None), log=getattr(opt,'_log',None))
def solve_NLP_subproblem(solve_data, config): m = solve_data.working_model.clone() MindtPy = m.MindtPy_utils main_objective = next(m.component_data_objects(Objective, active=True)) solve_data.nlp_iter += 1 config.logger.info('NLP %s: Solve subproblem for fixed binaries.' % (solve_data.nlp_iter, )) # Set up NLP for v in MindtPy.variable_list: if v.is_binary(): v.fix(int(round(value(v)))) # restore original variable values for nlp_var, orig_val in zip(MindtPy.variable_list, solve_data.initial_var_values): if not nlp_var.fixed and not nlp_var.is_binary(): nlp_var.value = orig_val MindtPy.MindtPy_linear_cuts.deactivate() m.tmp_duals = ComponentMap() for c in m.component_data_objects(ctype=Constraint, active=True, descend_into=True): rhs = ((0 if c.upper is None else c.upper) + (0 if c.lower is None else c.lower)) sign_adjust = 1 if value(c.upper) is None else -1 m.tmp_duals[c] = sign_adjust * max(0, sign_adjust * (rhs - value(c.body))) # TODO check sign_adjust t = TransformationFactory('contrib.deactivate_trivial_constraints') t.apply_to(m, tmp=True, ignore_infeasible=True) # Solve the NLP # m.pprint() # print nlp problem for debugging with SuppressInfeasibleWarning(): results = SolverFactory(config.nlp_solver).solve( m, **config.nlp_solver_args) var_values = list(v.value for v in MindtPy.variable_list) subprob_terminate_cond = results.solver.termination_condition if subprob_terminate_cond is tc.optimal: copy_var_list_values( m.MindtPy_utils.variable_list, solve_data.working_model.MindtPy_utils.variable_list, config) for c in m.tmp_duals: if m.dual.get(c, None) is None: m.dual[c] = m.tmp_duals[c] duals = list(m.dual[c] for c in MindtPy.constraint_list) if main_objective.sense == minimize: solve_data.UB = min(value(main_objective.expr), solve_data.UB) solve_data.solution_improved = solve_data.UB < solve_data.UB_progress[ -1] solve_data.UB_progress.append(solve_data.UB) else: solve_data.LB = max(value(main_objective.expr), solve_data.LB) solve_data.solution_improved = solve_data.LB > solve_data.LB_progress[ -1] solve_data.LB_progress.append(solve_data.LB) config.logger.info('NLP {}: OBJ: {} LB: {} UB: {}'.format( solve_data.nlp_iter, value(main_objective.expr), solve_data.LB, solve_data.UB)) if solve_data.solution_improved: solve_data.best_solution_found = m.clone() # Add the linear cut if config.strategy == 'OA': add_oa_cut(var_values, duals, solve_data, config) elif config.strategy == 'PSC': add_psc_cut(solve_data, config) elif config.strategy == 'GBD': add_gbd_cut(solve_data, config) # This adds an integer cut to the feasible_integer_cuts # ConstraintList, which is not activated by default. However, it # may be activated as needed in certain situations or for certain # values of option flags. add_int_cut(var_values, solve_data, config, feasible=True) config.call_after_subproblem_feasible(m, solve_data) elif subprob_terminate_cond is tc.infeasible: # TODO try something else? Reinitialize with different initial # value? config.logger.info('NLP subproblem was locally infeasible.') for c in m.component_data_objects(ctype=Constraint, active=True, descend_into=True): rhs = ((0 if c.upper is None else c.upper) + (0 if c.lower is None else c.lower)) sign_adjust = 1 if value(c.upper) is None else -1 m.dual[c] = sign_adjust * max(0, sign_adjust * (rhs - value(c.body))) for var in m.component_data_objects(ctype=Var, descend_into=True): if config.strategy == 'PSC' or config.strategy == 'GBD': m.ipopt_zL_out[var] = 0 m.ipopt_zU_out[var] = 0 if var.ub is not None and abs( var.ub - value(var)) < config.bound_tolerance: m.ipopt_zL_out[var] = 1 elif var.lb is not None and abs( value(var) - var.lb) < config.bound_tolerance: m.ipopt_zU_out[var] = -1 # m.pprint() #print infeasible nlp problem for debugging if config.strategy == 'OA': config.logger.info('Solving feasibility problem') if config.initial_feas: # add_feas_slacks(m, solve_data) # config.initial_feas = False var_values, duals = solve_NLP_feas(solve_data, config) add_oa_cut(var_values, duals, solve_data, config) # Add an integer cut to exclude this discrete option add_int_cut(var_values, solve_data, config) elif subprob_terminate_cond is tc.maxIterations: # TODO try something else? Reinitialize with different initial # value? config.logger.info( 'NLP subproblem failed to converge within iteration limit.') # Add an integer cut to exclude this discrete option add_int_cut(solve_data, config) else: raise ValueError('MindtPy unable to handle NLP subproblem termination ' 'condition of {}'.format(subprob_terminate_cond)) # Call the NLP post-solve callback config.call_after_subproblem_solve(m, solve_data)
def _apply_solver(self): self.results = [] start_time = time.time() # # Solve with a specified solver # solver = self.options.solver if not self.options.solver: solver = 'gurobi' bigm = TransformationFactory('gdp.bigm') # Step 1. Initialization LB = -inf UB = inf theta = 0. xi = 10e-3 k = 0 epsilon = 1e-4 M = 1e6 # matrix representation for bilevel problem matrix_repn = BilevelMatrixRepn(self._instance) # each lower-level problem submodel = [ block for block in self._instance.component_objects(SubModel) ][0] if len(submodel) != 1: raise Exception( 'Problem encountered, this is not a valid bilevel model for the solver.' ) self._instance.reclassify_component_type(submodel, Block) varref(submodel) dataref(submodel) # all algorithm blocks algorithm_blocks = list() algorithm_blocks.append(submodel) all_vars = {key: var for (key, var) in matrix_repn._all_vars.items()} # for k,v in all_vars.items(): # if v.ub is None: # v.setub(M) # if v.lb is None: # v.setlb(-M) # get the variables that are fixed for the submodel (lower-level block) fixed_vars = { key: var for (key, var) in matrix_repn._all_vars.items() if key in matrix_repn._fixed_var_ids[submodel.name] } # continuous variables in SubModel c_vars = { key: var for (key, var) in matrix_repn._all_vars.items() if key in matrix_repn._c_var_ids - fixed_vars.keys() } # binary variables in SubModel b_vars = { key: var for (key, var) in matrix_repn._all_vars.items() if key in matrix_repn._b_var_ids - fixed_vars.keys() } # integer variables in SubModel i_vars = { key: var for (key, var) in matrix_repn._all_vars.items() if key in matrix_repn._i_var_ids - fixed_vars.keys() } # get constraint information related to constraint id, sign, and rhs value sub_cons = matrix_repn._cons_sense_rhs[submodel.name] # lower bounding block name -- unique naming convention _lower_model_name = '_p9' _lower_model_name = unique_component_name(self._instance, _lower_model_name) # upper bounding block name -- unique naming convention _upper_model_name = '_p7' _upper_model_name = unique_component_name(self._instance, _upper_model_name) while k <= self._k_max_iter: # Step 2. Lower Bounding # Solve problem (P5) master problem. # This includes equations (53), (12), (13), (15), and (54) # On iteration k = 0, (54) does not exist. Instead of implementing (54), # this approach applies problem (P9) which incorporates KKT-based tightening # constraints, and a projection and indicator constraint set. lower_bounding_master = getattr(self._instance, _lower_model_name, None) if lower_bounding_master is None: xfrm = TransformationFactory('pao.bilevel.highpoint') kwds = {'submodel_name': _lower_model_name} xfrm.apply_to(self._instance, **kwds) lower_bounding_master = getattr(self._instance, _lower_model_name) algorithm_blocks.append(lower_bounding_master) _c_var_bounds_rule = lambda m, k: c_vars[k].bounds _c_var_init_rule = lambda m, k: (c_vars[k].lb + c_vars[k].ub ) / 2 lower_bounding_master._iter_c = Var( Any, bounds=(0, M), within=Reals, dense=False) # set (iter k, c_var_ids) lower_bounding_master._iter_c_tilde = Var( c_vars.keys(), bounds=_c_var_bounds_rule, initialize=_c_var_init_rule, within=Reals) # set (iter k, c_var_ids) lower_bounding_master._iter_b = Var( Any, within=Binary, bounds=(0, M), dense=False) # set (iter k, b_var_ids) lower_bounding_master._iter_i = Var( Any, within=Integers, bounds=(0, M), dense=False) # set (iter k, i_var_ids) lower_bounding_master._iter_pi_tilde = Var( sub_cons.keys(), bounds=(0, M)) # set (iter k, sub_cons_ids) lower_bounding_master._iter_pi = Var( Any, bounds=(0, M), dense=False) # set (iter k, sub_cons_ids) lower_bounding_master._iter_t = Var( Any, bounds=(0, M), dense=False) # set (iter k, sub_cons_ids) lower_bounding_master._iter_lambda = Var( Any, bounds=(0, M), dense=False) # set (iter k, sub_cons_ids) m = lower_bounding_master # shorthand reference to model if k == 0: # constraint (74) lhs_expr = 0. rhs_expr = 0. for _vid, var in c_vars.items(): (C, C_q, C_constant) = matrix_repn.cost_vectors(submodel, var) coef = float(C) # + dot(C_q,_fixed)) ref = m._map[var] lhs_expr += coef * ref rhs_expr += coef * m._iter_c_tilde[_vid] expr = lhs_expr >= rhs_expr if not type(expr) is bool: lower_bounding_master.KKT_tight1 = Constraint( expr=lhs_expr >= rhs_expr) # constraint (75a) lower_bounding_master.KKT_tight2a = Constraint(sub_cons.keys()) lhs_expr_a = {key: 0. for key in sub_cons.keys()} rhs_expr_a = {key: 0. for key in sub_cons.keys()} for _vid, var in c_vars.items(): (A, A_q, sign, b) = matrix_repn.coef_matrices(submodel, var) coef = A #+ dot(A_q.toarray(), _fixed) for _cid in sub_cons.keys(): idx = list(sub_cons.keys()).index(_cid) lhs_expr_a[_cid] += float( coef[idx]) * m._iter_c_tilde[_vid] for var in {**b_vars, **i_vars, **fixed_vars}.values(): (A, A_q, sign, b) = matrix_repn.coef_matrices(submodel, var) coef = A #+ dot(A_q.toarray(), _fixed) for _cid in sub_cons.keys(): idx = list(sub_cons.keys()).index(_cid) ref = m._map[var] rhs_expr_a[_cid] += -float(coef[idx]) * ref for _cid, b in sub_cons.items(): (_, sign) = _cid rhs_expr_a[_cid] += b if sign == 'l' or sign == 'g->l': expr = lhs_expr_a[_cid] <= rhs_expr_a[_cid] if sign == 'e' or sign == 'g': raise Exception( 'Problem encountered, this problem is not in standard form.' ) if not type(expr) is bool: lower_bounding_master.KKT_tight2a[_cid] = expr else: lower_bounding_master.KKT_tight2a[ _cid] = Constraint.Skip # constraint (75b) lower_bounding_master.KKT_tight2b = Constraint(c_vars.keys()) lhs_expr_b = {key: 0. for key in c_vars.keys()} rhs_expr_b = {key: 0. for key in c_vars.keys()} for _vid, var in c_vars.items(): (A, A_q, sign, b) = matrix_repn.coef_matrices(submodel, var) coef = A #+ dot(A_q.toarray(), _fixed) for _cid in sub_cons.keys(): idx = list(sub_cons.keys()).index(_cid) lhs_expr_b[_vid] += float( coef[idx]) * m._iter_pi_tilde[_cid] (C, C_q, C_constant) = matrix_repn.cost_vectors(submodel, var) rhs_expr_b[_vid] = float(C) #+ dot(C_q,_fixed)) expr = lhs_expr_b[_vid] >= rhs_expr_b[_vid] if not type(expr) is bool: lower_bounding_master.KKT_tight2b[_vid] = expr else: lower_bounding_master.KKT_tight2b[ _vid] = Constraint.Skip # constraint (76a) lower_bounding_master.KKT_tight3a = ComplementarityList() for _vid in c_vars.keys(): lower_bounding_master.KKT_tight3a.add( complements(m._iter_c_tilde[_vid] >= 0, lhs_expr_b[_vid] - rhs_expr_b[_vid] >= 0)) # constraint (76b) lower_bounding_master.KKT_tight3b = ComplementarityList() for _cid in sub_cons.keys(): lower_bounding_master.KKT_tight3b.add( complements(m._iter_pi_tilde[_cid] >= 0, rhs_expr_a[_cid] - lhs_expr_a[_cid] >= 0)) # constraint (77a) lower_bounding_master.KKT_tight4a = Constraint(c_vars.keys()) for _vid in c_vars.keys(): lower_bounding_master.KKT_tight4a[ _vid] = m._iter_c_tilde[_vid] >= 0 # constraint (77b) lower_bounding_master.KKT_tight4b = Constraint(sub_cons.keys()) for _cid in sub_cons.keys(): lower_bounding_master.KKT_tight4b[ _cid] = m._iter_pi_tilde[_cid] >= 0 # solve the HPR and check the termination condition lower_bounding_master.activate() TransformationFactory('mpec.simple_disjunction').apply_to( lower_bounding_master) bigm.apply_to(lower_bounding_master) with pyomo.opt.SolverFactory(solver) as opt: self.results.append( opt.solve(lower_bounding_master, tee=self._tee, timelimit=self._timelimit)) if not _check_termination_condition(self.results[-1]): raise Exception( 'The lower-bounding master is infeasible or sub-optimal.') # the LB should be a sequence of non-decreasing lower-bounds _lb = [ value(odata) for odata in self._instance.component_objects(Objective) if odata.parent_block() == self._instance ][0] if _lb < LB: raise Exception( 'The lower-bound should be non-decreasing; a decreasing lower-bound indicates an algorithm issue.' ) LB = max(LB, _lb) lower_bounding_master.deactivate() # Step 3. Termination if UB - LB < xi: # print(UB) # print(LB) if self._instance.solutions.solutions: self._instance.solutions.select(0, ignore_fixed_vars=True) stop_time = time.time() self.wall_time = stop_time - start_time self.results_obj = self._setup_results_obj() return pyutilib.misc.Bunch(rc=getattr(opt, '_rc', None), log=getattr(opt, '_log', None)) # fix the upper-level (master) variables to solve (P6) and (P7) for key, var in fixed_vars.items(): var.fix(var.value) # Step 4. Subproblem 1 # Solve problem (P6) lower-level problem for fixed upper-level optimal vars. # In iteration k=0, this first subproblem is always feasible; furthermore, the # optimal solution to (P5), alternatively (P9), will also be feasible to (P6). with pyomo.opt.SolverFactory(solver) as _opt: _results = _opt.solve(submodel, tee=self._tee, timelimit=self._timelimit) if not _check_termination_condition(_results): raise Exception( 'The lower-level subproblem with fixed upper-level variables is infeasible or sub-optimal.' ) theta = [ value(odata) for odata in submodel.component_objects(Objective) ][0] # solution for all variable values _fixed = array( [var.value for (key, var) in matrix_repn._all_vars.items()]) # temporary dictionary for b_vars _b_vars_subproblem1 = dict() for _vid, var in b_vars.items(): _b_vars_subproblem1[_vid] = var.value # temporary dictionary for i_vars _i_vars_subproblem1 = dict() for _vid, var in i_vars.items(): _i_vars_subproblem1[_vid] = var.value # Step 5. Subproblem 2 # Solve problem (P7) upper bounding problem for fixed upper-level optimal vars. upper_bounding_subproblem = getattr(self._instance, _upper_model_name, None) if upper_bounding_subproblem is None: xfrm = TransformationFactory('pao.bilevel.highpoint') kwds = {'submodel_name': _upper_model_name} xfrm.apply_to(self._instance, **kwds) upper_bounding_subproblem = getattr(self._instance, _upper_model_name) algorithm_blocks.append(upper_bounding_subproblem) for odata in upper_bounding_subproblem.component_objects( Objective): upper_bounding_subproblem.del_component(odata) # solve for the master problem objective value for just the lower level variables upper_bounding_subproblem.del_component('objective') obj_constant = 0. obj_expr = 0. for var in {**c_vars, **b_vars, **i_vars}.values(): (C, C_q, C_constant) = matrix_repn.cost_vectors(self._instance, var) if obj_constant == 0. and C_constant != 0.: obj_constant += C_constant # only add the constant once obj_expr += float(C + dot(C_q, _fixed)) * var upper_bounding_subproblem.objective = Objective(expr=obj_expr + obj_constant) # include lower bound constraint on the subproblem objective upper_bounding_subproblem.del_component('theta_pareto') sub_constant = 0. sub_expr = 0. for var in all_vars.values(): (C, C_q, C_constant) = matrix_repn.cost_vectors(submodel, var) if sub_constant == 0. and C_constant != 0.: sub_constant += C_constant # only add the constant once sub_expr += float(C + dot(C_q, _fixed)) * var upper_bounding_subproblem.theta_pareto = Constraint( expr=sub_expr + sub_constant >= theta) with pyomo.opt.SolverFactory(solver) as opt: self.results.append( opt.solve(upper_bounding_subproblem, tee=self._tee, timelimit=self._timelimit)) if _check_termination_condition(self.results[-1]): # calculate new upper bound obj_constant = 0. obj_expr = 0. for var in fixed_vars.values(): (C, C_q, C_constant) = matrix_repn.cost_vectors( self._instance, var) if obj_constant == 0. and C_constant != 0.: obj_constant += C_constant # only add the constant once obj_expr += float(C + dot(C_q, _fixed)) * var.value # line 16 of decomposition algorithm _ub = obj_expr + obj_constant + [ value(odata) for odata in upper_bounding_subproblem.component_objects(Objective) ][0] UB = min(UB, _ub) # unfix the upper-level variables for var in fixed_vars.values(): var.unfix() # fix the solution for submodel binary variables for _vid, var in b_vars.items(): m._iter_b[(k, _vid)].fix(var.value) # fix the solution for submodel integer variables for _vid, var in i_vars.items(): m._iter_i[(k, _vid)].fix(var.value) else: # infeasible problem # unfix the upper-level variables for var in fixed_vars.values(): var.unfix() # retrieve b_vars from temporary dictionary for subproblem1 for _vid, var in b_vars.items(): m._iter_b[(k, _vid)].fix(_b_vars_subproblem1[_vid]) # retrieve i_vars from temporary dictionary for subproblem1 for _vid, var in i_vars.items(): m._iter_i[(k, _vid)].fix(_i_vars_subproblem1[_vid]) # Step 6. Tightening the Master Problem projections = getattr(lower_bounding_master, 'projections', None) if projections is None: lower_bounding_master.projections = Block(Any) projections = lower_bounding_master.projections # constraint (79) projections[k].projection1 = Constraint(sub_cons.keys()) lhs_expr_proj = {key: 0. for key in sub_cons.keys()} rhs_expr_proj = {key: 0. for key in sub_cons.keys()} for _vid, var in c_vars.items(): (A, A_q, sign, b) = matrix_repn.coef_matrices(submodel, var) coef = A + dot(A_q.toarray(), _fixed) for _cid in sub_cons.keys(): idx = list(sub_cons.keys()).index(_cid) lhs_expr_proj[_cid] += float( coef[idx]) * m._iter_c[(k, _vid)] for _vid, var in b_vars.items(): (A, A_q, sign, b) = matrix_repn.coef_matrices(submodel, var) coef = A + dot(A_q.toarray(), _fixed) for _cid in sub_cons.keys(): idx = list(sub_cons.keys()).index(_cid) rhs_expr_proj[_cid] += -float(coef[idx]) * m._iter_b[ (k, _vid)] for _vid, var in i_vars.items(): (A, A_q, sign, b) = matrix_repn.coef_matrices(submodel, var) coef = A + dot(A_q.toarray(), _fixed) for _cid in sub_cons.keys(): idx = list(sub_cons.keys()).index(_cid) rhs_expr_proj[_cid] += -float(coef[idx]) * m._iter_i[ (k, _vid)] for _vid, var in fixed_vars.items(): (A, A_q, sign, b) = matrix_repn.coef_matrices(submodel, var) coef = A + dot(A_q.toarray(), _fixed) for _cid in sub_cons.keys(): idx = list(sub_cons.keys()).index(_cid) rhs_expr_proj[_cid] += -float(coef[idx]) * var for _cid, b in sub_cons.items(): (id, sign) = _cid rhs_expr_proj[_cid] += b if sign == 'l' or sign == 'g->l': projections[k].projection1[ _cid] = lhs_expr_proj[_cid] - m._iter_t[ (k, _cid)] <= rhs_expr_proj[_cid] if sign == 'e' or sign == 'g': raise Exception( 'Problem encountered, this problem is not in standard form.' ) # constraint (80a) projections[k].projection2a = Constraint(c_vars.keys()) for _vid in c_vars.keys(): projections[k].projection2a[_vid] = m._iter_c[(k, _vid)] >= 0 # constraint (80b) projections[k].projection2b = Constraint(sub_cons.keys()) for _cid in sub_cons.keys(): projections[k].projection2b[_cid] = m._iter_t[(k, _cid)] >= 0 # constraint (82) projections[k].projection3 = Block() projections[k].projection3.indicator = Disjunct() projections[k].projection3.block = Disjunct() projections[k].projection3.disjunct = Disjunction(expr=[ projections[k].projection3.indicator, projections[k].projection3.block ]) projections[k].projection3.indicator.cons_feas = Constraint( expr=sum(m._iter_t[(k, _cid)] for _cid in sub_cons.keys()) >= epsilon) disjunction = projections[k].projection3.block # constraint (82a) lhs_constant = 0. lhs_expr = 0. rhs_constant = 0. rhs_expr = 0. for _vid, var in {**c_vars, **b_vars, **i_vars}.items(): (C, C_q, C_constant) = matrix_repn.cost_vectors(submodel, var) lhs_expr += float(C + dot(C_q, _fixed)) * var if var.is_continuous(): rhs_expr += float(C + dot(C_q, _fixed)) * m._iter_c[(k, _vid)] if var.is_binary(): rhs_expr += float(C + dot(C_q, _fixed)) * m._iter_b[(k, _vid)] if var.is_integer(): rhs_expr += float(C + dot(C_q, _fixed)) * m._iter_i[(k, _vid)] disjunction.projection3a = Constraint( expr=lhs_expr + lhs_constant >= rhs_expr + rhs_constant) # constraint (82b) disjunction.projection3b = Constraint(sub_cons.keys()) for _cid in sub_cons.keys(): (_, sign) = _cid if sign == 'l' or sign == 'g->l': expr = lhs_expr_proj[_cid] <= rhs_expr_proj[_cid] if sign == 'e' or sign == 'g': raise Exception( 'Problem encountered, this problem is not in standard form.' ) if not type(expr) is bool: disjunction.projection3b[_cid] = expr else: disjunction.projection3b[_cid] = Constraint.Skip # constraint (82c) disjunction.projection3c = Constraint(c_vars.keys()) lhs_expr = {key: 0. for key in c_vars.keys()} rhs_expr = {key: 0. for key in c_vars.keys()} for _vid, var in c_vars.items(): (A, A_q, sign, b) = matrix_repn.coef_matrices(submodel, var) coef = A + dot(A_q.toarray(), _fixed) idx = list(sub_cons.keys()).index(_cid) lhs_expr[_vid] += float(coef[idx]) * m._iter_pi[(k, _cid)] (C, C_q, C_constant) = matrix_repn.cost_vectors(submodel, var) rhs_expr[_vid] = float(C + dot(C_q, _fixed)) expr = lhs_expr[_vid] >= rhs_expr[_vid] if not type(expr) is bool: disjunction.projection3c[_vid] = expr else: disjunction.projection3c[_vid] = Constraint.Skip # constraint (82d) disjunction.projection3d = ComplementarityList() for _vid in c_vars.keys(): disjunction.projection3d.add( complements(m._iter_c[(k, _vid)] >= 0, lhs_expr[_vid] - rhs_expr[_vid] >= 0)) # constraint (82e) disjunction.projection3e = ComplementarityList() for _cid in sub_cons.keys(): disjunction.projection3e.add( complements( m._iter_pi[(k, _cid)] >= 0, rhs_expr_proj[_cid] - lhs_expr_proj[_cid] >= 0)) # constraint (82f) disjunction.projection3f = Constraint(c_vars.keys()) for _vid in c_vars.keys(): disjunction.projection3f[_vid] = m._iter_c[(k, _vid)] >= 0 # constraint (82g) disjunction.projection3g = Constraint(sub_cons.keys()) for _cid in sub_cons.keys(): disjunction.projection3g[_cid] = m._iter_pi[(k, _cid)] >= 0 # constraint (83a) projections[k].projection4a = Constraint(c_vars.keys()) lhs_expr = {key: 0. for key in c_vars.keys()} for _vid, var in c_vars.items(): (A, A_q, sign, b) = matrix_repn.coef_matrices(submodel, var) coef = A + dot(A_q.toarray(), _fixed) for _cid in sub_cons.keys(): idx = list(sub_cons.keys()).index(_cid) lhs_expr[_vid] += float( coef[idx]) * m._iter_lambda[(k, _cid)] expr = lhs_expr[_vid] >= 0 if not type(expr) is bool: projections[k].projection4a[_vid] = expr else: projections[k].projection4a[_vid] = Constraint.Skip # constraint (83b) projections[k].projection4b = ComplementarityList() for _vid in c_vars.keys(): projections[k].projection4b.add( complements(m._iter_c[(k, _vid)] >= 0, lhs_expr[_vid] >= 0)) # constraint (84a) projections[k].projection5a = Constraint(sub_cons.keys()) for _cid in sub_cons.keys(): projections[k].projection5a[_cid] = 1 - m._iter_lambda[ (k, _cid)] >= 0 # constraint (84b) projections[k].projection5b = ComplementarityList() for _cid in sub_cons.keys(): projections[k].projection5b.add( complements(m._iter_t[(k, _cid)] >= 0, 1 - m._iter_lambda[(k, _cid)] >= 0)) # constraint (85) projections[k].projection6 = ComplementarityList() for _cid in sub_cons.keys(): projections[k].projection6.add( complements( m._iter_lambda[(k, _cid)] >= 0, rhs_expr_proj[_cid] - lhs_expr_proj[_cid] + m._iter_t[(k, _cid)] >= 0)) k = k + 1 # Step 7. Loop if UB - LB < xi: # print(UB) # print(LB) if self._instance.solutions.solutions: self._instance.solutions.select(0, ignore_fixed_vars=True) stop_time = time.time() self.wall_time = stop_time - start_time self.results_obj = self._setup_results_obj() return pyutilib.misc.Bunch(rc=getattr(opt, '_rc', None), log=getattr(opt, '_log', None))
def solve_NLP_subproblem(solve_data, config): m = solve_data.working_model.clone() MindtPy = m.MindtPy_utils main_objective = next(m.component_data_objects(Objective, active=True)) solve_data.nlp_iter += 1 config.logger.info('NLP %s: Solve subproblem for fixed binaries.' % (solve_data.nlp_iter,)) # Set up NLP for v in MindtPy.variable_list: if v.is_binary(): v.fix(int(round(value(v)))) # restore original variable values for nlp_var, orig_val in zip( MindtPy.variable_list, solve_data.initial_var_values): if not nlp_var.fixed and not nlp_var.is_binary(): nlp_var.value = orig_val MindtPy.MindtPy_linear_cuts.deactivate() m.tmp_duals = ComponentMap() for c in m.component_data_objects(ctype=Constraint, active=True, descend_into=True): rhs = ((0 if c.upper is None else c.upper) + (0 if c.lower is None else c.lower)) sign_adjust = 1 if value(c.upper) is None else -1 m.tmp_duals[c] = sign_adjust * max(0, sign_adjust * (rhs - value(c.body))) # TODO check sign_adjust t = TransformationFactory('contrib.deactivate_trivial_constraints') t.apply_to(m, tmp=True, ignore_infeasible=True) # Solve the NLP # m.pprint() # print nlp problem for debugging with SuppressInfeasibleWarning(): results = SolverFactory(config.nlp_solver).solve( m, **config.nlp_solver_args) var_values = list(v.value for v in MindtPy.variable_list) subprob_terminate_cond = results.solver.termination_condition if subprob_terminate_cond is tc.optimal: copy_var_list_values( m.MindtPy_utils.variable_list, solve_data.working_model.MindtPy_utils.variable_list, config) for c in m.tmp_duals: if m.dual.get(c, None) is None: m.dual[c] = m.tmp_duals[c] duals = list(m.dual[c] for c in MindtPy.constraint_list) if main_objective.sense == minimize: solve_data.UB = min(value(main_objective.expr), solve_data.UB) solve_data.solution_improved = solve_data.UB < solve_data.UB_progress[-1] solve_data.UB_progress.append(solve_data.UB) else: solve_data.LB = max(value(main_objective.expr), solve_data.LB) solve_data.solution_improved = solve_data.LB > solve_data.LB_progress[-1] solve_data.LB_progress.append(solve_data.LB) config.logger.info( 'NLP {}: OBJ: {} LB: {} UB: {}' .format(solve_data.nlp_iter, value(main_objective.expr), solve_data.LB, solve_data.UB)) if solve_data.solution_improved: solve_data.best_solution_found = m.clone() # Add the linear cut if config.strategy == 'OA': add_oa_cut(var_values, duals, solve_data, config) elif config.strategy == 'PSC': add_psc_cut(solve_data, config) elif config.strategy == 'GBD': add_gbd_cut(solve_data, config) # This adds an integer cut to the feasible_integer_cuts # ConstraintList, which is not activated by default. However, it # may be activated as needed in certain situations or for certain # values of option flags. add_int_cut(var_values, solve_data, config, feasible=True) config.call_after_subproblem_feasible(m, solve_data) elif subprob_terminate_cond is tc.infeasible: # TODO try something else? Reinitialize with different initial # value? config.logger.info('NLP subproblem was locally infeasible.') for c in m.component_data_objects(ctype=Constraint, active=True, descend_into=True): rhs = ((0 if c.upper is None else c.upper) + (0 if c.lower is None else c.lower)) sign_adjust = 1 if value(c.upper) is None else -1 m.dual[c] = sign_adjust * max(0, sign_adjust * (rhs - value(c.body))) for var in m.component_data_objects(ctype=Var, descend_into=True): if config.strategy == 'PSC' or config.strategy == 'GBD': m.ipopt_zL_out[var] = 0 m.ipopt_zU_out[var] = 0 if var.ub is not None and abs(var.ub - value(var)) < config.bound_tolerance: m.ipopt_zL_out[var] = 1 elif var.lb is not None and abs(value(var) - var.lb) < config.bound_tolerance: m.ipopt_zU_out[var] = -1 # m.pprint() #print infeasible nlp problem for debugging if config.strategy == 'OA': config.logger.info('Solving feasibility problem') if config.initial_feas: # add_feas_slacks(m, solve_data) # config.initial_feas = False var_values, duals = solve_NLP_feas(solve_data, config) add_oa_cut(var_values, duals, solve_data, config) # Add an integer cut to exclude this discrete option add_int_cut(var_values, solve_data, config) elif subprob_terminate_cond is tc.maxIterations: # TODO try something else? Reinitialize with different initial # value? config.logger.info('NLP subproblem failed to converge within iteration limit.') # Add an integer cut to exclude this discrete option add_int_cut(solve_data, config) else: raise ValueError( 'MindtPy unable to handle NLP subproblem termination ' 'condition of {}'.format(subprob_terminate_cond)) # Call the NLP post-solve callback config.call_after_subproblem_solve(m, solve_data)
def get_dual_values(solver, model): if id(model) not in get_dual_values.discrete_stage2_vars: # 1st attempt to get duals: we need to see if the model has # discrete variables (solvers won't give duals if there are # still active discrete variables) try: get_dual_values.discrete_stage2_vars[id(model)] = False return get_dual_values(solver, model) except: get_dual_values.discrete_stage2_vars[id(model)] = True # Find the discrete variables to populate the list return get_dual_values(solver, model) duals = {} _con = model._interscenario_plugin.fixed_variables_constraint if get_dual_values.discrete_stage2_vars[id(model)]: # Fix all discrete variables xfrm = TransformationFactory('core.relax_discrete') if PYOMO_4_0: xfrm.apply(model, inplace=True) else: xfrm.apply_to(model) # Note: preprocessing is only necessary if we are changing a # fixed/freed variable. if FALLBACK_ON_BRUTE_FORCE_PREPROCESS: model.preprocess() else: _map = {} preprocess_block_constraints(model._interscenario_plugin, idMap=_map) #SOLVE results = solver.solve(model, warmstart=True) ss = results.solver.status tc = results.solver.termination_condition #self.timeInSolver += results['Solver'][0]['Time'] if ss == SolverStatus.ok and tc in _acceptable_termination_conditions: state = '' elif tc in _infeasible_termination_conditions: state = 'INFEASIBLE' else: state = 'NONOPTIMAL' if state: logger.warning( "Resolving subproblem model with relaxed second-stage " "discrete variables failed (%s). " "Dual values not available." % (state, )) else: # Get the duals if PYOMO_4_0: model.load(results) else: model.solutions.load_from(results) #model.dual.pprint() for varid in model._interscenario_plugin.STAGE1VAR: duals[varid] = model.dual[_con[varid]] # Free the discrete second-stage variables if PYOMO_4_0: xfrm.apply(model, inplace=True, undo=True) else: xfrm.apply_to(model, undo=True) else: # return the duals for varid in model._interscenario_plugin.STAGE1VAR: duals[varid] = model.dual[_con[varid]] return duals
def solve_separation_problem(solver, model, fallback): xfrm = TransformationFactory('core.relax_discrete') if PYOMO_4_0: xfrm.apply(model, inplace=True) else: xfrm.apply_to(model) _block = model._interscenario_plugin # Switch objectives _block.original_obj().deactivate() _block.separation_obj.activate() #_block.separation_variables.unfix() _par = _block.fixed_variable_values _sep = _block.separation_variables allow_slack = _block.allow_slack if allow_slack: epsilon = _block.epsilon for idx in _sep: _sep[idx].setlb(None) _sep[idx].setub(None) else: _sep.unfix() # Note: preprocessing is only necessary if we are changing a # fixed/freed variable. if FALLBACK_ON_BRUTE_FORCE_PREPROCESS: model.preprocess() else: _map = {} preprocess_block_objectives(_block, idMap=_map) preprocess_block_constraints(_block, idMap=_map) #SOLVE output_buffer = StringIO() pyutilib.misc.setup_redirect(output_buffer) try: results = solver.solve(model, tee=True) except: logger.warning("Exception raised solving the interscenario " "evaluation subproblem") logger.warning("Solver log:\n%s" % output_buffer.getvalue()) raise finally: pyutilib.misc.reset_redirect() ss = results.solver.status tc = results.solver.termination_condition #self.timeInSolver += results['Solver'][0]['Time'] if ss == SolverStatus.ok and tc in _acceptable_termination_conditions: state = '' if PYOMO_4_0: model.load(results) else: model.solutions.load_from(results) elif tc in _infeasible_termination_conditions: state = 'INFEASIBLE' ans = "!!!!" else: state = 'NONOPTIMAL' ans = "????" if state: if fallback: #logger.warning("Initial attempt to solve the interscenario cut " # "separation subproblem failed with the default " # "solver (%s)." % (state,) ) pass else: logger.warning("Solving the interscenario cut separation " "subproblem failed (%s)." % (state,) ) logger.warning("Solver log:\n%s" % output_buffer.getvalue()) else: cut = dict((vid, (value(_sep[vid]), value(_par[vid]))) for vid in _block.STAGE1VAR) obj = value(_block.separation_obj) ans = (math.sqrt(obj), cut) output_buffer.close() # Restore the objective _block.original_obj().activate() _block.separation_obj.deactivate() # Turn off the separation variables if allow_slack: for idx in _sep: _sep[idx].setlb(-epsilon) _sep[idx].setub(epsilon) else: _sep.fix(0) if PYOMO_4_0: xfrm.apply(model, inplace=True, undo=True) else: xfrm.apply_to(model, undo=True) if FALLBACK_ON_BRUTE_FORCE_PREPROCESS: pass else: _map = {} preprocess_block_objectives(_block, idMap=_map) return ans
def solve_separation_problem(solver, model, fallback): xfrm = TransformationFactory('core.relax_discrete') if PYOMO_4_0: xfrm.apply(model, inplace=True) else: xfrm.apply_to(model) _block = model._interscenario_plugin # Switch objectives _block.original_obj().deactivate() _block.separation_obj.activate() #_block.separation_variables.unfix() _par = _block.fixed_variable_values _sep = _block.separation_variables allow_slack = _block.allow_slack if allow_slack: epsilon = _block.epsilon for idx in _sep: _sep[idx].setlb(None) _sep[idx].setub(None) else: _sep.unfix() # Note: preprocessing is only necessary if we are changing a # fixed/freed variable. if FALLBACK_ON_BRUTE_FORCE_PREPROCESS: model.preprocess() else: _map = {} preprocess_block_objectives(_block, idMap=_map) preprocess_block_constraints(_block, idMap=_map) #SOLVE output_buffer = StringIO() setup_redirect(output_buffer) try: results = solver.solve(model, tee=True) except: logger.warning("Exception raised solving the interscenario " "evaluation subproblem") logger.warning("Solver log:\n%s" % output_buffer.getvalue()) raise finally: reset_redirect() ss = results.solver.status tc = results.solver.termination_condition #self.timeInSolver += results['Solver'][0]['Time'] if ss == SolverStatus.ok and tc in _acceptable_termination_conditions: state = '' if PYOMO_4_0: model.load(results) else: model.solutions.load_from(results) elif tc in _infeasible_termination_conditions: state = 'INFEASIBLE' ans = "!!!!" else: state = 'NONOPTIMAL' ans = "????" if state: if fallback: #logger.warning("Initial attempt to solve the interscenario cut " # "separation subproblem failed with the default " # "solver (%s)." % (state,) ) pass else: logger.warning("Solving the interscenario cut separation " "subproblem failed (%s)." % (state, )) logger.warning("Solver log:\n%s" % output_buffer.getvalue()) else: cut = dict((vid, (value(_sep[vid]), value(_par[vid]))) for vid in _block.STAGE1VAR) obj = value(_block.separation_obj) ans = (math.sqrt(obj), cut) output_buffer.close() # Restore the objective _block.original_obj().activate() _block.separation_obj.deactivate() # Turn off the separation variables if allow_slack: for idx in _sep: _sep[idx].setlb(-epsilon) _sep[idx].setub(epsilon) else: _sep.fix(0) if PYOMO_4_0: xfrm.apply(model, inplace=True, undo=True) else: xfrm.apply_to(model, undo=True) if FALLBACK_ON_BRUTE_FORCE_PREPROCESS: pass else: _map = {} preprocess_block_objectives(_block, idMap=_map) return ans
def _apply_solver(self): start_time = time.time() # # Cache the instance # xfrm = TransformationFactory('bilevel.linear_dual') xfrm.apply_to(self._instance) # # Apply an additional transformation to remap bilinear terms # if self.options.transform is None: xfrm = None else: xfrm = TransformationFactory(self.options.transform) xfrm.apply_to(self._instance) # # Solve with a specified solver # solver = self.options.solver if not self.options.solver: solver = 'glpk' # use the with block here so that deactivation of the # solver plugin always occurs thereby avoiding memory # leaks caused by plugins! with pyomo.opt.SolverFactory(solver) as opt: self.results = [] # # **NOTE: It would be better to override _presolve on the # base class of this solver as you might be # missing a number of keywords that were passed # into the solve method (e.g., none of the # io_options are getting relayed to the subsolver # here). # self.results.append(opt.solve(self._instance, tee=self._tee, timelimit=self._timelimit)) # # Transform the result back into the original model # tdata = self._instance._transformation_data['bilevel.linear_dual'] unfixed_cuids = set() # Copy variable values and fix them for vuid in tdata.fixed: for index_, data_ in vuid.find_component_on(self._instance).iteritems(): if not data_.fixed: data_.value = self._instance.find_component(data_).value data_.fixed = True unfixed_cuids.add(ComponentUID(data_)) # Reclassify the SubModel components and resolve for name_ in tdata.submodel: submodel = getattr(self._instance, name_) submodel.activate() dual_submodel = getattr(self._instance, name_+'_dual') dual_submodel.deactivate() pyomo.util.PyomoAPIFactory('pyomo.repn.compute_canonical_repn')({}, model=submodel) self._instance.reclassify_component_type(name_, Block) # use the with block here so that deactivation of the # solver plugin always occurs thereby avoiding memory # leaks caused by plugins! with pyomo.opt.SolverFactory(solver) as opt_inner: # # **NOTE: It would be better to override _presolve on the # base class of this solver as you might be # missing a number of keywords that were passed # into the solve method (e.g., none of the # io_options are getting relayed to the subsolver # here). # self.results.append(opt_inner.solve(self._instance, tee=self._tee, timelimit=self._timelimit, select=None)) self._instance.solutions.select(0, ignore_fixed_vars=True) data_.parent_component().parent_block().reclassify_component_type(name_, SubModel) # Unfix variables for vuid in tdata.fixed: for index_, data_ in vuid.find_component_on(self._instance).iteritems(): if ComponentUID(data_) in unfixed_cuids: data_.fixed = False stop_time = time.time() self.wall_time = stop_time - start_time # Reactivate top level objective for oname, odata in self._instance.component_map(Objective).items(): odata.activate() # # Return the sub-solver return condition value and log # return pyutilib.misc.Bunch(rc=getattr(opt,'_rc', None), log=getattr(opt,'_log',None))
def _apply_solver(self): start_time = time.time() instance = self._instance # Reformulate adjustable variables if not self.options.adjustable: adjustable = 'romodel.adjustable.ldr' else: adjustable = self.options.adjustable xfrm = TransformationFactory(adjustable) xfrm.apply_to(instance) # Add cutting plane generators xfrm = TransformationFactory('romodel.generators') xfrm.apply_to(instance) tdata = instance._transformation_data['romodel.generators'] generators = tdata.generators print("Adding {} cutting plane generators.".format(len(generators))) instance.transformation_time = time.time() - start_time # Need to set this up for main and sub solver if not self.options.solver: # Use glpk instead solver = 'gurobi' else: solver = self.options.solver if not self.options.max_iter: max_iter = 300 else: max_iter = self.options.max_iter if not self.options.subsolver: subsolver = solver else: subsolver = self.options.subsolver self.options.setdefault('subsolver_options', self.options) subsolver_options = self.options.pop('subsolver_options') print("Using solver {}\n".format(solver)) with SolverFactory(solver) as opt: self.results = [] feasible = {} # Solve nominal problem print("Solving nominal problem.\n") opt.options = self.options results = opt.solve(instance, tee=self._tee, timelimit=self._timelimit) # Add initial cut to check feasibility for g in generators: feasible[g.name] = g.add_cut(solver=subsolver, options=subsolver_options) feas, total = sum(feasible.values()), len(feasible) print("{0}/{1} constraints robustly feasible. " "Add cuts and resolve.".format(feas, total)) # Keep adding cuts until feasible n_iter = 1 while (not all(feasible.values())) and (n_iter < max_iter): if (results.solver.termination_condition is not TerminationCondition.optimal): break results = opt.solve(instance, tee=self._tee, timelimit=self._timelimit) for g in generators: feasible[g.name] = g.add_cut(solver=subsolver, options=subsolver_options) self.results.append(results) n_iter += 1 feas, total = sum(feasible.values()), len(feasible) print("{0}/{1} constraints robustly feasible. " "Add cuts and resolve.".format(feas, total)) if all(feasible.values()): print("\nAll constraints robustly feasible after {} " "iterations.".format(n_iter)) else: print("\nEnding after reaching max_iter={} iterations. " "Solution is not robustly feasible".format(max_iter)) self.termination_condition = results.solver.termination_condition stop_time = time.time() self.wall_time = stop_time - start_time self.results_obj = self._setup_results_obj() # # Return the sub-solver return condition value and log # return pyutilib.misc.Bunch(rc=getattr(opt, '_rc', None), log=getattr(opt, '_log', None))