def dual(self): if self.problem is not None: if self.problem.is_integer: raise ValueError("Dual values are not well-defined for integer problems") return glp_get_row_dual(self.problem.problem, self._index) else: return None
def shadow_prices(self): if self.is_integer: raise ValueError( "Dual values are not well-defined for integer problems") shadow_prices = collections.OrderedDict( (constraint.name, glp_get_row_dual(self.problem, index + 1)) for index, constraint in enumerate(self.constraints)) return shadow_prices
def shadow_prices(self): if self.problem: shadow_prices = collections.OrderedDict() for index, constraint in enumerate(self.constraints): value = glp_get_row_dual(self.problem, index + 1) shadow_prices[constraint.name] = value return shadow_prices else: return None
def getShadowPrices(self, materials): if not self._eqConstBuilt: raise Exception( "Equality constraints not yet built. Finish construction of the problem before accessing dual values." ) self._solve() return np.array([ glp.glp_get_row_dual(self._lp, 1 + self._materialIdxLookup[material]) if material in self._materialIdxLookup else None for material in materials ])
def shadow_prices(self): shadow_prices = collections.OrderedDict() for index, constraint in enumerate(self.constraints): value = glp_get_row_dual(self.problem, index + 1) shadow_prices[constraint.name] = value return shadow_prices
def dual(self): if self.problem is not None: return glp_get_row_dual(self.problem.problem, self._index) else: return None
def _solve(self): import swiglpk as glpk # An alias to the internal problem instance. p = self.int continuous = self.ext.is_continuous() # Select LP solver (Simplex or Interior Point Method). if continuous: if self.ext.options["lp_root_method"] == "interior": interior = True else: # Default to Simplex. interior = False simplex = not interior else: simplex = interior = False # Select appropriate options container. if simplex: options = glpk.glp_smcp() glpk.glp_init_smcp(options) elif interior: options = glpk.glp_iptcp() glpk.glp_init_iptcp(options) else: options = glpk.glp_iocp() glpk.glp_init_iocp(options) # Handle "verbose" option. verbosity = self.verbosity() if verbosity < 0: options.msg_lev = glpk.GLP_MSG_OFF elif verbosity == 0: options.msg_lev = glpk.GLP_MSG_ERR elif verbosity == 1: options.msg_lev = glpk.GLP_MSG_ON elif verbosity >= 2: options.msg_lev = glpk.GLP_MSG_ALL # Handle "tol" option. # Note that GLPK knows three different tolerances for Simplex but none # for the Interior Point Method, while PICOS states that "tol" is meant # only for the IPM. # XXX: The option is unsupported but does not default to None, so we # cannot warn the user. pass # Handle "maxit" option. if not simplex: self._handle_unsupported_option("maxit", "GLPK supports the 'maxit' option only with Simplex.") elif self.ext.options["maxit"] is not None: options.it_lim = int(self.ext.options["maxit"]) # Handle "lp_root_method" option. # Note that the PICOS option is explicitly also meant for the MIP # preprocessing step but GLPK does not support it in that scenario. if not continuous: self._handle_unsupported_option("lp_root_method", "GLPK supports the 'lp_root_method' option only for LPs.") elif self.ext.options["lp_root_method"] is not None: if self.ext.options["lp_root_method"] == "interior": # Handled above. pass elif self.ext.options["lp_root_method"] == "psimplex": assert simplex options.meth = glpk.GLP_PRIMAL elif self.ext.options["lp_root_method"] == "dsimplex": assert simplex options.meth = glpk.GLP_DUAL else: self._handle_bad_option_value("lp_root_method") # Handle "timelimit" option. if interior: self._handle_unsupported_option("timelimit", "GLPK does not support the 'timelimit' option with the " "Interior Point Method.") elif self.ext.options["timelimit"] is not None: options.tm_lim = 1000 * int(self.ext.options["timelimit"]) # Handle "gaplim" option. # Note that the option is silently ignored if passed alongside an LP; # while the solver does not allow us to pass the option in that case, it # is still technically a valid option as every LP is also a MIP. # TODO: Find out if "mip_gap" is really equivalent to "gaplim". if self.ext.options["gaplim"] is not None: if not continuous: options.mip_gap = float(self.ext.options["gaplim"]) # Handle unsupported options. self._handle_unsupported_options( "lp_node_method", "treememory", "nbsol", "hotstart") # TODO: Add GLPK-sepcific options. Candidates are: # For both Simplex and MIPs: # tol_*, out_* # For Simplex: # pricing, r_test, obj_* # For the Interior Point Method: # ord_alg # For MIPs: # *_tech, *_heur, ps_tm_lim, *_cuts, cb_size, binarize # Attempt to solve the problem. with self._header(): with self._stopwatch(): if simplex: # TODO: Support glp_exact. error = glpk.glp_simplex(p, options) elif interior: error = glpk.glp_interior(p, options) else: options.presolve = glpk.GLP_ON error = glpk.glp_intopt(p, options) # Conert error codes to text output. # Note that by printing it above the footer, this output is made to # look like it's coming from GLPK, which is technically wrong but # semantically correct. if error == glpk.GLP_EBADB: self._warn("Unable to start the search, because the initial " "basis specified in the problem object is invalid.") elif error == glpk.GLP_ESING: self._warn("Unable to start the search, because the basis " "matrix corresponding to the initial basis is singular " "within the working precision.") elif error == glpk.GLP_ECOND: self._warn("Unable to start the search, because the basis " "matrix corresponding to the initial basis is " "ill-conditioned.") elif error == glpk.GLP_EBOUND: self._warn("Unable to start the search, because some double-" "bounded variables have incorrect bounds.") elif error == glpk.GLP_EFAIL: self._warn("The search was prematurely terminated due to a " "solver failure.") elif error == glpk.GLP_EOBJLL: self._warn("The search was prematurely terminated, because the " "objective function being maximized has reached its lower " "limit and continues decreasing.") elif error == glpk.GLP_EOBJUL: self._warn("The search was prematurely terminated, because the " "objective function being minimized has reached its upper " "limit and continues increasing.") elif error == glpk.GLP_EITLIM: self._warn("The search was prematurely terminated, because the " "simplex iteration limit has been exceeded.") elif error == glpk.GLP_ETMLIM: self._warn("The search was prematurely terminated, because the " "time limit has been exceeded.") elif error == glpk.GLP_ENOPFS: self._verbose("The LP has no primal feasible solution.") elif error == glpk.GLP_ENODFS: self._verbose("The LP has no dual feasible solution.") elif error != 0: self._warn("GLPK error {:d}.".format(error)) # Retrieve primals. if self.ext.options["noprimals"]: primals = None else: primals = {} for variable in self.ext.variables.values(): value = [] for localIndex, picosIndex \ in enumerate(range(variable.startIndex, variable.endIndex)): glpkIndex = self._picos2glpk_variable_index(picosIndex) if simplex: localValue = glpk.glp_get_col_prim(p, glpkIndex); elif interior: localValue = glpk.glp_ipt_col_prim(p, glpkIndex); else: localValue = glpk.glp_mip_col_val(p, glpkIndex); value.append(localValue) primals[variable.name] = value # Retrieve duals. # XXX: Returns the duals as a flat cvx.matrix to be consistent with # other solvers. This feels incorrect when the constraint was given # as a proper two dimensional matrix. if self.ext.options["noduals"] or not continuous: duals = None else: duals = [] rowOffset = 1 for constraintNum, constraint in enumerate(self.ext.constraints): assert isinstance(constraint, AffineConstraint) numRows = len(constraint) values = [] for localConIndex in range(numRows): glpkConIndex = rowOffset + localConIndex if simplex: localValue = glpk.glp_get_row_dual(p, glpkConIndex); elif interior: localValue = glpk.glp_ipt_row_dual(p, glpkConIndex); else: assert False values.append(localValue) if constraint.is_decreasing(): duals.append(-cvxopt.matrix(values)) else: duals.append(cvxopt.matrix(values)) rowOffset += numRows if glpk.glp_get_obj_dir(p) == glpk.GLP_MIN: duals = [-d for d in duals] # Retrieve objective value. if simplex: objectiveValue = glpk.glp_get_obj_val(p) elif interior: objectiveValue = glpk.glp_ipt_obj_val(p) else: objectiveValue = glpk.glp_mip_obj_val(p) # Retrieve solution metadata. meta = {} if simplex: # Set common entry "status". status = glpk.glp_get_status(p) if status is glpk.GLP_OPT: meta["status"] = "optimal" elif status is glpk.GLP_FEAS: meta["status"] = "feasible" elif status in (glpk.GLP_INFEAS, glpk.GLP_NOFEAS): meta["status"] = "infeasible" elif status is glpk.GLP_UNBND: meta["status"] = "unbounded" elif status is glpk.GLP_UNDEF: meta["status"] = "undefined" else: meta["status"] = "unknown" # Set GLPK-specific entry "primal_status". primalStatus = glpk.glp_get_prim_stat(p) if primalStatus is glpk.GLP_FEAS: meta["primal_status"] = "feasible" elif primalStatus in (glpk.GLP_INFEAS, glpk.GLP_NOFEAS): meta["primal_status"] = "infeasible" elif primalStatus is glpk.GLP_UNDEF: meta["primal_status"] = "undefined" else: meta["primal_status"] = "unknown" # Set GLPK-specific entry "dual_status". dualStatus = glpk.glp_get_dual_stat(p) if dualStatus is glpk.GLP_FEAS: meta["dual_status"] = "feasible" elif dualStatus in (glpk.GLP_INFEAS, glpk.GLP_NOFEAS): meta["dual_status"] = "infeasible" elif dualStatus is glpk.GLP_UNDEF: meta["dual_status"] = "undefined" else: meta["dual_status"] = "unknown" elif interior: # Set common entry "status". status = glpk.glp_ipt_status(p) if status is glpk.GLP_OPT: meta["status"] = "optimal" elif status in (glpk.GLP_INFEAS, glpk.GLP_NOFEAS): meta["status"] = "infeasible" elif status is glpk.GLP_UNDEF: meta["status"] = "undefined" else: meta["status"] = "unknown" else: # Set common entry "status". status = glpk.glp_mip_status(p) if status is glpk.GLP_OPT: meta["status"] = "optimal" elif status is glpk.GLP_FEAS: meta["status"] = "feasible" elif status is glpk.GLP_NOFEAS: meta["status"] = "infeasible" elif status is glpk.GLP_UNDEF: meta["status"] = "undefined" else: meta["status"] = "unknown" return (primals, duals, objectiveValue, meta)
def dual(self): if self.problem is not None: return glp_get_row_dual(self.problem.problem, self.index) else: return None
def rowDualValue(self, i): """Return the dual value (i.e. reduced cost) of the structural variable for the i-th row. """ return glp.glp_get_row_dual(self._lp, i)