##############################################################################
# Institute for the Design of Advanced Energy Systems Process Systems
# Engineering Framework (IDAES PSE Framework) Copyright (c) 2018, by the
# software owners: The Regents of the University of California, through
# Lawrence Berkeley National Laboratory, National Technology & Engineering
# Solutions of Sandia, LLC, Carnegie Mellon University, West Virginia
# University Research Corporation, et al. All rights reserved.
#
# Please see the files COPYRIGHT.txt and LICENSE.txt for full copyright and
# license information, respectively. Both files are also available online
# at the URL "https://github.com/IDAES/idaes".
##############################################################################
"""
This is a solver options dialog box. It should provide a comprehensive
list of solvers and solver options and allow assigning default solvers for
different purposes.
"""
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import # disable implicit relative imports
__author__ = "John Eslick"
__version__ = "1.0.0"
import os
import warnings
from collections import OrderedDict
try:
from PyQt5 import QtCore
from PyQt5.QtWidgets import QDockWidget, QAbstractItemView, QShortcut, QApplication
from PyQt5 import QtGui
from PyQt5 import uic
except:
try:
from PyQt4 import QtCore
from PyQt4.QtGui import QDockWidget, QAbstractItemView, QShortcut, QApplication
from PyQt4 import QtGui
from PyQt4 import uic
except:
# This lets the file still be imported, but you won't be able to use it
warnings.warn("Cannot import PyQt")
mypath = os.path.dirname(__file__)
try:
_SolverUI, _Solver = uic.loadUiType(os.path.join(mypath, "solve.ui"))
except:
# This lets the file still be imported, but you won't be able to use it
class _SolverUI(object):
pass
class _Solver(object):
pass
def _validate_option(option):
"""
Check that an option value is valid.
"""
if option["dtype"] == "int":
v = int(option["value"])
if option["lb"] is not None and v < option["lb"]:
return (0, "Below lower bound")
elif option["lb"] is not None and v < option["ub"]:
return (0, "Above upper bound")
elif option["valid_set"] is not None and v not in option["valid_set"]:
return (0, "Not in valid set")
elif option["dtype"] == "real":
v = float(option["value"])
if option["lb"] is not None and v < option["lb"]:
return (0, "Below lower bound")
elif option["lb"] is not None and v < option["ub"]:
return (0, "Above upper bound")
elif option["dtype"] == "bool":
v = option["value"]
if v not in [0,1,True,False,"True","true","False","false"]:
return (0, "Not recognized as a boolean")
elif option["dtype"] == "str":
v = option["value"]
if option["valid_set"] is not None and v not in option["valid_set"]:
return (0, "Not in valid set")
return (1, "")
def _to_out_dtype(v, dtype):
"""
Return an option value that can be used to write out solve function call
code in a Jupyter notebook.
"""
if dtype=="bool" and v in ["1", "True", "true", True]:
return "True"
elif dtype=="bool" and v in ["0", "False", "false", False]:
return "False"
elif dtype=="str":
return '"{}"'.format(v)
elif dtype=="int":
return int(v)
elif dtype=="real":
return float(v)
[docs]class SolverOptionSet(object):
"""
This contains a dictionary that has (will have) a comprehensive list of
solvers and their options, documentation, and validation information. This
make it easy to put together a solver option tree view, and provides an
easy way to store solver settings for later use.
"""
def __init__(self):
self.option_sets = OrderedDict()
[docs] def add_option(
self,
solver,
subset,
name,
value=None,
dtype="real",
lb=None,
ub=None,
valid_set=None,
description="",
active=False):
option = {
"value":value,
"dtype":dtype,
"lb":lb,
"ub":ub,
"valid_set":valid_set,
"description":description,
"active":active
}
if solver in self.option_sets:
d = self.option_sets[solver]
else:
d = OrderedDict()
self.option_sets[solver] = d
if subset in d:
d = d[subset]
else:
d[subset] = OrderedDict()
d = d[subset]
d[name] = option
[docs] def get_option(self, solver, name):
for key in self.option_sets[solver]:
if name in self.option_sets[solver][key]:
return self.option_sets[solver][key][name]
return None
[docs] def option_dict(self):
return self.option_sets
[docs] def pyomo_options(self, solver):
o = []
if "Pyomo" in self.option_sets[solver]:
for name in self.option_sets[solver]["Pyomo"]:
val = self.option_sets[solver]['Pyomo'][name]["value"]
active = self.option_sets[solver]['Pyomo'][name]["active"]
dtype = self.option_sets[solver]['Pyomo'][name]["dtype"]
if val is not None and active:
o.append("{}={}".format(name, _to_out_dtype(val, dtype)))
return o
[docs] def options(self, solver):
o = []
for subset in self.option_sets[solver]:
if subset != "Pyomo":
for name in self.option_sets[solver][subset]:
val = self.option_sets[solver][subset][name]["value"]
active = self.option_sets[solver][subset][name]["active"]
if val is not None and active:
o.append("'{}':'{}'".format(name, val))
return o
[docs]class SolveDialog(_Solver, _SolverUI):
model_str = "model"
def __init__(self, parent=None, solver_options=None):
super(SolveDialog, self).__init__(parent=parent)
self.setupUi(self)
if solver_options is None:
self.solver_options = SolverOptionSet()
add_ipopt_options(self.solver_options)
else:
self.solver_options = solver_options
datmodel = SolveOptionDataModel(self, self.solver_options)
self.treeView.setModel(datmodel)
[docs]class SolveOptionDataItem(object):
"""
"""
def __init__(self, name, parent, o):
self.data = o
self.name = name
self.parent = parent
self.children = []
[docs] def add_child(self, name, o):
item = SolveOptionDataItem(name, self, o)
self.children.append(item)
return item
[docs]class SolveOptionDataModel(QtCore.QAbstractItemModel):
def __init__(self, parent, solver_options={}):
super(SolveOptionDataModel, self).__init__(parent)
self.rootItems = []
self.solver_options = solver_options
self.create_tree("ipopt")
[docs] def create_tree(self, solver):
d = self.solver_options.option_dict()[solver]
for subsec in d:
self.rootItems.append(SolveOptionDataItem(name=subsec, parent=None, o=d[subsec]))
for op in d[subsec]:
self.rootItems[-1].add_child(op, d[subsec][op])
[docs] def parent(self, index):
if not index.isValid():
return QtCore.QModelIndex()
item = index.internalPointer()
if item.parent is None:
return QtCore.QModelIndex()
else:
return self.createIndex(0, 0, item.parent)
[docs] def index(self, row, column, parent=QtCore.QModelIndex()):
if not parent.isValid():
return self.createIndex(row, column, self.rootItems[row])
parentItem = parent.internalPointer()
return self.createIndex(row, column, parentItem.children[row])
[docs] def columnCount(self, parent=QtCore.QModelIndex()):
"""
Return the number of columns
"""
return 6
[docs] def rowCount(self, parent=QtCore.QModelIndex()):
if not parent.isValid():
return len(self.rootItems)
return len(parent.internalPointer().children)
[docs] def data(self, index=QtCore.QModelIndex(), role=QtCore.Qt.DisplayRole):
if role==QtCore.Qt.DisplayRole:
if index.column() == 0:
return index.internalPointer().name
elif "value" in index.internalPointer().data:
if index.column() == 1:
return index.internalPointer().data["value"]
elif index.column() == 2:
return index.internalPointer().data["dtype"]
elif index.column() == 3:
return index.internalPointer().data["lb"]
elif index.column() == 4:
return index.internalPointer().data["ub"]
elif index.column() == 5:
vs = index.internalPointer().data["valid_set"]
if vs is None:
vs = ""
return "{}".format(vs)
elif role==QtCore.Qt.CheckStateRole:
if index.column() == 0 and index.internalPointer() not in self.rootItems:
return index.internalPointer().data["active"]
elif role==QtCore.Qt.ToolTipRole:
if index.column() == 0:
return index.internalPointer().data["description"]
else:
return
[docs] def setData(self, index, value, role=QtCore.Qt.EditRole):
if role==QtCore.Qt.EditRole:
index.internalPointer().data["value"] = value
index.internalPointer().data["active"] = True
elif role==QtCore.Qt.CheckStateRole:
index.internalPointer().data["active"] = not\
index.internalPointer().data["active"]
return 1
[docs] def flags(self, index=QtCore.QModelIndex()):
if index.column() == 0 and index.internalPointer() not in self.rootItems:
return(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable |
QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEditable )
elif index.column() == 1 and index.internalPointer() not in self.rootItems:
return(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable |
QtCore.Qt.ItemIsEditable)
else:
return(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
[docs]def add_ipopt_options(options):
s = "ipopt"
sec = "Pyomo"
options.add_option(s, sec, "tee", value=False, dtype="bool",
description="Print solver messages")
options.add_option(s, sec, "symbolic_solver_labels", value=False, dtype="bool",
description=
"Keep row and col files containing variable and constraint labels.")
options.add_option(s, sec, "keepfiles", value=False, dtype="bool",
description="Keep solver input and output files.")
sec = "Output"
options.add_option(s, sec, "print_level", value=5, dtype="int", lb=0, ub=12,
description="Output verbosity level.\n"
"Sets the default verbosity level for console output. The larger this\n"
"value the more detailed is the output. The valid range for this integer\n"
"option is 0 <= print_level <= 12 and its default value is 5.")
options.add_option(s, sec, "print_user_options", dtype="str", value="no",
valid_set=("yes", "no"), description='Print all options set by the user.\n'
'If selected, the algorithm will print the list of all options set by\n'
'the user including their values and whether they have been used.\n'
'In some cases this information might be incorrect, due to the internal\n'
'program flow. The default value for this string option is "no".\n'
'\nPossible values:\nno: don\'t print options\nyes: print options')
options.add_option(s, sec, "print_options_documentation", dtype="str", valid_set=("yes", "no"))
options.add_option(s, sec, "print_frequency_iter", dtype="int", lb=1)
options.add_option(s, sec, "print_frequency_time", dtype="real", lb=1)
options.add_option(s, sec, "output_file", dtype="str")
options.add_option(s, sec, "file_print_level", dtype="int", lb=0, ub=12)
options.add_option(s, sec, "option_file_name", dtype="str")
options.add_option(s, sec, "print_info_string", dtype="str", valid_set=("yes", "no"))
options.add_option(s, sec, "inf_pr_output", dtype="str", valid_set=("internal", "original"))
options.add_option(s, sec, "print_timing_statistics", dtype="str", valid_set=("yes", "no"))
sec = "Termination"
options.add_option(s, sec, "tol", dtype="real", lb=0)
options.add_option(s, sec, "max_iter", dtype="int", lb=0)
options.add_option(s, sec, "max_cpu_time", dtype="real", lb=0)
options.add_option(s, sec, "dual_inf_tol", dtype="real", lb=0)
options.add_option(s, sec, "constr_viol_tol", dtype="real", lb=0)
options.add_option(s, sec, "compl_inf_tol", dtype="real", lb=0)
options.add_option(s, sec, "acceptable_tol", dtype="real", lb=0)
options.add_option(s, sec, "acceptable_iter", dtype="int", lb=0)
options.add_option(s, sec, "acceptable_constr_viol_tol", dtype="real", lb=0)
options.add_option(s, sec, "acceptable_dual_inf_tol", dtype="real", lb=0)
options.add_option(s, sec, "acceptable_compl_inf_tol", dtype="real", lb=0)
options.add_option(s, sec, "acceptable_obj_change_tol", dtype="real", lb=0)
options.add_option(s, sec, "diverging_iterates_tol", dtype="real", lb=0)
sec="NLP Scaling"
options.add_option(s, sec, "obj_scaling_factor")
options.add_option(s, sec, "nlp_scaling_method", dtype="str",
valid_set=("none", "user-scaling", "gradient-based", "equilibration-based"))
options.add_option(s, sec, "nlp_scaling_max_gradient", lb=0)
options.add_option(s, sec, "nlp_scaling_min_value", lb=0)
sec = "NLP"
options.add_option(s, sec, "bound_relax_factor", lb=0)
options.add_option(s, sec, "honor_original_bounds", dtype="str",
valid_set=("yes", "no"))
options.add_option(s, sec, "check_derivatives_for_naninf", dtype="str",
valid_set=("yes", "no"))
options.add_option(s, sec, "nlp_lower_bound_inf")
options.add_option(s, sec, "nlp_upper_bound_inf")
options.add_option(s, sec, "fixed_variable_treatment", dtype="str",
valid_set=("make_parameter", "make_constraint", "relax_bounds"))
options.add_option(s, sec, "jac_c_constant", dtype="str",
valid_set=("yes", "no"))
options.add_option(s, sec, "jac_d_constant", dtype="str",
valid_set=("yes", "no"))
options.add_option(s, sec, "hessian_constant", dtype="str",
valid_set=("yes", "no"))
sec = "Initialization"
options.add_option(s, sec, "bound_frac", lb=0, ub=0.5)
options.add_option(s, sec, "bound_push", lb=0)
options.add_option(s, sec, "slack_bound_frac", lb=0, ub=0.5)
options.add_option(s, sec, "slack_bound_push", lb=0)
options.add_option(s, sec, "bound_mult_init_val", lb=0)
options.add_option(s, sec, "constr_mult_init_max", lb=0)
options.add_option(s, sec, "bound_mult_init_method", dtype="str",
valid_set=("constant", "mu-based"))
sec="Barrier Parameter"
options.add_option(s, sec, "mehrotra_algorithm", dtype="str",
valid_set=("yes","no"))
options.add_option(s, sec, "mu_strategy", dtype="str",
valid_set=("monotone","adaptive"))
options.add_option(s, sec, "mu_oracle", dtype="str",
valid_set=("probing","loqo","quality_function"))
options.add_option(s, sec, "quality_function_max_section_steps", dtype="int",
lb=0)
options.add_option(s, sec, "fixed_mu_oracle", dtype="str",
valid_set=("probing","loqo","quality_function","average_compl"))
options.add_option(s, sec, "adaptive_mu_globalization", dtype="str",
valid_set=("kkt-error", "obj-constr-filter", "never-monotone-mode"))
options.add_option(s, sec, "mu_init", lb=0)
options.add_option(s, sec, "mu_max_fact", lb=0)
options.add_option(s, sec, "mu_max", lb=0)
options.add_option(s, sec, "mu_min", lb=0)
options.add_option(s, sec, "mu_target", lb=0)
options.add_option(s, sec, "barrier_tol_factor", lb=0)
options.add_option(s, sec, "mu_linear_decrease_factor", lb=0, ub=1)
options.add_option(s, sec, "mu_superlinear_decrease_power", lb=1, ub=2)
sec="Multiplier Updates"
options.add_option(s, sec, "alpha_for_y")
options.add_option(s, sec, "alpha_for_y_tol")
options.add_option(s, sec, "recalc_y")
options.add_option(s, sec, "recalc_y_feas_tol")
sec="Line Search"
options.add_option(s, sec, "max_soc")
options.add_option(s, sec, "watchdog_shortened_iter_trigger")
options.add_option(s, sec, "watchdog_trial_iter_max")
options.add_option(s, sec, "accept_every_trial_step")
options.add_option(s, sec, "corrector_type")
options.add_option(s, sec, "soc_method")
sec="Warm Start"
options.add_option(s, sec, "warm_start_init_point")
options.add_option(s, sec, "warm_start_bound_push")
options.add_option(s, sec, "warm_start_bound_frac")
options.add_option(s, sec, "warm_start_slack_bound_frac")
options.add_option(s, sec, "warm_start_slack_bound_push")
options.add_option(s, sec, "warm_start_mult_bound_push")
options.add_option(s, sec, "warm_start_mult_init_max")
sec="Restoration Phase"
options.add_option(s, sec, "expect_infeasible_problem")
options.add_option(s, sec, "expect_infeasible_problem_ctol")
options.add_option(s, sec, "expect_infeasible_problem_ytol")
options.add_option(s, sec, "start_with_resto")
options.add_option(s, sec, "soft_resto_pderror_reduction_factor")
options.add_option(s, sec, "required_infeasibility_reduction")
options.add_option(s, sec, "bound_mult_reset_threshold")
options.add_option(s, sec, "constr_mult_reset_threshold")
options.add_option(s, sec, "evaluate_orig_obj_at_resto_trial")
sec="Linear Solver"
options.add_option(s, sec, "linear_solver")
options.add_option(s, sec, "linear_system_scaling")
options.add_option(s, sec, "linear_scaling_on_demand")
options.add_option(s, sec, "max_refinement_steps")
options.add_option(s, sec, "min_refinement_steps")
options.add_option(s, sec, "neg_curv_test_reg")
options.add_option(s, sec, "neg_curv_test_tol")
sec="Hessian Perturbation"
options.add_option(s, sec, "max_hessian_perturbation")
options.add_option(s, sec, "min_hessian_perturbation")
options.add_option(s, sec, "first_hessian_perturbation")
options.add_option(s, sec, "perturb_inc_fact_first")
options.add_option(s, sec, "perturb_inc_fact")
options.add_option(s, sec, "perturb_dec_fact")
options.add_option(s, sec, "jacobian_regularization_value")
sec="Quasi-Newton"
options.add_option(s, sec, "hessian_approximation")
options.add_option(s, sec, "limited_memory_update_type")
options.add_option(s, sec, "limited_memory_max_history")
options.add_option(s, sec, "limited_memory_max_skipping")
options.add_option(s, sec, "limited_memory_initialization")
options.add_option(s, sec, "limited_memory_init_val")
options.add_option(s, sec, "limited_memory_init_val_max")
options.add_option(s, sec, "limited_memory_init_val_min")
options.add_option(s, sec, "limited_memory_special_for_resto")
sec="Derivative Test"
options.add_option(s, sec, "derivative_test")
options.add_option(s, sec, "derivative_test_perturbation")
options.add_option(s, sec, "derivative_test_tol")
options.add_option(s, sec, "derivative_test_print_all")
options.add_option(s, sec, "derivative_test_first_index")
options.add_option(s, sec, "point_perturbation_radius")
sec="MA27 Linear Solver"
options.add_option(s, sec, "ma27_pivtol")
options.add_option(s, sec, "ma27_pivtolmax")
options.add_option(s, sec, "ma27_liw_init_factor")
options.add_option(s, sec, "ma27_la_init_factor")
options.add_option(s, sec, "ma27_meminc_factor")
sec="MA57 Linear Solver"
options.add_option(s, sec, "ma57_pivtol")
options.add_option(s, sec, "ma57_pivtolmax")
options.add_option(s, sec, "ma57_pre_alloc")
options.add_option(s, sec, "ma57_pivot_order")
options.add_option(s, sec, "ma57_automatic_scaling")
options.add_option(s, sec, "ma57_block_size")
options.add_option(s, sec, "ma57_node_amalgamation")
options.add_option(s, sec, "ma57_small_pivot_flag")
sec="MUMPS Linear Solver"
options.add_option(s, sec, "mumps_pivtol")
options.add_option(s, sec, "mumps_pivtolmax")
options.add_option(s, sec, "mumps_mem_percent")
options.add_option(s, sec, "mumps_permuting_scaling")
options.add_option(s, sec, "mumps_pivot_order")
options.add_option(s, sec, "mumps_scaling")