# ____________________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
# Copyright (c) 2008-2026 National Technology and Engineering Solutions of Sandia, LLC
# Under the terms of Contract DE-NA0003525 with National Technology and Engineering
# Solutions of Sandia, LLC, the U.S. Government retains certain rights in this
# software. This software is distributed under the 3-clause BSD License.
# ____________________________________________________________________________________
import time
import pyomo.opt
from pyomo.opt import SolverFactory
from pyomo.core import TransformationFactory
from pyomo.common.collections import Bunch
[docs]
@SolverFactory.register(
'mpec_nlp', doc='MPEC solver that optimizes a nonlinear transformation'
)
class MPEC_Solver1(pyomo.opt.OptSolver):
[docs]
def __init__(self, **kwds):
kwds['type'] = 'mpec_nlp'
pyomo.opt.OptSolver.__init__(self, **kwds)
self._metasolver = True
def _presolve(self, *args, **kwds):
#
# Cache the instance
#
self._instance = args[0]
pyomo.opt.OptSolver._presolve(self, *args, **kwds)
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.set_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_on(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 Bunch(rc=getattr(opt, '_rc', None), log=getattr(opt, '_log', None))
def _postsolve(self):
#
# Create a results object
#
results = pyomo.opt.SolverResults()
#
# SOLVER
#
solv = results.solver
solv.name = self.options.subsolver
solv.wallclock_time = self.wall_time
cpu_ = []
for res in self.results: # pragma:nocover
if not getattr(res.solver, 'cpu_time', None) is None:
cpu_.append(res.solver.cpu_time)
if len(cpu_) > 0: # pragma:nocover
solv.cpu_time = sum(cpu_)
# solv.termination_condition = pyomo.opt.TerminationCondition.maxIterations
#
# PROBLEM
#
self._instance.compute_statistics()
prob = results.problem
prob.name = self._instance.name
prob.number_of_constraints = self._instance.statistics.number_of_constraints
prob.number_of_variables = self._instance.statistics.number_of_variables
prob.number_of_binary_variables = (
self._instance.statistics.number_of_binary_variables
)
prob.number_of_integer_variables = (
self._instance.statistics.number_of_integer_variables
)
prob.number_of_continuous_variables = (
self._instance.statistics.number_of_continuous_variables
)
prob.number_of_objectives = self._instance.statistics.number_of_objectives
#
# SOLUTION(S)
#
self._instance.solutions.store_to(results)
#
# Uncache the instance and return the results
#
self._instance = None
return results