def set_linear_coefficients(self, coefficients): if self.problem is not None: self.problem.update() for variable, coefficient in coefficients.items(): glp_set_obj_coef(self.problem.problem, variable._index, float(coefficient)) self._expression_expired = True else: raise Exception("Can't change coefficients if objective is not associated with a model.")
def set_objective(lp, c): cols_count = len(c) glpk.glp_add_cols(lp, cols_count) for idx, coef in enumerate(c): glpk.glp_set_col_bnds(lp, idx + 1, glpk.GLP_LO, 0.0, 0.0) glpk.glp_set_obj_coef(lp, idx + 1, coef) return cols_count
def setFlowObjectiveCoeff(self, flow, coefficient): idx = self._getVar(flow) self._objective[flow] = coefficient glp.glp_set_obj_coef( self._lp, 1 + idx, # GLPK does 1 indexing coefficient) self._solved = False
def set_minimize_direction(self, direction): '''set the optimization direction''' assert len(direction) == self.get_num_cols(), f"expected {self.get_num_cols()} cols, but optimization " + \ f"vector had {len(direction)} variables" for i, d in enumerate(direction): col = int(1 + i) glpk.glp_set_obj_coef(self.lp, col, float(d))
def _linprog(c, A, b, obj): lp = glpk.glp_create_prob() glpk.glp_set_obj_dir(lp, obj) params = glpk.glp_smcp() glpk.glp_init_smcp(params) params.msg_lev = glpk.GLP_MSG_OFF #Only print error messages from GLPK num_rows = A.shape[0] num_cols = A.shape[1] mat_size = num_rows * num_cols glpk.glp_add_rows(lp, num_rows) for row_ind in range(num_rows): glpk.glp_set_row_bnds(lp, row_ind + 1, glpk.GLP_UP, 0.0, float(b[row_ind])) glpk.glp_add_cols(lp, num_cols) for col_ind in range(num_cols): glpk.glp_set_col_bnds(lp, col_ind + 1, glpk.GLP_FR, 0.0, 0.0) glpk.glp_set_obj_coef(lp, col_ind + 1, c[col_ind]) 'Swig arrays are used for feeding constraints in GLPK' ia, ja, ar = [], [], [] for i, j in product(range(num_rows), range(num_cols)): ia.append(i + 1) ja.append(j + 1) ar.append(float(A[i][j])) ia = glpk.as_intArray(ia) ja = glpk.as_intArray(ja) ar = glpk.as_doubleArray(ar) glpk.glp_load_matrix(lp, mat_size, ia, ja, ar) glpk.glp_simplex(lp, params) fun = glpk.glp_get_obj_val(lp) x = [ i for i in map(lambda x: glpk.glp_get_col_prim(lp, x + 1), range(num_cols)) ] glpk.glp_delete_prob(lp) glpk.glp_free_env() return LPSolution(x, fun)
def objective(self, value): value.problem = None if self._objective is not None: for variable in self.objective.variables: if variable.index is not None: glp_set_obj_coef(self.problem, variable.index, 0.) super(Model, self.__class__).objective.fset(self, value) self.update() expression = self._objective._expression if isinstance(expression, float) or isinstance(expression, int) or expression.is_Number: pass else: if expression.is_Symbol: glp_set_obj_coef(self.problem, expression.index, 1.) if expression.is_Mul: coeff, var = expression.args glp_set_obj_coef(self.problem, var.index, float(coeff)) elif expression.is_Add: for term in expression.args: coeff, var = term.args glp_set_obj_coef(self.problem, var.index, float(coeff)) else: raise ValueError( "Provided objective %s doesn't seem to be appropriate." % self._objective) glp_set_obj_dir( self.problem, {'min': GLP_MIN, 'max': GLP_MAX}[self._objective.direction] ) value.problem = self
def setup_col( problem: SwigPyObject, j: int, recipe: 'Recipe', resource_indices: Dict[str, int], min_clock: Optional[int] = None, fixed_clock: Optional[int] = None, ): lp.glp_set_col_name(problem, j, recipe.name) # The game's clock scaling resolution is one percentage point, so we # ask for integers with an implicit scale of 100 lp.glp_set_col_kind(problem, j, lp.GLP_IV) # All recipes are currently weighed the same lp.glp_set_obj_coef(problem, j, 1) if fixed_clock is None: # All recipes must have at least 0 instances lp.glp_set_col_bnds( problem, j, lp.GLP_LO, min_clock or 0, float('inf'), # Lower and upper boundaries ) else: # Set our desired (fixed) outputs lp.glp_set_col_bnds( problem, j, lp.GLP_FX, fixed_clock, fixed_clock, # Boundaries are equal (variable is fixed) ) # The constraint coefficients are just the recipe rates n_sparse = len(recipe.rates) ind = lp.intArray(n_sparse + 1) val = lp.doubleArray(n_sparse + 1) for i, (resource, rate) in enumerate(recipe.rates.items(), 1): ind[i] = resource_indices[resource] val[i] = rate lp.glp_set_mat_col(problem, j, n_sparse, ind, val)
def objective(self, value): value.problem = None if self._objective is not None: variables = self.objective.variables for variable in variables: if variable._index is not None: glp_set_obj_coef(self.problem, variable._index, 0.) super(Model, self.__class__).objective.fset(self, value) self.update() coef_dict, _ = parse_optimization_expression(value, linear=True) for var, coef in coef_dict.items(): glp_set_obj_coef(self.problem, var._index, float(coef)) glp_set_obj_dir(self.problem, { 'min': GLP_MIN, 'max': GLP_MAX }[self._objective.direction]) value.problem = self
def objective(self, value): value.problem = None if self._objective is not None: variables = self.objective.variables for variable in variables: if variable._index is not None: glp_set_obj_coef(self.problem, variable._index, 0.) super(Model, self.__class__).objective.fset(self, value) self.update() coef_dict, _ = parse_optimization_expression(value, linear=True) for var, coef in coef_dict.items(): glp_set_obj_coef(self.problem, var._index, float(coef)) glp_set_obj_dir( self.problem, {'min': GLP_MIN, 'max': GLP_MAX}[self._objective.direction] ) value.problem = self
def test_swiglpk(self): """Test the underlying GLPK lib and its SWIG interface based on the example from https://github.com/biosustain/swiglpk """ ia = glp.intArray(1 + 1000) ja = glp.intArray(1 + 1000) ar = glp.doubleArray(1 + 1000) lp = glp.glp_create_prob() smcp = glp.glp_smcp() glp.glp_init_smcp(smcp) smcp.msg_lev = glp.GLP_MSG_ALL # use GLP_MSG_ERR? glp.glp_set_prob_name(lp, "sample") glp.glp_set_obj_dir(lp, glp.GLP_MAX) glp.glp_add_rows(lp, 3) glp.glp_set_row_name(lp, 1, "p") glp.glp_set_row_bnds(lp, 1, glp.GLP_UP, 0.0, 100.0) glp.glp_set_row_name(lp, 2, "q") glp.glp_set_row_bnds(lp, 2, glp.GLP_UP, 0.0, 600.0) glp.glp_set_row_name(lp, 3, "r") glp.glp_set_row_bnds(lp, 3, glp.GLP_UP, 0.0, 300.0) glp.glp_add_cols(lp, 3) glp.glp_set_col_name(lp, 1, "x1") glp.glp_set_col_bnds(lp, 1, glp.GLP_LO, 0.0, 0.0) glp.glp_set_obj_coef(lp, 1, 10.0) glp.glp_set_col_name(lp, 2, "x2") glp.glp_set_col_bnds(lp, 2, glp.GLP_LO, 0.0, 0.0) glp.glp_set_obj_coef(lp, 2, 6.0) glp.glp_set_col_name(lp, 3, "x3") glp.glp_set_col_bnds(lp, 3, glp.GLP_LO, 0.0, 0.0) glp.glp_set_obj_coef(lp, 3, 4.0) ia[1] = 1; ja[1] = 1; ar[1] = 1.0 # a[1,1] = 1 ia[2] = 1; ja[2] = 2; ar[2] = 1.0 # a[1,2] = 1 ia[3] = 1; ja[3] = 3; ar[3] = 1.0 # a[1,3] = 1 ia[4] = 2; ja[4] = 1; ar[4] = 10.0 # a[2,1] = 10 ia[5] = 3; ja[5] = 1; ar[5] = 2.0 # a[3,1] = 2 ia[6] = 2; ja[6] = 2; ar[6] = 4.0 # a[2,2] = 4 ia[7] = 3; ja[7] = 2; ar[7] = 2.0 # a[3,2] = 2 ia[8] = 2; ja[8] = 3; ar[8] = 5.0 # a[2,3] = 5 ia[9] = 3; ja[9] = 3; ar[9] = 6.0 # a[3,3] = 6 glp.glp_load_matrix(lp, 9, ia, ja, ar) glp.glp_simplex(lp, smcp) Z = glp.glp_get_obj_val(lp) x1 = glp.glp_get_col_prim(lp, 1) x2 = glp.glp_get_col_prim(lp, 2) x3 = glp.glp_get_col_prim(lp, 3) self.assertAlmostEqual(Z, 733.3333, 4) self.assertAlmostEqual(x1, 33.3333, 4) self.assertAlmostEqual(x2, 66.6667, 4) self.assertAlmostEqual(x3, 0) glp.glp_delete_prob(lp)
def set_minimize_direction(self, direction_vec, is_csr=False, offset=None): '''set the direction for the optimization if offset is None, will use cur_vars_offset (direction is in terms of current-time variables) ''' Timers.tic("set_minimize_direction") if offset is None: offset = self.cur_vars_offset size = direction_vec.shape[1] if is_csr else len(direction_vec) assert size <= self.dims, "len(direction_vec) ({}) > number of cur_vars({})".format( size, self.dims) else: assert direction_vec.shape[1] + offset <= self.get_num_cols() # set the previous objective columns to zero for i in self.obj_cols: glpk.glp_set_obj_coef(self.lp, i, 0) self.obj_cols = [] if is_csr: assert isinstance(direction_vec, csr_matrix) assert direction_vec.shape[0] == 1 data, inds, indptr = direction_vec.data, direction_vec.indices, direction_vec.indptr for n in range(indptr[1]): col = int(1 + offset + inds[n]) self.obj_cols.append(col) if col > len(self.names): print(self) assert col <= len(self.names) glpk.glp_set_obj_coef(self.lp, col, data[n]) else: # non-csr if not isinstance(direction_vec, np.ndarray): direction_vec = np.array(direction_vec, dtype=float) assert len(direction_vec.shape) == 1 assert len(direction_vec) <= self.dims, "dirLen({}) > dims({})".format(len(direction_vec), self.dims) for i, direction in enumerate(direction_vec): col = int(1 + offset + i) self.obj_cols.append(col) glpk.glp_set_obj_coef(self.lp, col, float(direction)) Timers.toc("set_minimize_direction")
def set_objective(self, expression): """Set objective of problem.""" if isinstance(expression, numbers.Number): # Allow expressions with no variables as objective, # represented as a number expression = Expression(offset=expression) # Clear previous objective for i in range(swiglpk.glp_get_num_cols(self._p)): swiglpk.glp_set_obj_coef(self._p, 1 + i, 0) for variable, value in expression.values(): var_index = self._variables[variable] swiglpk.glp_set_obj_coef(self._p, var_index, value) swiglpk.glp_set_obj_coef(self._p, 0, expression.offset)
def set_linear_coefficients(self, coefficients): for variable, coefficient in coefficients.items(): glp_set_obj_coef(self.problem.problem, variable._index, coefficient) self._expression_expired = True
def _import_problem(self): import swiglpk as glpk if self.verbosity() >= 1: glpk.glp_term_out(glpk.GLP_ON) else: glpk.glp_term_out(glpk.GLP_OFF) # Create a problem instance. p = self.int = glpk.glp_create_prob(); # Set the objective. if self.ext.objective[0] in ("find", "min"): glpk.glp_set_obj_dir(p, glpk.GLP_MIN) elif self.ext.objective[0] is "max": glpk.glp_set_obj_dir(p, glpk.GLP_MAX) else: raise NotImplementedError("Objective '{0}' not supported by GLPK." .format(self.ext.objective[0])) # Set objective function shift if self.ext.objective[1] is not None \ and self.ext.objective[1].constant is not None: if not isinstance(self.ext.objective[1], AffinExp): raise NotImplementedError("Non-linear objective function not " "supported by GLPK.") if self.ext.objective[1].constant.size != (1,1): raise NotImplementedError("Non-scalar objective function not " "supported by GLPK.") glpk.glp_set_obj_coef(p, 0, self.ext.objective[1].constant[0]) # Add variables. # Multideminsional variables are split into multiple scalar variables # represented as matrix columns within GLPK. for varName in self.ext.varNames: var = self.ext.variables[varName] # Add a column for every scalar variable. numCols = var.size[0] * var.size[1] glpk.glp_add_cols(p, numCols) for localIndex, picosIndex \ in enumerate(range(var.startIndex, var.endIndex)): glpkIndex = self._picos2glpk_variable_index(picosIndex) # Assign a name to the scalar variable. scalarName = varName if numCols > 1: x = localIndex // var.size[0] y = localIndex % var.size[0] scalarName += "_{:d}_{:d}".format(x + 1, y + 1) glpk.glp_set_col_name(p, glpkIndex, scalarName) # Assign bounds to the scalar variable. lower, upper = var.bnd.get(localIndex, (None, None)) if lower is not None and upper is not None: if lower == upper: glpk.glp_set_col_bnds( p, glpkIndex, glpk.GLP_FX, lower, upper) else: glpk.glp_set_col_bnds( p, glpkIndex, glpk.GLP_DB, lower, upper) elif lower is not None and upper is None: glpk.glp_set_col_bnds(p, glpkIndex, glpk.GLP_LO, lower, 0) elif lower is None and upper is not None: glpk.glp_set_col_bnds(p, glpkIndex, glpk.GLP_UP, 0, upper) else: glpk.glp_set_col_bnds(p, glpkIndex, glpk.GLP_FR, 0, 0) # Assign a type to the scalar variable. if var.vtype in ("continuous", "symmetric"): glpk.glp_set_col_kind(p, glpkIndex, glpk.GLP_CV) elif var.vtype == "integer": glpk.glp_set_col_kind(p, glpkIndex, glpk.GLP_IV) elif var.vtype == "binary": glpk.glp_set_col_kind(p, glpkIndex, glpk.GLP_BV) else: raise NotImplementedError("Variable type '{0}' not " "supported by GLPK.".format(var.vtype())) # Set objective function coefficient of the scalar variable. if self.ext.objective[1] is not None \ and var in self.ext.objective[1].factors: glpk.glp_set_obj_coef(p, glpkIndex, self.ext.objective[1].factors[var][localIndex]) # Add constraints. # Multideminsional constraints are split into multiple scalar # constraints represented as matrix rows within GLPK. rowOffset = 1 for constraintNum, constraint in enumerate(self.ext.constraints): if not isinstance(constraint, AffineConstraint): raise NotImplementedError( "Non-linear constraints not supported by GLPK.") # Add a row for every scalar constraint. # Internally, GLPK uses an auxiliary variable for every such row, # bounded by the right hand side of the scalar constraint in a # canonical form. numRows = len(constraint) glpk.glp_add_rows(p, numRows) self._debug("Handling PICOS Constraint: " + str(constraint)) # Split multidimensional constraints into multiple scalar ones. for localConIndex, (glpkVarIndices, coefficients, rhs) in \ enumerate(constraint.sparse_Ab_rows( None, indexFunction = lambda picosVar, i: self._picos2glpk_variable_index(picosVar.startIndex + i))): # Determine GLPK's row index of the scalar constraint. glpkConIndex = rowOffset + localConIndex numColumns = len(glpkVarIndices) # Name the auxiliary variable associated with the current row. if constraint.name: name = constraint.name else: name = "rhs_{:d}".format(constraintNum) if numRows > 1: x = localConIndex // constraint.size[0] y = localConIndex % constraint.size[0] name += "_{:d}_{:d}".format(x + 1, y + 1) glpk.glp_set_row_name(p, glpkConIndex, name) # Assign bounds to the auxiliary variable. if constraint.is_equality(): glpk.glp_set_row_bnds(p, glpkConIndex, glpk.GLP_FX, rhs,rhs) elif constraint.is_increasing(): glpk.glp_set_row_bnds(p, glpkConIndex, glpk.GLP_UP, 0, rhs) elif constraint.is_decreasing(): glpk.glp_set_row_bnds(p, glpkConIndex, glpk.GLP_LO, rhs, 0) else: assert False, "Unexpected constraint relation." # Set coefficients for current row. # Note that GLPK requires a glpk.intArray containing column # indices and a glpk.doubleArray of same size containing the # coefficients for the listed column index. The first element # of both arrays (with index 0) is skipped by GLPK. glpkVarIndicesArray = glpk.intArray(numColumns + 1) for i in range(numColumns): glpkVarIndicesArray[i + 1] = glpkVarIndices[i] coefficientsArray = glpk.doubleArray(numColumns + 1) for i in range(numColumns): coefficientsArray[i + 1] = coefficients[i] glpk.glp_set_mat_row(p, glpkConIndex, numColumns, glpkVarIndicesArray, coefficientsArray) rowOffset += numRows
def _set_linear_objective_term(self, variable, coefficient): glp_set_obj_coef(self.problem, variable.index, coefficient)