From 11eaed9163b1a018bbb5ff2713d3ced6975dd029 Mon Sep 17 00:00:00 2001 From: jasherma Date: Thu, 4 Jun 2026 18:53:01 -0400 Subject: [PATCH 1/6] Tweak `CardinalitySet` class documentation --- pyomo/contrib/pyros/uncertainty_sets.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pyomo/contrib/pyros/uncertainty_sets.py b/pyomo/contrib/pyros/uncertainty_sets.py index 33e68a53859..a62bd8715e2 100644 --- a/pyomo/contrib/pyros/uncertainty_sets.py +++ b/pyomo/contrib/pyros/uncertainty_sets.py @@ -1475,16 +1475,16 @@ class CardinalitySet(UncertaintySet): origin : (N,) array_like Origin of the set (e.g., nominal uncertain parameter values). positive_deviation : (N,) array_like - Upper bounds for absolute values of the positive coordinate - deviations from the origin. + Maximal absolute deviation from the origin in the + positive coordinate direction. gamma : numeric type Upper bound for the number of coordinates that can simultaneously realize their maximal deviations from the origin. Must be a numerical value ranging from 0 to the set dimension `N`. negative_deviation : (N,) array_like, optional - Upper bounds for absolute values of the negative coordinate - deviations from the origin. + Maximal absolute deviation from the origin in the + negative coordinate direction. If `None` is passed, then this argument is set to an (`N`,) shaped array of zeros. @@ -1538,7 +1538,8 @@ class CardinalitySet(UncertaintySet): \\right\\}, the cardinality-constrained set implicitly defined - in the popular robust optimization work [BS04]_. + in the popular robust optimization work by Bertsimas and Sim + [BS04]_. Examples -------- From 6af87c91b9cd1554bae5d4c9e3b6437c874e71c5 Mon Sep 17 00:00:00 2001 From: jasherma Date: Thu, 4 Jun 2026 18:54:15 -0400 Subject: [PATCH 2/6] Fix date in PyROS changelog --- pyomo/contrib/pyros/CHANGELOG.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyomo/contrib/pyros/CHANGELOG.txt b/pyomo/contrib/pyros/CHANGELOG.txt index 1ebf2bc60ce..def9abd64d1 100644 --- a/pyomo/contrib/pyros/CHANGELOG.txt +++ b/pyomo/contrib/pyros/CHANGELOG.txt @@ -4,7 +4,7 @@ PyROS CHANGELOG ------------------------------------------------------------------------------- -PyROS 1.3.15 12 May 2026 +PyROS 1.3.15 04 Jun 2026 ------------------------------------------------------------------------------- - Extend `CardinalitySet` to allow for negative deviations From 7a0e2ae3595a8c47dd5563fd106f6457f9d27214 Mon Sep 17 00:00:00 2001 From: jasherma Date: Thu, 4 Jun 2026 19:13:16 -0400 Subject: [PATCH 3/6] Update PyROS solver log introductory material --- pyomo/contrib/pyros/pyros.py | 19 +++++++++++-------- pyomo/contrib/pyros/tests/test_grcs.py | 23 +++++++++++------------ 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/pyomo/contrib/pyros/pyros.py b/pyomo/contrib/pyros/pyros.py index 7013ca3fa24..aa425775aef 100644 --- a/pyomo/contrib/pyros/pyros.py +++ b/pyomo/contrib/pyros/pyros.py @@ -194,15 +194,22 @@ def _log_intro(self, logger, **log_kwargs): logger.log( msg=( "of Energy's " - "Institute for the Design of Advanced Energy Systems (IDAES)." + "Institute for the Design of Advanced Energy Systems (IDAES)" + ), + **log_kwargs, + ) + logger.log( + msg=( + "and Carbon Capture Simulation for Industry Impact " + "(CCSI2) projects." ), **log_kwargs, ) logger.log(msg="=" * self._LOG_LINE_LENGTH, **log_kwargs) - def _log_disclaimer(self, logger, **log_kwargs): + def _log_feedback_guidance(self, logger, **log_kwargs): """ - Log PyROS solver disclaimer messages. + Log PyROS solver guidance on providing user feedback. Parameters ---------- @@ -212,10 +219,6 @@ def _log_disclaimer(self, logger, **log_kwargs): Keyword arguments to ``logger.log()`` callable. Should not include `msg`. """ - disclaimer_header = " DISCLAIMER ".center(self._LOG_LINE_LENGTH, "=") - - logger.log(msg=disclaimer_header, **log_kwargs) - logger.log(msg="PyROS is currently under active development. ", **log_kwargs) logger.log( msg=( "Please provide feedback and/or report any issues by creating " @@ -419,7 +422,7 @@ def solve( ) ) self._log_intro(logger=progress_logger, level=logging.INFO) - self._log_disclaimer(logger=progress_logger, level=logging.INFO) + self._log_feedback_guidance(logger=progress_logger, level=logging.INFO) config, user_var_partitioning = self._resolve_and_validate_pyros_args( model, **kwds diff --git a/pyomo/contrib/pyros/tests/test_grcs.py b/pyomo/contrib/pyros/tests/test_grcs.py index 01a8f3b3a17..8b9852c7f7c 100644 --- a/pyomo/contrib/pyros/tests/test_grcs.py +++ b/pyomo/contrib/pyros/tests/test_grcs.py @@ -3979,7 +3979,7 @@ def test_log_intro(self): # check number of lines is as expected self.assertEqual( len(intro_msg_lines), - 14, + 15, msg=( "PyROS solver introductory message does not contain" "the expected number of lines." @@ -3993,16 +3993,17 @@ def test_log_intro(self): # check regex main text self.assertRegex( " ".join(intro_msg_lines[1:-1]), - r"PyROS: The Pyomo Robust Optimization Solver, v.* \(IDAES\)\.", + r"PyROS: The Pyomo Robust Optimization Solver, v.* \(CCSI2\) " + r"projects\.", ) - def test_log_disclaimer(self): + def test_log_feedback_ref(self): """ - Test logging of PyROS solver disclaimer messages. + Test logging of PyROS solver guidance on providing feedback. """ pyros_solver = SolverFactory("pyros") with LoggingIntercept(level=logging.INFO) as LOG: - pyros_solver._log_disclaimer(logger=logger, level=logging.INFO) + pyros_solver._log_feedback_guidance(logger=logger, level=logging.INFO) disclaimer_msgs = LOG.getvalue() @@ -4012,23 +4013,21 @@ def test_log_disclaimer(self): # check number of lines is as expected self.assertEqual( len(disclaimer_msg_lines), - 5, + 3, msg=( - "PyROS solver disclaimer message does not contain" + "PyROS solver disclaimer message does not contain " "the expected number of lines." ), ) # regex first line of disclaimer section - self.assertRegex(disclaimer_msg_lines[0], r"=.* DISCLAIMER .*=") # check last line of disclaimer section - self.assertEqual(disclaimer_msg_lines[-1], "=" * 78) - # check regex main text self.assertRegex( - " ".join(disclaimer_msg_lines[1:-1]), - r"PyROS is currently under active development.*ticket at.*", + " ".join(disclaimer_msg_lines[0:-1]), + r"Please provide feedback.*ticket at.*", ) + self.assertEqual(disclaimer_msg_lines[-1], "=" * 78) class UnavailableSolver: From 2380a2069d703e89ab6cf593267948d9d71e8127 Mon Sep 17 00:00:00 2001 From: jasherma Date: Thu, 4 Jun 2026 19:27:32 -0400 Subject: [PATCH 4/6] Update PyROS solver logging example --- .../explanation/solvers/pyros/solver_log.rst | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/doc/OnlineDocs/explanation/solvers/pyros/solver_log.rst b/doc/OnlineDocs/explanation/solvers/pyros/solver_log.rst index 2459eafed50..2ae7d46f45b 100644 --- a/doc/OnlineDocs/explanation/solvers/pyros/solver_log.rst +++ b/doc/OnlineDocs/explanation/solvers/pyros/solver_log.rst @@ -26,10 +26,10 @@ your console output will, by default, look like this: :linenos: ============================================================================== - PyROS: The Pyomo Robust Optimization Solver, v1.3.11. - Pyomo version: 6.9.5 + PyROS: The Pyomo Robust Optimization Solver, v1.3.15. + Pyomo version: 6.10.2.dev0 Commit hash: unknown - Invoked at UTC 2025-10-18T00:00:00.000000+00:00 + Invoked at UTC 2026-06-05T00:00:00.000000+00:00 Developed by: Natalie M. Isenberg (1), Jason A. F. Sherman (1), John D. Siirola (2), Chrysanthos E. Gounaris (1) @@ -37,17 +37,18 @@ your console output will, by default, look like this: (2) Sandia National Laboratories, Center for Computing Research The developers gratefully acknowledge support from the U.S. Department - of Energy's Institute for the Design of Advanced Energy Systems (IDAES). + of Energy's Institute for the Design of Advanced Energy Systems (IDAES) + and Carbon Capture Simulation for Industry Impact (CCSI2) projects. ============================================================================== - ================================= DISCLAIMER ================================= - PyROS is currently under active development. Please provide feedback and/or report any issues by creating a ticket at https://github.com/Pyomo/pyomo/issues/new/choose ============================================================================== User-provided solver options: + tee=False objective_focus= decision_rule_order=1 solve_master_globally=True + bypass_local_separation=False ------------------------------------------------------------------------------ Model Statistics (before preprocessing): Number of variables : 4 @@ -60,21 +61,23 @@ your console output will, by default, look like this: Inequality constraints : 2 ------------------------------------------------------------------------------ Preprocessing... - Done preprocessing; required wall time of 0.004s. + Done preprocessing; required wall time of 0.003s. ------------------------------------------------------------------------------ Itn Objective 1-Stg Shift 2-Stg Shift #CViol Max Viol Wall Time (s) ------------------------------------------------------------------------------ - 0 5.4079e+03 - - 3 7.9226e+00 0.209 - 1 5.4079e+03 6.0451e-10 1.0717e-10 2 1.0250e-01 0.476 - 2 6.5403e+03 1.0018e-01 7.4564e-03 1 1.0249e-02 0.786 - 3 6.5403e+03 1.9372e-16 2.0321e-05 2 8.7074e-03 1.132 - 4 6.5403e+03 0.0000e+00 2.0311e-05 0 1.2310e-06g 1.956 + 0 5.4079e+03 - - 3 4.6876e+02 0.185 + 1 5.4079e+03 6.0451e-10 1.0717e-10 2 6.1500e+01 0.496 + 2 6.5403e+03 1.0018e-01 7.4564e-03 1 1.7142e-03 0.804 + 3 6.5403e+03 1.9372e-16 3.6832e-06 2 2.7964e-01 1.136 + 4 6.5403e+03 0.0000e+00 3.8115e-06 1 1.7141e-03 1.465 + 5 6.5403e+03 0.0000e+00 8.4872e-03 1 4.7920e-01 1.855 + 6 6.5403e+03 0.0000e+00 2.0736e-04 0 1.3594e-06g 2.756 ------------------------------------------------------------------------------ Robust optimal solution identified. ------------------------------------------------------------------------------ Termination stats: - Iterations : 5 - Solve time (wall s) : 1.956 + Iterations : 7 + Solve time (wall s) : 2.756 Final objective value : 6.5403e+03 Termination condition : pyrosTerminationCondition.robust_optimal ------------------------------------------------------------------------------ @@ -87,32 +90,32 @@ Observe that the log contains the following information (listed in order of appearance): -* **Introductory information and disclaimer** (lines 1--19): +* **Introductory information** (lines 1--18): Includes the version number, author information, (UTC) time at which the solver was invoked, and, if available, information on the local Git branch and commit hash. -* **Summary of solver options** (lines 20--24): Enumeration of +* **Summary of solver options** (lines 19--25): Enumeration of specifications for optional arguments to the solver. -* **Model component statistics** (lines 25--34): +* **Model component statistics** (lines 26--35): Breakdown of component statistics for the user-provided model and variable selection (before preprocessing). -* **Preprocessing information** (lines 35--37): +* **Preprocessing information** (lines 36--38): Wall time required for preprocessing the deterministic model and associated components, i.e., standardizing model components and adding the decision rule variables and equations. -* **Iteration log table** (lines 38--45): +* **Iteration log table** (lines 39--48): Summary information on the problem iterates and subproblem outcomes. The constituent columns are defined in detail in :ref:`the table that follows `. -* **Termination message** (lines 46--47): One-line message briefly summarizing +* **Termination message** (lines 49--50): One-line message briefly summarizing the reason the solver has terminated. -* **Final result** (lines 48--53): +* **Final result** (lines 51--56): A printout of the :class:`~pyomo.contrib.pyros.solve_data.ROSolveResults` object that is finally returned. -* **Exit message** (lines 54--55): Confirmation that the +* **Exit message** (lines 57--58): Confirmation that the solver has been exited properly. The iteration log table is designed to provide, in a concise manner, From 61cb1eeeb5f341a51f1ddff9ae85cb4b2bd4a1db Mon Sep 17 00:00:00 2001 From: jasherma Date: Thu, 4 Jun 2026 19:29:42 -0400 Subject: [PATCH 5/6] Update changelog --- pyomo/contrib/pyros/CHANGELOG.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/pyomo/contrib/pyros/CHANGELOG.txt b/pyomo/contrib/pyros/CHANGELOG.txt index def9abd64d1..58d1e42ebdc 100644 --- a/pyomo/contrib/pyros/CHANGELOG.txt +++ b/pyomo/contrib/pyros/CHANGELOG.txt @@ -7,6 +7,7 @@ PyROS CHANGELOG PyROS 1.3.15 04 Jun 2026 ------------------------------------------------------------------------------- - Extend `CardinalitySet` to allow for negative deviations +- Update PyROS solver output log introductory information ------------------------------------------------------------------------------- From ddce22ae17bbcd231b5cc6c827d4274252ff8832 Mon Sep 17 00:00:00 2001 From: jasherma Date: Thu, 4 Jun 2026 19:41:06 -0400 Subject: [PATCH 6/6] Apply black --- pyomo/contrib/pyros/pyros.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pyomo/contrib/pyros/pyros.py b/pyomo/contrib/pyros/pyros.py index aa425775aef..51a95d52b45 100644 --- a/pyomo/contrib/pyros/pyros.py +++ b/pyomo/contrib/pyros/pyros.py @@ -199,10 +199,7 @@ def _log_intro(self, logger, **log_kwargs): **log_kwargs, ) logger.log( - msg=( - "and Carbon Capture Simulation for Industry Impact " - "(CCSI2) projects." - ), + msg="and Carbon Capture Simulation for Industry Impact (CCSI2) projects.", **log_kwargs, ) logger.log(msg="=" * self._LOG_LINE_LENGTH, **log_kwargs)