PyROS causes Python to crash when solving a model with uncertainty set constrained to be a single value.
In running my PyROS models, I occasionally get an error that there was no feasible solution found. Even for problems to which I know there is a feasible solution.
Of course, when I fix the parameters to be equal to the feasible solution that is known to exist, and thus remove them from the set of uncertain parameters - it finds the optimal/feasible solution with ease.
However, when these parameters are made to be uncertain again, by creating an uncertainty set such that it includes only the nominal value for the uncertain parameters, then it causes PyROS/Python to crash.
Compare the two examples of runnable code:
## Feasible solution clearly exists, because when we make the uncertain parameters to be certain, it finds the solution
# === Required import ===
import pyomo.kernel as pmo
import numpy as np
import pyomo.environ as pe
import pyomo.contrib.pyros as pyros
# === Instantiate the PyROS solver object ===
pyros_solver = pe.SolverFactory("pyros")
def d_init(m, ix):
if ix == 19:
return 1
return 0
def t_init(m, i):
t = 0.5*np.ones((1,m.n))
return t[0,i]
# === Construct the Pyomo model object ===
m = pe.ConcreteModel()
n = m.n = 3
Q = m.Q = 20
N = m.N = 2
# === Define continuous variables ===
m.del_component('L')
m.add_component('L', pe.Var(range(n), range(n*Q*N), within=pe.Reals))
# === Define parameters ===
m.t = pe.Param(range(n), initialize=t_init, mutable=True)
m.d = pe.Param(range(Q), initialize=d_init, mutable=True)
# === Specify the objective function ===
m.del_component('objective')
m.add_component('objective', pe.Objective(expr=0))
S=2
M=1
W=5
# === Specify the constraints ===
m.del_component('c1')
m.add_component('c1', pe.Constraint(expr= 0 <= S*m.t[0] + W*m.d[0] + m.d[1]*M*m.L[0,1]*m.t[1]))
results = ipopt_solver.solve(m)
Now look at the example below, where the uncertain parameters are introduced, yet fixed to a single value. This causes Python/PyROS to crash on my machine:
### In the example below, the parameters are made to be uncertain, but fixed to a particular value,...
### ...and this causes PyROS/Python to crash
# === Required import ===
import pyomo.kernel as pmo
import numpy as np
import pyomo.environ as pe
import pyomo.contrib.pyros as pyros
# === Instantiate the PyROS solver object ===
pyros_solver = pe.SolverFactory("pyros")
def d_init(m, ix):
if ix == 19:
return 1
return 0
def t_init(m, i):
t = 0.5*np.ones((1,m.n))
return t[0,i]
# === Construct the Pyomo model object ===
m = pe.ConcreteModel()
n = m.n = 3
Q = m.Q = 20
N = m.N = 2
# === Define continuous variables ===
m.del_component('L')
m.add_component('L', pe.Var(range(n), range(n*Q*N), within=pe.Reals))
# === Define parameters ===
m.t = pe.Param(range(n), initialize=t_init, mutable=True)
m.d = pe.Param(range(Q), initialize=d_init, mutable=True)
# === Specify the objective function ===
m.del_component('objective')
m.add_component('objective', pe.Objective(expr=0))
S=2
M=1
W=5
# === Specify the constraints ===
m.del_component('c1')
m.add_component('c1', pe.Constraint(expr= 0 <= S*m.t[0] + W*m.d[0] + m.d[1]*M*m.L[0,1]*m.t[1]))
# === Specify which parameters are uncertain ===
uncertain_parameters = [m.t, m.d] # We can pass IndexedParams this way to PyROS, or as an expanded list per index
# === Define the pertinent data ===
bounds_t = [(0.5, 0.5)]*pe.value(m.n)
bounds_d = [(0,0)]*pe.value(m.Q)
bounds_d[19] = (1,1)
bounds = bounds_t + bounds_d
# === Construct the desirable uncertainty set ===
box_uncertainty_set = pyros.BoxSet(bounds=bounds)
# === Designate local and global NLP solvers ===
ipopt_solver = pe.SolverFactory('appsi_ipopt')
local_solver = ipopt_solver
global_solver = ipopt_solver
# === Designate which variables correspond to first- and second-stage degrees of freedom ===
first_stage_variables =[m.L]
second_stage_variables = []
# The remaining variables are implicitly designated to be state variables
# === Call PyROS to solve the robust optimization problem ===
results_1 = pyros_solver.solve(model = m,
first_stage_variables = first_stage_variables,
second_stage_variables = second_stage_variables,
uncertain_params = uncertain_parameters,
uncertainty_set = box_uncertainty_set,
local_solver = local_solver,
global_solver = global_solver,
tee=True,
options = {
"objective_focus": pyros.ObjectiveType.worst_case,
"solve_master_globally": True,
"load_solution":False
})
# === Query results ===
time = results_1.time
iterations = results_1.iterations
termination_condition = results_1.pyros_termination_condition
objective = results_1.final_objective_value
# === Print some results ===
single_stage_final_objective = round(objective,-1)
print("Final objective value: %s" % single_stage_final_objective)
print("PyROS termination condition: %s" % termination_condition)
I'm running:
- MacOS Monterey 12.4
- Python 3.7
Are you able to share the traceback printed to your console when you attempt to run the second script?
@makansij I've run the second script independently. It appears that
- your model variables
m.Lare uninitialized when passed to PyROS (in which case, their values are set toNone), - only
m.L[0,1]is included in your model constraint expression(s), and that variable effectively does not participate in the constraint (in either your determinstic problem or the first PyROS master problem) since it only shows up in the termm.d[1] * m.L[0, 1] * m.t[1]---which is identically 0 sincem.d[1]is set to 0.
In fact, if I attempt to solve your deterministic model with SolverFactory("ipopt") independently, then I encounter an exception with the traceback:
ipopt_solver.solve(m, tee=True, load_solutions=False)
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/opt/base/solvers.py", line 570, in solve
self._presolve(*args, **kwds)
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/opt/solver/shellcmd.py", line 209, in _presolve
OptSolver._presolve(self, *args, **kwds)
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/opt/base/solvers.py", line 667, in _presolve
self._convert_problem(args,
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/opt/base/solvers.py", line 718, in _convert_problem
return convert_problem(args,
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/opt/base/convert.py", line 101, in convert_problem
problem_files, symbol_map = converter.apply(*tmp, **tmpkw)
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/solvers/plugins/converter/model.py", line 181, in apply
instance.write(
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/core/base/block.py", line 1808, in write
(filename, smap) = problem_writer(self,
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/repn/plugins/ampl/ampl_.py", line 405, in __call__
symbol_map = self._print_model_NL(
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/repn/plugins/ampl/ampl_.py", line 1280, in _print_model_NL
raise ValueError("No variables appear in the Pyomo model constraints or"
ValueError: No variables appear in the Pyomo model constraints or objective. This is not supported by the NL file interface
However, this traceback does not show up when PyROS attempts to solve the first master problem---possibly due to the fact that PyROS automatically performs an epigraph reformulation of the model objective function in the master problem. in fact, IPOPT reports an optimal solution, but the value of m.L remain unchanged (set to None), which may be problematic during the separation phase. When I run your second script, I encounter the traceback:
Traceback (most recent call last):
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/contrib/pyros/separation_problem_methods.py", line 290, in solve_separation_problem
model_data.master_nominal_scenario_value = value(model_data.master_nominal_scenario.find_component(nom_constraint))
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/core/expr/numvalue.py", line 141, in value
tmp = obj(exception=True)
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/core/base/constraint.py", line 151, in __call__
return value(self.body, exception=exception)
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/core/expr/numvalue.py", line 141, in value
tmp = obj(exception=True)
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/core/expr/numeric_expr.py", line 210, in __call__
return evaluate_expression(self, exception)
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/core/expr/visitor.py", line 893, in evaluate_expression
return visitor.dfs_postorder_stack(exp)
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/core/expr/visitor.py", line 575, in dfs_postorder_stack
flag, value = self.visiting_potential_leaf(_sub)
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/core/expr/visitor.py", line 803, in visiting_potential_leaf
return True, value(node, exception=self.exception)
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/core/expr/numvalue.py", line 143, in value
raise ValueError(
ValueError: No value for uninitialized NumericValue object scenarios[0,0].L[0,1]
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/jasherma/Documents/vim_example/pyros_test_examples/makansij_github_issues/makansij_singleton_box_example.py", line 70, in <module>
results_1 = pyros_solver.solve(model = m,
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/contrib/pyros/pyros.py", line 434, in solve
pyros_soln, final_iter_separation_solns = ROSolver_iterative_solve(model_data, config)
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/contrib/pyros/pyros_algorithm_methods.py", line 255, in ROSolver_iterative_solve
separation_problem_methods.solve_separation_problem(model_data=separation_data, config=config)
File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/contrib/pyros/separation_problem_methods.py", line 292, in solve_separation_problem
raise ValueError("Unable to access nominal scenario value for the constraint " + str(nom_constraint))
ValueError: Unable to access nominal scenario value for the constraint c1
Was this what you encountered?