Skip to content

Commit 2739945

Browse files
authored
Merge pull request Pyomo#3503 from shermanjasonaf/pyros-effective-uncertain-params
Add PyROS Uncertain Parameter Reduction
2 parents 4a90ead + b704f71 commit 2739945

File tree

11 files changed

+782
-127
lines changed

11 files changed

+782
-127
lines changed

doc/OnlineDocs/explanation/solvers/pyros.rst

+28-24
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,9 @@ Observe that the log contains the following information:
924924
are included in parentheses, next to the total numbers
925925
of second-stage variables and state variables, respectively;
926926
note that "adjustable" has been abbreviated as "adj."
927+
The number of truly uncertain parameters detected during preprocessing
928+
is also noted in parentheses
929+
(in which "eff." is an abbreviation for "effective").
927930
* **Iteration log table** (lines 59--69).
928931
Summary information on the problem iterates and subproblem outcomes.
929932
The constituent columns are defined in detail in
@@ -961,21 +964,21 @@ Observe that the log contains the following information:
961964
:linenos:
962965
963966
==============================================================================
964-
PyROS: The Pyomo Robust Optimization Solver, v1.3.4.
965-
Pyomo version: 6.9.0
966-
Commit hash: unknown
967-
Invoked at UTC 2025-02-13T00:00:00.000000
967+
PyROS: The Pyomo Robust Optimization Solver, v1.3.6.
968+
Pyomo version: 6.9.2.dev0 (devel {pyros-effective-uncertain-params})
969+
Commit hash: 41cd797e0
970+
Invoked at UTC 2025-03-13T16:20:31.105320+00:00
968971
969972
Developed by: Natalie M. Isenberg (1), Jason A. F. Sherman (1),
970973
John D. Siirola (2), Chrysanthos E. Gounaris (1)
971974
(1) Carnegie Mellon University, Department of Chemical Engineering
972975
(2) Sandia National Laboratories, Center for Computing Research
973-
976+
974977
The developers gratefully acknowledge support from the U.S. Department
975978
of Energy's Institute for the Design of Advanced Energy Systems (IDAES).
976979
==============================================================================
977980
================================= DISCLAIMER =================================
978-
PyROS is still under development.
981+
PyROS is still under development.
979982
Please provide feedback and/or report any issues by creating a ticket at
980983
https://github.com/Pyomo/pyomo/issues/new/choose
981984
==============================================================================
@@ -1001,7 +1004,7 @@ Observe that the log contains the following information:
10011004
p_robustness={}
10021005
------------------------------------------------------------------------------
10031006
Preprocessing...
1004-
Done preprocessing; required wall time of 0.009s.
1007+
Done preprocessing; required wall time of 0.013s.
10051008
------------------------------------------------------------------------------
10061009
Model Statistics:
10071010
Number of variables : 62
@@ -1010,7 +1013,7 @@ Observe that the log contains the following information:
10101013
Second-stage variables : 6 (6 adj.)
10111014
State variables : 18 (7 adj.)
10121015
Decision rule variables : 30
1013-
Number of uncertain parameters : 4
1016+
Number of uncertain parameters : 4 (4 eff.)
10141017
Number of constraints : 52
10151018
Equality constraints : 24
10161019
Coefficient matching constraints : 0
@@ -1023,33 +1026,34 @@ Observe that the log contains the following information:
10231026
------------------------------------------------------------------------------
10241027
Itn Objective 1-Stg Shift 2-Stg Shift #CViol Max Viol Wall Time (s)
10251028
------------------------------------------------------------------------------
1026-
0 3.5838e+07 - - 5 1.8832e+04 0.412
1027-
1 3.5838e+07 1.2289e-09 1.5886e-12 5 2.8919e+02 0.992
1028-
2 3.6269e+07 3.1647e-01 1.0432e-01 4 2.9020e+02 1.865
1029-
3 3.6285e+07 7.6526e-01 2.2258e-01 0 2.3874e-12g 3.508
1029+
0 3.5838e+07 - - 5 1.8832e+04 0.693
1030+
1 3.5838e+07 1.2289e-09 1.5876e-12 5 3.7762e+04 1.514
1031+
2 3.6129e+07 2.7244e-01 3.6878e-01 3 1.1093e+02 2.486
1032+
3 3.6269e+07 3.7352e-01 4.3227e-01 1 2.7711e+01 3.667
1033+
4 3.6285e+07 7.6526e-01 2.8426e-11 0 4.3364e-05g 6.291
10301034
------------------------------------------------------------------------------
10311035
Robust optimal solution identified.
10321036
------------------------------------------------------------------------------
10331037
Timing breakdown:
1034-
1038+
10351039
Identifier ncalls cumtime percall %
10361040
-----------------------------------------------------------
1037-
main 1 3.509 3.509 100.0
1041+
main 1 6.291 6.291 100.0
10381042
------------------------------------------------------
1039-
dr_polishing 3 0.209 0.070 6.0
1040-
global_separation 27 0.590 0.022 16.8
1041-
local_separation 108 1.569 0.015 44.7
1042-
master 4 0.654 0.163 18.6
1043-
master_feasibility 3 0.083 0.028 2.4
1044-
preprocessing 1 0.009 0.009 0.3
1045-
other n/a 0.394 n/a 11.2
1043+
dr_polishing 4 0.334 0.083 5.3
1044+
global_separation 27 0.954 0.035 15.2
1045+
local_separation 135 3.046 0.023 48.4
1046+
master 5 1.027 0.205 16.3
1047+
master_feasibility 4 0.133 0.033 2.1
1048+
preprocessing 1 0.013 0.013 0.2
1049+
other n/a 0.785 n/a 12.5
10461050
======================================================
10471051
===========================================================
1048-
1052+
10491053
------------------------------------------------------------------------------
10501054
Termination stats:
1051-
Iterations : 4
1052-
Solve time (wall s) : 3.509
1055+
Iterations : 5
1056+
Solve time (wall s) : 6.291
10531057
Final objective value : 3.6285e+07
10541058
Termination condition : pyrosTerminationCondition.robust_optimal
10551059
------------------------------------------------------------------------------

pyomo/contrib/pyros/CHANGELOG.txt

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ PyROS CHANGELOG
33
===============
44

55

6+
-------------------------------------------------------------------------------
7+
PyROS 1.3.6 06 Mar 2025
8+
-------------------------------------------------------------------------------
9+
- Add uncertain parameter reduction to preprocessor and subproblems
10+
11+
612
-------------------------------------------------------------------------------
713
PyROS 1.3.5 13 Feb 2025
814
-------------------------------------------------------------------------------

pyomo/contrib/pyros/pyros.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
)
3434

3535

36-
__version__ = "1.3.5"
36+
__version__ = "1.3.6"
3737

3838

3939
default_pyros_solver_logger = setup_pyros_logger()

pyomo/contrib/pyros/separation_problem_methods.py

+48-14
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@
1515
"""
1616

1717
from itertools import product
18-
import math
1918
import os
2019

2120
from pyomo.common.collections import ComponentSet, ComponentMap
2221
from pyomo.common.dependencies import numpy as np
2322
from pyomo.core.base import Block, Constraint, maximize, Objective, value, Var
2423
from pyomo.opt import TerminationCondition as tc
25-
from pyomo.core.expr import replace_expressions, identify_mutable_parameters
24+
from pyomo.core.expr import (
25+
replace_expressions,
26+
identify_variables,
27+
identify_mutable_parameters,
28+
)
2629

2730
from pyomo.contrib.pyros.solve_data import (
2831
DiscreteSeparationSolveCallResults,
@@ -35,8 +38,6 @@
3538
ABS_CON_CHECK_FEAS_TOL,
3639
call_solver,
3740
check_time_limit_reached,
38-
PARAM_IS_CERTAIN_ABS_TOL,
39-
PARAM_IS_CERTAIN_REL_TOL,
4041
)
4142

4243

@@ -77,17 +78,26 @@ def add_uncertainty_set_constraints(separation_model, config):
7778
for auxvar, auxval in zip(aux_vars, aux_var_vals):
7879
auxvar.set_value(auxval)
7980

80-
# preprocess uncertain parameters which have been fixed by bounds
81-
# in order to simplify the separation problems
82-
for param_var, nomval in zip(param_var_list, config.nominal_uncertain_param_vals):
83-
bounds_close = math.isclose(
84-
a=param_var.lb,
85-
b=param_var.ub,
86-
rel_tol=PARAM_IS_CERTAIN_REL_TOL,
87-
abs_tol=PARAM_IS_CERTAIN_ABS_TOL,
88-
)
89-
if bounds_close:
81+
# fix the effectively certain parameters
82+
param_val_enum_zip = enumerate(
83+
zip(param_var_list, config.nominal_uncertain_param_vals)
84+
)
85+
fixed_param_var_set = ComponentSet()
86+
for idx, (param_var, nomval) in param_val_enum_zip:
87+
if idx not in separation_model.effective_uncertain_dimensions:
9088
param_var.fix(nomval)
89+
fixed_param_var_set.add(param_var)
90+
91+
# deactivate constraints that depend on only the
92+
# effective certain parameters
93+
separation_model.uncertainty.certain_param_var_cons = []
94+
for con in uncertainty_cons:
95+
unfixed_param_vars_in_con = (
96+
ComponentSet(identify_variables(con.expr)) - fixed_param_var_set
97+
)
98+
if not unfixed_param_vars_in_con:
99+
con.deactivate()
100+
separation_model.uncertainty.certain_param_var_cons.append(con)
91101

92102

93103
def construct_separation_problem(model_data):
@@ -889,6 +899,30 @@ def eval_master_violation(scenario_idx):
889899
f"{con.name!r} by more than {tol} ({lslack=}, {uslack=})"
890900
)
891901

902+
for con in sep_model.uncertainty.certain_param_var_cons:
903+
trivially_infeasible = (
904+
con.lslack() < -ABS_CON_CHECK_FEAS_TOL
905+
or con.uslack() < -ABS_CON_CHECK_FEAS_TOL
906+
)
907+
if trivially_infeasible:
908+
# this should never happen in the context of a full solve,
909+
# since the certain parameters should be at their
910+
# nominal values, and the nominal point was already
911+
# confirmed to be a member of the set
912+
config.progress_logger.error(
913+
f"Uncertainty set "
914+
f"(type {type(config.uncertainty_set).__name__}) "
915+
f"constraint {con.name!r}, with expression {con.expr}, "
916+
"is trivially infeasible at the parameter realization "
917+
f"{config.nominal_uncertain_param_vals}. "
918+
f"Check implementation of "
919+
f"{config.uncertainty_set.set_as_constraint.__name__}."
920+
)
921+
raise ValueError(
922+
f"Trivial infeasibility detected in the uncertainty set "
923+
f"(type {type(config.uncertainty_set).__name__}) constraints."
924+
)
925+
892926

893927
locally_acceptable = {tc.optimal, tc.locallyOptimal, tc.globallyOptimal}
894928
globally_acceptable = {tc.optimal, tc.globallyOptimal}

0 commit comments

Comments
 (0)