Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/OnlineDocs/explanation/solvers/pyros/uncertainty_sets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ subclasses are enumerated below:
~pyomo.contrib.pyros.uncertainty_sets.BoxSet
~pyomo.contrib.pyros.uncertainty_sets.BudgetSet
~pyomo.contrib.pyros.uncertainty_sets.CardinalitySet
~pyomo.contrib.pyros.uncertainty_sets.CartesianProductSet
~pyomo.contrib.pyros.uncertainty_sets.DiscreteScenarioSet
~pyomo.contrib.pyros.uncertainty_sets.EllipsoidalSet
~pyomo.contrib.pyros.uncertainty_sets.FactorModelSet
Expand Down Expand Up @@ -76,6 +77,9 @@ subclasses are provided below.
* - :class:`~pyomo.contrib.pyros.uncertainty_sets.CardinalitySet`
- :math:`\begin{array}{l} q^{0} \in \mathbb{R}^{n}, \\ \hat{q} \in \mathbb{R}_{+}^{n}, \\ \Gamma \in [0, n] \end{array}`
- :math:`\left\{ q \in \mathbb{R}^{n} \middle| \begin{array}{l} \exists\,\xi \in [0, 1]^n\,:\\ \quad \,q = q^{0} + \hat{q} \circ \xi \\ \quad \displaystyle \sum_{i=1}^{n} \xi_{i} \leq \Gamma \end{array} \right\}`
* - :class:`~pyomo.contrib.pyros.uncertainty_sets.CartesianProductSet`
- :math:`\begin{array}{l} \mathcal{Q}_{1} \subset \mathbb{R}^{n_1}, \\ \mathcal{Q}_{2} \subset \mathbb{R}^{n_2}, \\ \vdots \\ \mathcal{Q}_{m} \subset \mathbb{R}^{n_m} \end{array}`
- :math:`\displaystyle \mathcal{Q}_{1} \times \mathcal{Q}_{2} \times \cdots \times \mathcal{Q}_{m}`
* - :class:`~pyomo.contrib.pyros.uncertainty_sets.DiscreteScenarioSet`
- :math:`q^{1}, q^{2},\dots , q^{S} \in \mathbb{R}^{n}`
- :math:`\{q^{1}, q^{2}, \dots , q^{S}\}`
Expand Down
1 change: 1 addition & 0 deletions pyomo/contrib/pyros/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@
BoxSet,
IntersectionSet,
AxisAlignedEllipsoidalSet,
CartesianProductSet,
)
86 changes: 86 additions & 0 deletions pyomo/contrib/pyros/tests/test_grcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@
_setup_standard_uncertainty_set_constraint_block,
AxisAlignedEllipsoidalSet,
BoxSet,
CardinalitySet,
CartesianProductSet,
DiscreteScenarioSet,
FactorModelSet,
Geometry,
Expand Down Expand Up @@ -460,6 +462,90 @@ def test_two_stg_model_discrete_set(self):
)


@unittest.skipUnless(ipopt_available, "IPOPT is not available.")
class TestPyROSSolveCartesianProductSet(unittest.TestCase):
"""
Test PyROS successfully solves model with cartesian product uncertainty.
"""

def build_model(self):
m = ConcreteModel()
m.q = Param(range(4), initialize=0, mutable=True)
m.x = Var(initialize=0, bounds=(0, 100))
m.obj = Objective(expr=m.x, sense=minimize)
m.con = Constraint(expr=m.x >= sum(m.q.values()))
return m

def test_solve_with_cartesian_product_set(self):
"""
Test solve with cartesian product uncertainty.
"""
m = self.build_model()
cpset = CartesianProductSet(
[
BoxSet([[0, 1]]),
FactorModelSet(
origin=[0, 0], number_of_factors=1, beta=1, psi_mat=[[1], [3]]
),
CardinalitySet(origin=[0], positive_deviation=[0.5], gamma=1),
]
)
results = SolverFactory("pyros").solve(
model=m,
first_stage_variables=[m.x],
second_stage_variables=[],
uncertain_params=m.q,
uncertainty_set=cpset,
local_solver=SolverFactory("ipopt"),
global_solver=SolverFactory("ipopt"),
options={
"objective_focus": ObjectiveType.worst_case,
"solve_master_globally": True,
},
)

# check successful termination
self.assertEqual(
results.pyros_termination_condition,
pyrosTerminationCondition.robust_optimal,
msg="Did not identify robust optimal solution to problem instance.",
)
# need only 2 iterations:
# - first gives nominally optimal x, which is robust infeasible
# - second gives robust optimal x
self.assertEqual(results.iterations, 2)
# final objective is just sum of the parameter values
# that cause maximal violation of the inequality constraint
self.assertAlmostEqual(results.final_objective_value, 5.5, places=6)
self.assertAlmostEqual(m.x.value, 5.5, places=6)

def test_solve_invalid_cartesian_product_set(self):
"""
Test PyROS solver cartesian product set validation failure.
"""
m = self.build_model()
cpset = CartesianProductSet(
[BoxSet([[0, 1]]), DiscreteScenarioSet([(0, 1, 3), (0, 0, 0)])]
)
# exception raised during set validation due to involvement
# of discrete uncertainty in the cartesian product
disc_exc_str = r"CartesianProductSet.*entry.*with a discrete geometry"
with self.assertRaisesRegex(ValueError, disc_exc_str):
SolverFactory("pyros").solve(
model=m,
first_stage_variables=[m.x],
second_stage_variables=[],
uncertain_params=m.q,
uncertainty_set=cpset,
local_solver=SolverFactory("ipopt"),
global_solver=SolverFactory("ipopt"),
options={
"objective_focus": ObjectiveType.worst_case,
"solve_master_globally": True,
},
)


class TestPyROSRobustInfeasible(unittest.TestCase):
@unittest.skipUnless(baron_available, "BARON is not available and licensed")
def test_pyros_robust_infeasible(self):
Expand Down
Loading
Loading