def __del__(self): if hasattr(self, 'lp') and self.lp is not None: if not isinstance(self.lp, tuple): glpk.glp_delete_prob(self.lp) self.lp = None
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 __del__(self): try: import swiglpk as glpk except ImportError: # Happens when python is shutting down. In this case, no garbage # collection is necessary, anyway. return if self.int is not None: glpk.glp_delete_prob(self.int)
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 serialize(self): 'serialize self.lp from a glpk instance into a tuple' Timers.tic('serialize') # get constraints as csr matrix lp_rows = self.get_num_rows() lp_cols = self.get_num_cols() inds_row = SwigArray.get_int_array(lp_cols + 1) vals_row = SwigArray.get_double_array(lp_cols + 1) data = [] glpk_indices = [] indptr = [0] for row in range(lp_rows): got_len = glpk.glp_get_mat_row(self.lp, row + 1, inds_row, vals_row) for i in range(1, got_len + 1): data.append(vals_row[i]) glpk_indices.append(inds_row[i]) indptr.append(len(data)) # rhs rhs = [] for row in range(lp_rows): assert glpk.glp_get_row_type(self.lp, row + 1) == glpk.GLP_UP rhs.append(glpk.glp_get_row_ub(self.lp, row + 1)) col_bounds = self.get_col_bounds() # remember to free lp object before overwriting with tuple glpk.glp_delete_prob(self.lp) self.lp = (data, glpk_indices, indptr, rhs, col_bounds) Timers.toc('serialize')
def solve_IP(self): #clear solution file open("lp.sol", "w").close() #create the LP lp = glpk.glp_create_prob() #create the model translator tran = glpk.glp_mpl_alloc_wksp() #read the model intro translator glpk.glp_mpl_read_model(tran, "lp.mod", 0) #generate the model glpk.glp_mpl_generate(tran, None) #build the LP from the model glpk.glp_mpl_build_prob(tran, lp) #create and init params for MIP solver params = glpk.glp_iocp() glpk.glp_init_iocp(params) params.presolve = glpk.GLP_ON #solve the MIP glpk.glp_intopt(lp, params) #save solution #glpk.glp_write_sol(lp,"lp2.sol") glpk.glp_mpl_postsolve(tran, lp, glpk.GLP_MIP) #free resources glpk.glp_mpl_free_wksp(tran) glpk.glp_delete_prob(lp) #read solution from model self.read_solution() #delete model and solution files os.remove("lp.mod") os.remove("lp.sol")
def reset_problem(self): import swiglpk as glpk if self.int is not None: glpk.glp_delete_prob(self.int) self.int = None
def solve(nutrition_target, foods): ''' Calculate food amounts to reach the nutrition target Parameters ---------- nutrition_target : soylent_recipes.nutrition_target.NormalizedNutritionTarget The desired nutrition foods : np.array The foods to use to achieve the nutrition target. Contains exactly the nutrients required by the nutrition target in the exact same order. Rows represent foods, columns represent nutrients. Returns ------- amounts : np.array(int) or None The amounts of each food to use to optimally achieve the nutrition target. ``amounts[i]`` is the amount of the i-th food to use. If the nutrition target cannot be achieved, returns None. ''' # Implementation: using the GLPK C library via ecyglpki Python library binding # GLPK documentation: download it and look inside the package (http://ftp.gnu.org/gnu/glpk/) # GLPK wikibook: https://en.wikibooks.org/wiki/GLPK # # GPLK lingo: rows and columns refer to Ax=b where b_i are auxiliary # variables, x_i are structural variables. Setting constraints on rows, set # constraints on b_i, while column constraints are applied to x_i. # Note: glpk is powerful. We're using mostly the default settings. # Performance likely can be improved by tinkering with the settings; or even # by providing the solution to the least squares equivalent, with amounts # rounded afterwards, as starting point could improve performance. nutrition_target = nutrition_target.values problem = glp.glp_create_prob() try: glp.glp_add_rows(problem, len(nutrition_target)) glp.glp_add_cols(problem, len(foods)) # Configure columns/amounts for i in range(len(foods)): glp.glp_set_col_kind(problem, i+1, glp.GLP_IV) # int glp.glp_set_col_bnds(problem, i+1, glp.GLP_LO, 0.0, np.nan) # >=0 # Configure rows/nutrients for i, extrema in enumerate(nutrition_target): if np.isnan(extrema[0]): bounds_type = glp.GLP_UP elif np.isnan(extrema[1]): bounds_type = glp.GLP_LO else: # Note: a nutrition target has either min, max or both and min!=max bounds_type = glp.GLP_DB glp.glp_set_row_bnds(problem, i+1, bounds_type, *extrema) # Load A of our Ax=b non_zero_count = foods.size row_indices = glp.intArray(non_zero_count+1) # +1 because (insane) 1-indexing column_indices = glp.intArray(non_zero_count+1) values = glp.doubleArray(non_zero_count+1) for i, ((row, column), value) in enumerate(np.ndenumerate(foods.transpose())): row_indices[i+1] = row+1 column_indices[i+1] = column+1 values[i+1] = value glp.glp_load_matrix(problem, non_zero_count, row_indices, column_indices, values) # Solve int_opt_args = glp.glp_iocp() glp.glp_init_iocp(int_opt_args) int_opt_args.presolve = glp.GLP_ON # without this, you have to provide an LP relaxation basis int_opt_args.msg_lev = glp.GLP_MSG_OFF # be quiet, no stdout glp.glp_intopt(problem, int_opt_args) # returns an error code; can safely ignore # Check we've got a valid solution # # Note: glp_intopt returns whether the algorithm completed successfully. # This does not imply you've got a good solution, it could even be # infeasible. glp_mip_status returns whether the solution is optimal, # feasible, infeasible or undefined. An optimal/feasible solution is not # necessarily a good solution. An optimal solution may even violate # bounds constraints. The thing you actually need to use is # glp_check_kkt and check that the solution satisfies KKT.PB (all within # bounds) max_error = glp.doubleArray(1) glp.glp_check_kkt(problem, glp.GLP_MIP, glp.GLP_KKT_PB, max_error, None, None, None) if not np.isclose(max_error[0], 0.0): # A row/column value exceeds its bounds return None # Return solution amounts = np.fromiter((glp.glp_mip_col_val(problem, i+1) for i in range(len(foods))), int) return amounts finally: glp.glp_delete_prob(problem)
def __del__(self): swiglpk.glp_delete_prob(self._p)
def __del__(self): glp.glp_delete_prob(self._lp)
def __del__(self): swiglpk.glp_delete_prob(self._p)
def delete_problem(lp): glpk.glp_delete_prob(lp)
def __del__(self): if hasattr(self, 'lp') and self.lp is not None: glpk.glp_delete_prob(self.lp) self.lp = None