Skip to content

Commit 5a821ae

Browse files
authored
Merge branch 'main' into feas-infeas
2 parents 9151e93 + 11fa674 commit 5a821ae

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1698
-1598
lines changed

doc/OnlineDocs/explanation/solvers/persistent.rst

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@ Using Persistent Solvers
2424
The first step in using a persistent solver is to create a Pyomo model
2525
as usual.
2626

27-
>>> import pyomo.environ as pe
28-
>>> m = pe.ConcreteModel()
29-
>>> m.x = pe.Var()
30-
>>> m.y = pe.Var()
31-
>>> m.obj = pe.Objective(expr=m.x**2 + m.y**2)
32-
>>> m.c = pe.Constraint(expr=m.y >= -2*m.x + 5)
27+
>>> import pyomo.environ as pyo
28+
>>> m = pyo.ConcreteModel()
29+
>>> m.x = pyo.Var()
30+
>>> m.y = pyo.Var()
31+
>>> m.obj = pyo.Objective(expr=m.x**2 + m.y**2)
32+
>>> m.c = pyo.Constraint(expr=m.y >= -2*m.x + 5)
3333

3434
You can create an instance of a persistent solver through the SolverFactory.
3535

36-
>>> opt = pe.SolverFactory('gurobi_persistent') # doctest: +SKIP
36+
>>> opt = pyo.SolverFactory('gurobi_persistent') # doctest: +SKIP
3737

3838
This returns an instance of :py:class:`GurobiPersistent`. Now we need
3939
to tell the solver about our model.
@@ -48,7 +48,7 @@ variables and constraints. We can now solve the model.
4848
We can also add or remove variables, constraints, blocks, and
4949
objectives. For example,
5050

51-
>>> m.c2 = pe.Constraint(expr=m.y >= m.x) # doctest: +SKIP
51+
>>> m.c2 = pyo.Constraint(expr=m.y >= m.x) # doctest: +SKIP
5252
>>> opt.add_constraint(m.c2) # doctest: +SKIP
5353

5454
This tells the solver to add one new constraint but otherwise leave
@@ -69,29 +69,29 @@ code will run without error, but the solver will have an extra
6969
constraint. The solver will have both y >= -2*x + 5 and y <= x, which
7070
is not what was intended!
7171

72-
>>> m = pe.ConcreteModel() # doctest: +SKIP
73-
>>> m.x = pe.Var() # doctest: +SKIP
74-
>>> m.y = pe.Var() # doctest: +SKIP
75-
>>> m.c = pe.Constraint(expr=m.y >= -2*m.x + 5) # doctest: +SKIP
76-
>>> opt = pe.SolverFactory('gurobi_persistent') # doctest: +SKIP
72+
>>> m = pyo.ConcreteModel() # doctest: +SKIP
73+
>>> m.x = pyo.Var() # doctest: +SKIP
74+
>>> m.y = pyo.Var() # doctest: +SKIP
75+
>>> m.c = pyo.Constraint(expr=m.y >= -2*m.x + 5) # doctest: +SKIP
76+
>>> opt = pyo.SolverFactory('gurobi_persistent') # doctest: +SKIP
7777
>>> opt.set_instance(m) # doctest: +SKIP
7878
>>> # WRONG:
7979
>>> del m.c # doctest: +SKIP
80-
>>> m.c = pe.Constraint(expr=m.y <= m.x) # doctest: +SKIP
80+
>>> m.c = pyo.Constraint(expr=m.y <= m.x) # doctest: +SKIP
8181
>>> opt.add_constraint(m.c) # doctest: +SKIP
8282

8383
The correct way to do this is:
8484

85-
>>> m = pe.ConcreteModel() # doctest: +SKIP
86-
>>> m.x = pe.Var() # doctest: +SKIP
87-
>>> m.y = pe.Var() # doctest: +SKIP
88-
>>> m.c = pe.Constraint(expr=m.y >= -2*m.x + 5) # doctest: +SKIP
89-
>>> opt = pe.SolverFactory('gurobi_persistent') # doctest: +SKIP
85+
>>> m = pyo.ConcreteModel() # doctest: +SKIP
86+
>>> m.x = pyo.Var() # doctest: +SKIP
87+
>>> m.y = pyo.Var() # doctest: +SKIP
88+
>>> m.c = pyo.Constraint(expr=m.y >= -2*m.x + 5) # doctest: +SKIP
89+
>>> opt = pyo.SolverFactory('gurobi_persistent') # doctest: +SKIP
9090
>>> opt.set_instance(m) # doctest: +SKIP
9191
>>> # Correct:
9292
>>> opt.remove_constraint(m.c) # doctest: +SKIP
9393
>>> del m.c # doctest: +SKIP
94-
>>> m.c = pe.Constraint(expr=m.y <= m.x) # doctest: +SKIP
94+
>>> m.c = pyo.Constraint(expr=m.y <= m.x) # doctest: +SKIP
9595
>>> opt.add_constraint(m.c) # doctest: +SKIP
9696

9797
.. warning:: Components removed from a pyomo model must be removed
@@ -100,14 +100,14 @@ The correct way to do this is:
100100
Additionally, unexpected behavior may result if a component is
101101
modified before being removed.
102102

103-
>>> m = pe.ConcreteModel() # doctest: +SKIP
104-
>>> m.b = pe.Block() # doctest: +SKIP
105-
>>> m.b.x = pe.Var() # doctest: +SKIP
106-
>>> m.b.y = pe.Var() # doctest: +SKIP
107-
>>> m.b.c = pe.Constraint(expr=m.b.y >= -2*m.b.x + 5) # doctest: +SKIP
108-
>>> opt = pe.SolverFactory('gurobi_persistent') # doctest: +SKIP
103+
>>> m = pyo.ConcreteModel() # doctest: +SKIP
104+
>>> m.b = pyo.Block() # doctest: +SKIP
105+
>>> m.b.x = pyo.Var() # doctest: +SKIP
106+
>>> m.b.y = pyo.Var() # doctest: +SKIP
107+
>>> m.b.c = pyo.Constraint(expr=m.b.y >= -2*m.b.x + 5) # doctest: +SKIP
108+
>>> opt = pyo.SolverFactory('gurobi_persistent') # doctest: +SKIP
109109
>>> opt.set_instance(m) # doctest: +SKIP
110-
>>> m.b.c2 = pe.Constraint(expr=m.b.y <= m.b.x) # doctest: +SKIP
110+
>>> m.b.c2 = pyo.Constraint(expr=m.b.y <= m.b.x) # doctest: +SKIP
111111
>>> # ERROR: The constraint referenced by m.b.c2 does not
112112
>>> # exist in the solver model.
113113
>>> opt.remove_block(m.b) # doctest: +SKIP
@@ -117,12 +117,12 @@ the solver instance, modify it with Pyomo, and then add it back to the
117117
solver instance. The only exception is with variables. Variables may
118118
be modified and then updated with with solver:
119119

120-
>>> m = pe.ConcreteModel() # doctest: +SKIP
121-
>>> m.x = pe.Var() # doctest: +SKIP
122-
>>> m.y = pe.Var() # doctest: +SKIP
123-
>>> m.obj = pe.Objective(expr=m.x**2 + m.y**2) # doctest: +SKIP
124-
>>> m.c = pe.Constraint(expr=m.y >= -2*m.x + 5) # doctest: +SKIP
125-
>>> opt = pe.SolverFactory('gurobi_persistent') # doctest: +SKIP
120+
>>> m = pyo.ConcreteModel() # doctest: +SKIP
121+
>>> m.x = pyo.Var() # doctest: +SKIP
122+
>>> m.y = pyo.Var() # doctest: +SKIP
123+
>>> m.obj = pyo.Objective(expr=m.x**2 + m.y**2) # doctest: +SKIP
124+
>>> m.c = pyo.Constraint(expr=m.y >= -2*m.x + 5) # doctest: +SKIP
125+
>>> opt = pyo.SolverFactory('gurobi_persistent') # doctest: +SKIP
126126
>>> opt.set_instance(m) # doctest: +SKIP
127127
>>> m.x.setlb(1.0) # doctest: +SKIP
128128
>>> opt.update_var(m.x) # doctest: +SKIP
@@ -160,13 +160,13 @@ Persistent Solver Performance
160160
In order to get the best performance out of the persistent solvers, use the
161161
"save_results" flag:
162162

163-
>>> import pyomo.environ as pe
164-
>>> m = pe.ConcreteModel()
165-
>>> m.x = pe.Var()
166-
>>> m.y = pe.Var()
167-
>>> m.obj = pe.Objective(expr=m.x**2 + m.y**2)
168-
>>> m.c = pe.Constraint(expr=m.y >= -2*m.x + 5)
169-
>>> opt = pe.SolverFactory('gurobi_persistent') # doctest: +SKIP
163+
>>> import pyomo.environ as pyo
164+
>>> m = pyo.ConcreteModel()
165+
>>> m.x = pyo.Var()
166+
>>> m.y = pyo.Var()
167+
>>> m.obj = pyo.Objective(expr=m.x**2 + m.y**2)
168+
>>> m.c = pyo.Constraint(expr=m.y >= -2*m.x + 5)
169+
>>> opt = pyo.SolverFactory('gurobi_persistent') # doctest: +SKIP
170170
>>> opt.set_instance(m) # doctest: +SKIP
171171
>>> results = opt.solve(save_results=False) # doctest: +SKIP
172172

doc/OnlineDocs/explanation/solvers/pynumero/tutorial.nlp_interfaces.rst

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Relevant imports
1010
.. doctest::
1111
:skipif: not numpy_available or not scipy_available or not asl_available
1212

13-
>>> import pyomo.environ as pe
13+
>>> import pyomo.environ as pyo
1414
>>> from pyomo.contrib.pynumero.interfaces.pyomo_nlp import PyomoNLP
1515
>>> import numpy as np
1616

@@ -19,12 +19,12 @@ Create a Pyomo model
1919
.. doctest::
2020
:skipif: not numpy_available or not scipy_available or not asl_available
2121

22-
>>> m = pe.ConcreteModel()
23-
>>> m.x = pe.Var(bounds=(-5, None))
24-
>>> m.y = pe.Var(initialize=2.5)
25-
>>> m.obj = pe.Objective(expr=m.x**2 + m.y**2)
26-
>>> m.c1 = pe.Constraint(expr=m.y == (m.x - 1)**2)
27-
>>> m.c2 = pe.Constraint(expr=m.y >= pe.exp(m.x))
22+
>>> m = pyo.ConcreteModel()
23+
>>> m.x = pyo.Var(bounds=(-5, None))
24+
>>> m.y = pyo.Var(initialize=2.5)
25+
>>> m.obj = pyo.Objective(expr=m.x**2 + m.y**2)
26+
>>> m.c1 = pyo.Constraint(expr=m.y == (m.x - 1)**2)
27+
>>> m.c2 = pyo.Constraint(expr=m.y >= pyo.exp(m.x))
2828

2929
Create a :py:class:`pyomo.contrib.pynumero.interfaces.pyomo_nlp.PyomoNLP` instance
3030

pyomo/common/log.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,8 @@ def redirect_streams(self, redirects):
415415
"""
416416
found = 0
417417
logger = self._logger
418+
while isinstance(logger, logging.LoggerAdapter):
419+
logger = logger.logger
418420
while logger:
419421
for handler in logger.handlers:
420422
found += 1

pyomo/common/tests/test_log.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,18 @@ def test_log_stream(self):
550550
# Exiting the context manager flushes the LogStream
551551
self.assertEqual(OUT.getvalue(), "INFO: line 1\nINFO: line 2\n")
552552

553+
def test_loggerAdapter(self):
554+
class Adapter(logging.LoggerAdapter):
555+
def process(self, msg, kwargs):
556+
return '[%s] %s' % (self.extra['foo'], msg), kwargs
557+
558+
adapter = Adapter(logging.getLogger('pyomo'), {"foo": 42})
559+
ls = LogStream(logging.INFO, adapter)
560+
LI = LoggingIntercept(level=logging.INFO, formatter=pyomo_formatter)
561+
with LI as OUT:
562+
ls.write("hello, world\n")
563+
self.assertEqual(OUT.getvalue(), "INFO: [42] hello, world\n")
564+
553565

554566
class TestPreformatted(unittest.TestCase):
555567
def test_preformatted_api(self):

pyomo/common/tests/test_tee.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,80 @@ def test_capture_fd_to_logger(self):
422422
finally:
423423
logger.propagate, logger.handlers = orig
424424

425+
def test_capture_to_logger_adapter(self):
426+
class Adapter(logging.LoggerAdapter):
427+
def process(self, msg, kwargs):
428+
return '[%s] %s' % (self.extra['foo'], msg), kwargs
429+
430+
logger = logging.getLogger('_pyomo_no_logger')
431+
adapter = Adapter(logger, {"foo": 42})
432+
lstream = LogStream(logging.WARNING, adapter)
433+
orig = logger.propagate, logger.handlers
434+
try:
435+
logger.propagate = False
436+
logger.handlers = []
437+
with LoggingIntercept(module='_pyomo_no_logger') as LOG:
438+
with tee.capture_output(lstream, capture_fd=False):
439+
sys.stderr.write("hi!\n")
440+
sys.stderr.flush()
441+
self.assertEqual(LOG.getvalue(), "[42] hi!\n")
442+
443+
# test that we handle the lastResort logger correctly
444+
_lastResort = logging.lastResort
445+
with tee.capture_output() as OUT:
446+
with tee.capture_output(lstream, capture_fd=False):
447+
self.assertIsNot(_lastResort, logging.lastResort)
448+
sys.stderr.write("hi?\n")
449+
self.assertEqual(OUT.getvalue(), "[42] hi?\n")
450+
451+
# test that we allow redirect-to-logger out
452+
with tee.capture_output() as OUT:
453+
logger.addHandler(logging.NullHandler())
454+
logger.addHandler(logging.StreamHandler(sys.stderr))
455+
with tee.capture_output(lstream, capture_fd=False):
456+
sys.stderr.write("hi.\n")
457+
self.assertEqual(OUT.getvalue(), "[42] hi.\n")
458+
logger.handlers.clear()
459+
finally:
460+
logger.propagate, logger.handlers = orig
461+
462+
def test_capture_fd_to_logger_adapter(self):
463+
class Adapter(logging.LoggerAdapter):
464+
def process(self, msg, kwargs):
465+
return '[%s] %s' % (self.extra['foo'], msg), kwargs
466+
467+
logger = logging.getLogger('_pyomo_no_logger')
468+
adapter = Adapter(logger, {"foo": 42})
469+
lstream = LogStream(logging.WARNING, adapter)
470+
orig = logger.propagate, logger.handlers
471+
try:
472+
logger.propagate = False
473+
logger.handlers = []
474+
with LoggingIntercept(module='_pyomo_no_logger') as LOG:
475+
with tee.capture_output(lstream, capture_fd=True):
476+
sys.stderr.write("hi!\n")
477+
sys.stderr.flush()
478+
self.assertEqual(LOG.getvalue(), "[42] hi!\n")
479+
480+
# test that we handle the lastResort logger correctly
481+
_lastResort = logging.lastResort
482+
with tee.capture_output() as OUT:
483+
with tee.capture_output(lstream, capture_fd=True):
484+
self.assertIsNot(_lastResort, logging.lastResort)
485+
sys.stderr.write("hi?\n")
486+
self.assertEqual(OUT.getvalue(), "[42] hi?\n")
487+
488+
# test that we allow redirect-to-logger out
489+
with tee.capture_output() as OUT:
490+
logger.addHandler(logging.NullHandler())
491+
logger.addHandler(logging.StreamHandler(sys.stderr))
492+
with tee.capture_output(lstream, capture_fd=True):
493+
sys.stderr.write("hi.\n")
494+
self.assertEqual(OUT.getvalue(), "[42] hi.\n")
495+
logger.handlers.clear()
496+
finally:
497+
logger.propagate, logger.handlers = orig
498+
425499
def test_no_fileno_stdout(self):
426500
T = tee.capture_output()
427501
with T:

pyomo/contrib/alternative_solutions/aos_utils.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import numpy.random
2222
from numpy.linalg import norm
2323

24-
import pyomo.environ as pe
24+
import pyomo.environ as pyo
2525
from pyomo.common.modeling import unique_component_name
2626
from pyomo.common.collections import ComponentSet
2727
import pyomo.util.vars_from_expressions as vfe
@@ -56,7 +56,7 @@ def get_active_objective(model):
5656
assume that there is exactly one active objective.
5757
"""
5858

59-
active_objs = list(model.component_data_objects(pe.Objective, active=True))
59+
active_objs = list(model.component_data_objects(pyo.Objective, active=True))
6060
assert (
6161
len(active_objs) == 1
6262
), "Model has {} active objective functions, exactly one is required.".format(
@@ -68,7 +68,7 @@ def get_active_objective(model):
6868

6969
def _add_aos_block(model, name="_aos_block"):
7070
"""Adds an alternative optimal solution block with a unique name."""
71-
aos_block = pe.Block()
71+
aos_block = pyo.Block()
7272
model.add_component(unique_component_name(model, name), aos_block)
7373
return aos_block
7474

@@ -103,11 +103,11 @@ def _add_objective_constraint(
103103
)
104104

105105
if objective_is_min:
106-
aos_block.optimality_tol_rel = pe.Constraint(
106+
aos_block.optimality_tol_rel = pyo.Constraint(
107107
expr=objective_expr <= objective_cutoff
108108
)
109109
else:
110-
aos_block.optimality_tol_rel = pe.Constraint(
110+
aos_block.optimality_tol_rel = pyo.Constraint(
111111
expr=objective_expr >= objective_cutoff
112112
)
113113
objective_constraints.append(aos_block.optimality_tol_rel)
@@ -116,11 +116,11 @@ def _add_objective_constraint(
116116
objective_cutoff = objective_value + objective_sense * abs_opt_gap
117117

118118
if objective_is_min:
119-
aos_block.optimality_tol_abs = pe.Constraint(
119+
aos_block.optimality_tol_abs = pyo.Constraint(
120120
expr=objective_expr <= objective_cutoff
121121
)
122122
else:
123-
aos_block.optimality_tol_abs = pe.Constraint(
123+
aos_block.optimality_tol_abs = pyo.Constraint(
124124
expr=objective_expr >= objective_cutoff
125125
)
126126
objective_constraints.append(aos_block.optimality_tol_abs)
@@ -219,7 +219,7 @@ def get_model_variables(
219219
220220
"""
221221

222-
component_list = (pe.Objective, pe.Constraint)
222+
component_list = (pyo.Objective, pyo.Constraint)
223223
variable_set = ComponentSet()
224224
if components == None:
225225
var_generator = vfe.get_vars_from_components(
@@ -235,7 +235,7 @@ def get_model_variables(
235235
)
236236
else:
237237
for comp in components:
238-
if hasattr(comp, "ctype") and comp.ctype == pe.Block:
238+
if hasattr(comp, "ctype") and comp.ctype == pyo.Block:
239239
blocks = comp.values() if comp.is_indexed() else (comp,)
240240
for item in blocks:
241241
variables = vfe.get_vars_from_components(
@@ -252,10 +252,10 @@ def get_model_variables(
252252
elif (
253253
isinstance(comp, tuple)
254254
and hasattr(comp[0], "ctype")
255-
and comp[0].ctype == pe.Block
255+
and comp[0].ctype == pyo.Block
256256
):
257257
block = comp[0]
258-
descend_into = pe.Block if comp[1] else False
258+
descend_into = pyo.Block if comp[1] else False
259259
blocks = block.values() if block.is_indexed() else (block,)
260260
for item in blocks:
261261
variables = vfe.get_vars_from_components(
@@ -275,7 +275,7 @@ def get_model_variables(
275275
elif hasattr(comp, "ctype") and comp.ctype in component_list:
276276
constraints = comp.values() if comp.is_indexed() else (comp,)
277277
for item in constraints:
278-
variables = pe.expr.identify_variables(
278+
variables = pyo.expr.identify_variables(
279279
item.expr, include_fixed=include_fixed
280280
)
281281
_filter_model_variables(
@@ -286,7 +286,7 @@ def get_model_variables(
286286
include_integer,
287287
include_fixed,
288288
)
289-
elif hasattr(comp, "ctype") and comp.ctype == pe.Var:
289+
elif hasattr(comp, "ctype") and comp.ctype == pyo.Var:
290290
variables = comp.values() if comp.is_indexed() else (comp,)
291291
_filter_model_variables(
292292
variable_set,

0 commit comments

Comments
 (0)