Skip to content

Commit 42b0fcb

Browse files
authored
Merge pull request #3975 from shermanjasonaf/pyros-extend-cardinality-set-2
Modify PyROS uncertainty set documentation and solver output log intro
2 parents 29f2b12 + 068e504 commit 42b0fcb

6 files changed

Lines changed: 170 additions & 98 deletions

File tree

doc/OnlineDocs/explanation/solvers/pyros/solver_log.rst

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,29 @@ your console output will, by default, look like this:
2626
:linenos:
2727
2828
==============================================================================
29-
PyROS: The Pyomo Robust Optimization Solver, v1.3.11.
30-
Pyomo version: 6.9.5
29+
PyROS: The Pyomo Robust Optimization Solver, v1.3.15.
30+
Pyomo version: 6.10.1
3131
Commit hash: unknown
32-
Invoked at UTC 2025-10-18T00:00:00.000000+00:00
32+
Invoked at UTC 2026-06-05T00:00:00.000000+00:00
3333
3434
Developed by: Natalie M. Isenberg (1), Jason A. F. Sherman (1),
3535
John D. Siirola (2), Chrysanthos E. Gounaris (1)
3636
(1) Carnegie Mellon University, Department of Chemical Engineering
3737
(2) Sandia National Laboratories, Center for Computing Research
3838
3939
The developers gratefully acknowledge support from the U.S. Department
40-
of Energy's Institute for the Design of Advanced Energy Systems (IDAES).
40+
of Energy's Institute for the Design of Advanced Energy Systems (IDAES)
41+
and Carbon Capture Simulation for Industry Impact (CCSI2) projects.
4142
==============================================================================
42-
================================= DISCLAIMER =================================
43-
PyROS is currently under active development.
4443
Please provide feedback and/or report any issues by creating a ticket at
4544
https://github.com/Pyomo/pyomo/issues/new/choose
4645
==============================================================================
4746
User-provided solver options:
47+
tee=False
4848
objective_focus=<ObjectiveType.worst_case: 1>
4949
decision_rule_order=1
5050
solve_master_globally=True
51+
bypass_local_separation=False
5152
------------------------------------------------------------------------------
5253
Model Statistics (before preprocessing):
5354
Number of variables : 4
@@ -60,21 +61,23 @@ your console output will, by default, look like this:
6061
Inequality constraints : 2
6162
------------------------------------------------------------------------------
6263
Preprocessing...
63-
Done preprocessing; required wall time of 0.004s.
64+
Done preprocessing; required wall time of 0.003s.
6465
------------------------------------------------------------------------------
6566
Itn Objective 1-Stg Shift 2-Stg Shift #CViol Max Viol Wall Time (s)
6667
------------------------------------------------------------------------------
67-
0 5.4079e+03 - - 3 7.9226e+00 0.209
68-
1 5.4079e+03 6.0451e-10 1.0717e-10 2 1.0250e-01 0.476
69-
2 6.5403e+03 1.0018e-01 7.4564e-03 1 1.0249e-02 0.786
70-
3 6.5403e+03 1.9372e-16 2.0321e-05 2 8.7074e-03 1.132
71-
4 6.5403e+03 0.0000e+00 2.0311e-05 0 1.2310e-06g 1.956
68+
0 5.4079e+03 - - 3 4.6876e+02 0.185
69+
1 5.4079e+03 6.0451e-10 1.0717e-10 2 6.1500e+01 0.496
70+
2 6.5403e+03 1.0018e-01 7.4564e-03 1 1.7142e-03 0.804
71+
3 6.5403e+03 1.9372e-16 3.6832e-06 2 2.7964e-01 1.136
72+
4 6.5403e+03 0.0000e+00 3.8115e-06 1 1.7141e-03 1.465
73+
5 6.5403e+03 0.0000e+00 8.4872e-03 1 4.7920e-01 1.855
74+
6 6.5403e+03 0.0000e+00 2.0736e-04 0 1.3594e-06g 2.756
7275
------------------------------------------------------------------------------
7376
Robust optimal solution identified.
7477
------------------------------------------------------------------------------
7578
Termination stats:
76-
Iterations : 5
77-
Solve time (wall s) : 1.956
79+
Iterations : 7
80+
Solve time (wall s) : 2.756
7881
Final objective value : 6.5403e+03
7982
Termination condition : pyrosTerminationCondition.robust_optimal
8083
------------------------------------------------------------------------------
@@ -87,32 +90,32 @@ Observe that the log contains the following information
8790
(listed in order of appearance):
8891

8992

90-
* **Introductory information and disclaimer** (lines 1--19):
93+
* **Introductory information** (lines 1--18):
9194
Includes the version number, author
9295
information, (UTC) time at which the solver was invoked,
9396
and, if available, information on the local Git branch and
9497
commit hash.
95-
* **Summary of solver options** (lines 20--24): Enumeration of
98+
* **Summary of solver options** (lines 19--25): Enumeration of
9699
specifications for optional arguments to the solver.
97-
* **Model component statistics** (lines 25--34):
100+
* **Model component statistics** (lines 26--35):
98101
Breakdown of component statistics for the user-provided model
99102
and variable selection (before preprocessing).
100-
* **Preprocessing information** (lines 35--37):
103+
* **Preprocessing information** (lines 36--38):
101104
Wall time required for preprocessing
102105
the deterministic model and associated components,
103106
i.e., standardizing model components and adding the decision rule
104107
variables and equations.
105-
* **Iteration log table** (lines 38--45):
108+
* **Iteration log table** (lines 39--48):
106109
Summary information on the problem iterates and subproblem outcomes.
107110
The constituent columns are defined in detail in
108111
:ref:`the table that follows <table-iteration-log-columns>`.
109-
* **Termination message** (lines 46--47): One-line message briefly summarizing
112+
* **Termination message** (lines 49--50): One-line message briefly summarizing
110113
the reason the solver has terminated.
111-
* **Final result** (lines 48--53):
114+
* **Final result** (lines 51--56):
112115
A printout of the
113116
:class:`~pyomo.contrib.pyros.solve_data.ROSolveResults`
114117
object that is finally returned.
115-
* **Exit message** (lines 54--55): Confirmation that the
118+
* **Exit message** (lines 57--58): Confirmation that the
116119
solver has been exited properly.
117120

118121
The iteration log table is designed to provide, in a concise manner,

pyomo/contrib/pyros/CHANGELOG.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ PyROS CHANGELOG
44

55

66
-------------------------------------------------------------------------------
7-
PyROS 1.3.15 12 May 2026
7+
PyROS 1.3.15 04 Jun 2026
88
-------------------------------------------------------------------------------
99
- Extend `CardinalitySet` to allow for negative deviations
10+
- Update PyROS solver output log introductory information
1011

1112

1213
-------------------------------------------------------------------------------

pyomo/contrib/pyros/pyros.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,19 @@ def _log_intro(self, logger, **log_kwargs):
194194
logger.log(
195195
msg=(
196196
"of Energy's "
197-
"Institute for the Design of Advanced Energy Systems (IDAES)."
197+
"Institute for the Design of Advanced Energy Systems (IDAES)"
198198
),
199199
**log_kwargs,
200200
)
201+
logger.log(
202+
msg="and Carbon Capture Simulation for Industry Impact (CCSI2) projects.",
203+
**log_kwargs,
204+
)
201205
logger.log(msg="=" * self._LOG_LINE_LENGTH, **log_kwargs)
202206

203-
def _log_disclaimer(self, logger, **log_kwargs):
207+
def _log_feedback_guidance(self, logger, **log_kwargs):
204208
"""
205-
Log PyROS solver disclaimer messages.
209+
Log PyROS solver guidance on providing user feedback.
206210
207211
Parameters
208212
----------
@@ -212,10 +216,6 @@ def _log_disclaimer(self, logger, **log_kwargs):
212216
Keyword arguments to ``logger.log()`` callable.
213217
Should not include `msg`.
214218
"""
215-
disclaimer_header = " DISCLAIMER ".center(self._LOG_LINE_LENGTH, "=")
216-
217-
logger.log(msg=disclaimer_header, **log_kwargs)
218-
logger.log(msg="PyROS is currently under active development. ", **log_kwargs)
219219
logger.log(
220220
msg=(
221221
"Please provide feedback and/or report any issues by creating "
@@ -419,7 +419,7 @@ def solve(
419419
)
420420
)
421421
self._log_intro(logger=progress_logger, level=logging.INFO)
422-
self._log_disclaimer(logger=progress_logger, level=logging.INFO)
422+
self._log_feedback_guidance(logger=progress_logger, level=logging.INFO)
423423

424424
config, user_var_partitioning = self._resolve_and_validate_pyros_args(
425425
model, **kwds

pyomo/contrib/pyros/tests/test_grcs.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ def test_cardinality_set_solve(self):
277277
m.ineq_con = Constraint(expr=m.x >= m.q[0] + m.q[1] - m.q[2] - m.q[3])
278278

279279
cset = CardinalitySet(
280-
origin=[1] * 4, positive_deviation=[1, 0, 2, 0.5], gamma=2
280+
origin=[1] * 4, gamma=2, positive_deviation=[1, 0, 2, 0.5]
281281
)
282282
res = SolverFactory("pyros").solve(
283283
model=m,
@@ -545,7 +545,7 @@ def test_solve_with_cartesian_product_set(self):
545545
FactorModelSet(
546546
origin=[0, 0], number_of_factors=1, beta=1, psi_mat=[[1], [3]]
547547
),
548-
CardinalitySet(origin=[0], positive_deviation=[0.5], gamma=1),
548+
CardinalitySet(origin=[0], gamma=1, positive_deviation=[0.5]),
549549
]
550550
)
551551
results = SolverFactory("pyros").solve(
@@ -3979,7 +3979,7 @@ def test_log_intro(self):
39793979
# check number of lines is as expected
39803980
self.assertEqual(
39813981
len(intro_msg_lines),
3982-
14,
3982+
15,
39833983
msg=(
39843984
"PyROS solver introductory message does not contain"
39853985
"the expected number of lines."
@@ -3993,16 +3993,17 @@ def test_log_intro(self):
39933993
# check regex main text
39943994
self.assertRegex(
39953995
" ".join(intro_msg_lines[1:-1]),
3996-
r"PyROS: The Pyomo Robust Optimization Solver, v.* \(IDAES\)\.",
3996+
r"PyROS: The Pyomo Robust Optimization Solver, v.* \(CCSI2\) "
3997+
r"projects\.",
39973998
)
39983999

3999-
def test_log_disclaimer(self):
4000+
def test_log_feedback_ref(self):
40004001
"""
4001-
Test logging of PyROS solver disclaimer messages.
4002+
Test logging of PyROS solver guidance on providing feedback.
40024003
"""
40034004
pyros_solver = SolverFactory("pyros")
40044005
with LoggingIntercept(level=logging.INFO) as LOG:
4005-
pyros_solver._log_disclaimer(logger=logger, level=logging.INFO)
4006+
pyros_solver._log_feedback_guidance(logger=logger, level=logging.INFO)
40064007

40074008
disclaimer_msgs = LOG.getvalue()
40084009

@@ -4012,23 +4013,21 @@ def test_log_disclaimer(self):
40124013
# check number of lines is as expected
40134014
self.assertEqual(
40144015
len(disclaimer_msg_lines),
4015-
5,
4016+
3,
40164017
msg=(
4017-
"PyROS solver disclaimer message does not contain"
4018+
"PyROS solver disclaimer message does not contain "
40184019
"the expected number of lines."
40194020
),
40204021
)
40214022

40224023
# regex first line of disclaimer section
4023-
self.assertRegex(disclaimer_msg_lines[0], r"=.* DISCLAIMER .*=")
40244024
# check last line of disclaimer section
4025-
self.assertEqual(disclaimer_msg_lines[-1], "=" * 78)
4026-
40274025
# check regex main text
40284026
self.assertRegex(
4029-
" ".join(disclaimer_msg_lines[1:-1]),
4030-
r"PyROS is currently under active development.*ticket at.*",
4027+
" ".join(disclaimer_msg_lines[0:-1]),
4028+
r"Please provide feedback.*ticket at.*",
40314029
)
4030+
self.assertEqual(disclaimer_msg_lines[-1], "=" * 78)
40324031

40334032

40344033
class UnavailableSolver:

0 commit comments

Comments
 (0)