@@ -2069,6 +2069,94 @@ def test_two_stage_set_nonstatic_dr_robust_opt(self, use_discrete_set, dr_order)
20692069 self .assertAlmostEqual (m .x .value , 2 , places = 4 )
20702070 self .assertAlmostEqual (m .z .value , 2 , places = 4 )
20712071
2072+ @unittest .skipUnless (baron_available , "BARON is not available." )
2073+ def test_pyros_discrete_intersection (self ):
2074+ """
2075+ Test PyROS properly supports intersection set involving
2076+ discrete set.
2077+ """
2078+ m = ConcreteModel ()
2079+ m .q1 = Param (initialize = 0.5 , mutable = True )
2080+ m .q2 = Param (initialize = 0.5 , mutable = True )
2081+ m .x1 = Var (bounds = [0 , 1 ])
2082+ m .x2 = Var (bounds = [0 , 1 ])
2083+ m .obj = Objective (expr = m .x1 + m .x2 )
2084+ m .con1 = Constraint (expr = m .x1 >= m .q1 )
2085+ m .con2 = Constraint (expr = m .x2 >= m .q2 )
2086+ iset = IntersectionSet (
2087+ set1 = BoxSet (bounds = [[0 , 2 ]] * 2 ),
2088+ set2 = DiscreteScenarioSet ([[0 , 0 ], [0.5 , 0.5 ], [1 , 1 ], [3 , 3 ]]),
2089+ )
2090+ res = SolverFactory ("pyros" ).solve (
2091+ model = m ,
2092+ first_stage_variables = [m .x1 , m .x2 ],
2093+ second_stage_variables = [],
2094+ uncertain_params = [m .q1 , m .q2 ],
2095+ uncertainty_set = iset ,
2096+ # note: using BARON instead of IPOPT.
2097+ # when IPOPT is used, this test will fail,
2098+ # as the discrete separation routine does not
2099+ # account for the case where there are no
2100+ # adjustable variables in the model
2101+ # (i.e. separation models without any variables).
2102+ # will be addressed later when the subproblem
2103+ # solve routines are refactored
2104+ local_solver = "baron" ,
2105+ global_solver = "baron" ,
2106+ solve_master_globally = True ,
2107+ objective_focus = "worst_case" ,
2108+ )
2109+ self .assertEqual (
2110+ res .pyros_termination_condition , pyrosTerminationCondition .robust_optimal
2111+ )
2112+ self .assertEqual (res .iterations , 2 )
2113+ # check worst-case optimal solution
2114+ self .assertAlmostEqual (res .final_objective_value , 2 )
2115+ self .assertAlmostEqual (m .x1 .value , 1 )
2116+ self .assertAlmostEqual (m .x2 .value , 1 )
2117+
2118+ @unittest .skipUnless (ipopt_available , "IPOPT is not available." )
2119+ def test_pyros_intersection_aux_vars (self ):
2120+ """
2121+ Test PyROS properly supports intersection set
2122+ in which at least one of the intersected sets
2123+ is defined with auxiliary variables.
2124+ """
2125+ m = ConcreteModel ()
2126+ m .q1 = Param (initialize = 0.5 , mutable = True )
2127+ m .q2 = Param (initialize = 0.5 , mutable = True )
2128+ m .x1 = Var (bounds = [0 , 1 ])
2129+ m .x2 = Var (bounds = [0 , 1 ])
2130+ m .obj = Objective (expr = m .x1 + m .x2 )
2131+ m .con1 = Constraint (expr = m .x1 >= m .q1 )
2132+ m .con2 = Constraint (expr = m .x2 >= m .q2 )
2133+ iset = IntersectionSet (
2134+ set1 = AxisAlignedEllipsoidalSet (center = (0 , 0 ), half_lengths = (1 , 1 )),
2135+ # factor model set requires auxiliary variables
2136+ set2 = FactorModelSet (
2137+ origin = [0 , 0 ], psi_mat = np .eye (2 ), number_of_factors = 2 , beta = 0.5
2138+ ),
2139+ )
2140+ res = SolverFactory ("pyros" ).solve (
2141+ model = m ,
2142+ first_stage_variables = [m .x1 , m .x2 ],
2143+ second_stage_variables = [],
2144+ uncertain_params = [m .q1 , m .q2 ],
2145+ uncertainty_set = iset ,
2146+ local_solver = "ipopt" ,
2147+ global_solver = "ipopt" ,
2148+ solve_master_globally = True ,
2149+ objective_focus = "worst_case" ,
2150+ )
2151+ self .assertEqual (
2152+ res .pyros_termination_condition , pyrosTerminationCondition .robust_optimal
2153+ )
2154+ self .assertEqual (res .iterations , 3 )
2155+ # check worst-case optimal solution
2156+ self .assertAlmostEqual (res .final_objective_value , 2 , places = 5 )
2157+ self .assertAlmostEqual (m .x1 .value , 1 )
2158+ self .assertAlmostEqual (m .x2 .value , 1 )
2159+
20722160
20732161@unittest .skipUnless (ipopt_available , "IPOPT not available." )
20742162class TestPyROSSeparationPriorityOrder (unittest .TestCase ):
0 commit comments