Source code for idaes.ui.solve

##############################################################################
# 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 headerData(self, i, orientation, role=QtCore.Qt.DisplayRole): """ Return the column headings for the horizontal header and index numbers for the vertical header. """ col = ["name", "value", "type", "lb", "ub", "valid set"] if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole: return col[i] return None
[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")