1# ___________________________________________________________________________ 2# 3# Pyomo: Python Optimization Modeling Objects 4# Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC 5# Under the terms of Contract DE-NA0003525 with National Technology and 6# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain 7# rights in this software. 8# This software is distributed under the 3-clause BSD License. 9# ___________________________________________________________________________ 10 11from pyomo.core.base.PyomoModel import ConcreteModel 12from pyomo.solvers.plugins.solvers.xpress_direct import XpressDirect 13from pyomo.solvers.plugins.solvers.persistent_solver import PersistentSolver 14from pyomo.core.expr.numvalue import value, is_fixed 15from pyomo.core.expr import current as EXPR 16from pyomo.opt.base import SolverFactory 17import collections 18 19 20@SolverFactory.register('xpress_persistent', doc='Persistent python interface to Xpress') 21class XpressPersistent(PersistentSolver, XpressDirect): 22 """ 23 A class that provides a persistent interface to Xpress. Direct solver interfaces do not use any file io. 24 Rather, they interface directly with the python bindings for the specific solver. Persistent solver interfaces 25 are similar except that they "remember" their model. Thus, persistent solver interfaces allow incremental changes 26 to the solver model (e.g., the gurobi python model or the cplex python model). Note that users are responsible 27 for notifying the persistent solver interfaces when changes are made to the corresponding pyomo model. 28 29 Keyword Arguments 30 ----------------- 31 model: ConcreteModel 32 Passing a model to the constructor is equivalent to calling the set_instance mehtod. 33 type: str 34 String indicating the class type of the solver instance. 35 name: str 36 String representing either the class type of the solver instance or an assigned name. 37 doc: str 38 Documentation for the solver 39 options: dict 40 Dictionary of solver options 41 """ 42 43 def __init__(self, **kwds): 44 kwds['type'] = 'xpress_persistent' 45 XpressDirect.__init__(self, **kwds) 46 47 self._pyomo_model = kwds.pop('model', None) 48 if self._pyomo_model is not None: 49 self.set_instance(self._pyomo_model, **kwds) 50 51 def _remove_constraint(self, solver_con): 52 self._solver_model.delConstraint(solver_con) 53 54 def _remove_sos_constraint(self, solver_sos_con): 55 self._solver_model.delSOS(solver_sos_con) 56 57 def _remove_var(self, solver_var): 58 self._solver_model.delVariable(solver_var) 59 60 def _warm_start(self): 61 XpressDirect._warm_start(self) 62 63 def _xpress_chgcoltype_from_var(self, var): 64 """ 65 This function takes a pyomo variable and returns the appropriate xpress variable type 66 for use in xpress.problem.chgcoltype 67 :param var: pyomo.core.base.var.Var 68 :return: xpress.continuous or xpress.binary or xpress.integer 69 """ 70 if var.is_binary(): 71 vartype = 'B' 72 elif var.is_integer(): 73 vartype = 'I' 74 elif var.is_continuous(): 75 vartype = 'C' 76 else: 77 raise ValueError('Variable domain type is not recognized for {0}'.format(var.domain)) 78 return vartype 79 80 def update_var(self, var): 81 """Update a single variable in the solver's model. 82 83 This will update bounds, fix/unfix the variable as needed, and 84 update the variable type. 85 86 Parameters 87 ---------- 88 var: Var (scalar Var or single _VarData) 89 90 """ 91 # see PR #366 for discussion about handling indexed 92 # objects and keeping compatibility with the 93 # pyomo.kernel objects 94 #if var.is_indexed(): 95 # for child_var in var.values(): 96 # self.update_var(child_var) 97 # return 98 if var not in self._pyomo_var_to_solver_var_map: 99 raise ValueError('The Var provided to update_var needs to be added first: {0}'.format(var)) 100 xpress_var = self._pyomo_var_to_solver_var_map[var] 101 qctype = self._xpress_chgcoltype_from_var(var) 102 lb, ub = self._xpress_lb_ub_from_var(var) 103 104 self._solver_model.chgbounds([xpress_var, xpress_var], ['L', 'U'], [lb, ub]) 105 self._solver_model.chgcoltype([xpress_var], [qctype]) 106 107 def _add_column(self, var, obj_coef, constraints, coefficients): 108 """Add a column to the solver's model 109 110 This will add the Pyomo variable var to the solver's 111 model, and put the coefficients on the associated 112 constraints in the solver model. If the obj_coef is 113 not zero, it will add obj_coef*var to the objective 114 of the solver's model. 115 116 Parameters 117 ---------- 118 var: Var (scalar Var or single _VarData) 119 obj_coef: float 120 constraints: list of solver constraints 121 coefficients: list of coefficients to put on var in the associated constraint 122 """ 123 124 ## set-up add var 125 varname = self._symbol_map.getSymbol(var, self._labeler) 126 vartype = self._xpress_chgcoltype_from_var(var) 127 lb, ub = self._xpress_lb_ub_from_var(var) 128 129 self._solver_model.addcols(objx=[obj_coef], mstart=[0,len(coefficients)], 130 mrwind=constraints, dmatval=coefficients, 131 bdl=[lb], bdu=[ub], names=[varname], 132 types=[vartype]) 133 134 xpress_var = self._solver_model.getVariable( 135 index=self._solver_model.getIndexFromName(type=2, name=varname)) 136 137 self._pyomo_var_to_solver_var_map[var] = xpress_var 138 self._solver_var_to_pyomo_var_map[xpress_var] = var 139 self._referenced_variables[var] = len(coefficients) 140 141 def get_xpress_attribute(self, *args): 142 """ 143 Get xpress atrributes. 144 145 Parameters 146 ---------- 147 control(s): str, strs, list, None 148 The xpress attribute to get. Options include any xpress attribute. 149 Can also be list of xpress controls or None for every atrribute 150 Please see the Xpress documentation for options. 151 152 See the Xpress documentation for xpress.problem.getAttrib for other 153 uses of this function 154 155 Returns 156 ------- 157 control value or dictionary of control values 158 """ 159 return self._solver_model.getAttrib(*args) 160 161 def set_xpress_control(self, *args): 162 """ 163 Set xpress controls. 164 165 Parameters 166 ---------- 167 control: str 168 The xpress control to set. Options include any xpree control. 169 Please see the Xpress documentation for options. 170 val: any 171 The value to set the control to. See Xpress documentation for possible values. 172 173 If one argument, it must be a dictionary with control keys and control values 174 """ 175 self._solver_model.setControl(*args) 176 177 def get_xpress_control(self, *args): 178 """ 179 Get xpress controls. 180 181 Parameters 182 ---------- 183 control(s): str, strs, list, None 184 The xpress control to get. Options include any xpress control. 185 Can also be list of xpress controls or None for every contorl 186 Please see the Xpress documentation for options. 187 188 See the Xpress documentation for xpress.problem.getControl for other 189 uses of this function 190 191 Returns 192 ------- 193 control value or dictionary of control values 194 """ 195 return self._solver_model.getControl(*args) 196 197 def write(self, filename, flags=''): 198 """ 199 Write the model to a file (e.g., a lp file). 200 201 Parameters 202 ---------- 203 filename: str 204 Name of the file to which the model should be written. 205 flags: str 206 Flags for xpress.problem.write 207 """ 208 self._solver_model.write(filename, flags) 209