def testGmp(self): """Test reading/writing GNU MathProg format.""" # there is no write keyword for 'gmp'; write the file manually self.f.write(''' var x, >= 0, <= 1; var y, >= 0, <= 1; maximize value: x + y; subject to row: .5*x + y <= 1; end; '''.encode('utf-8')) self.f.flush() lp = LPX(gmp=self.f.name) # TODO: why is this two? self.assertEqual(len(lp.rows), 2) self.assertEqual(len(lp.cols), 2) self.assertEqual(lp.cols[0].name, 'x') self.assertEqual(lp.cols[1].name, 'y') # try to read a non-existing file with self.assertRaises(RuntimeError) as cm: lp = LPX(gmp='not a real file') self.assertIn('GMP model reader failed', str(cm.exception)) # try to write to a non-existing path with self.assertRaises(ValueError) as cm: lp = LPX(gmp=()) self.assertIn('model tuple must have 1<=length<=3', str(cm.exception)) with self.assertRaises(TypeError) as cm: lp = LPX(gmp={}) self.assertIn('model arg must be string or tuple', str(cm.exception))
def solve_sat(self, expression=None, callback=None, return_processor=None, kwargs={}): """Runs a solve sat with a callback. This is similar to the other SAT solving procedures in this test suite, with some modifications to enable testing of the MIP callback functionality. expression is the expression argument, and defaults to the expression declared in the MIPCallbackTest. callback is the callback instance being tested. return_processor is a function called with the retval from the lp.integer call, and the lp, e.g., return_processor(retval, lp), prior to any further processing of the results. kwargs is a dictionary of other optional keyword arguments and their values which is passed to the lp.integer solution procedure.""" if expression is None: expression = self.expression if len(expression) == 0: return [] numvars = max(max(abs(v) for v in clause) for clause in expression) lp = LPX() lp.cols.add(2*numvars) for col in lp.cols: col.bounds = 0.0, 1.0 def lit2col(lit): if lit > 0: return 2*lit-2 return 2*(-lit)-1 for i in range(1, numvars+1): lp.cols[lit2col(i)].name = 'x_%d' % i lp.cols[lit2col(-i)].name = '!x_%d' % i lp.rows.add(1) lp.rows[-1].matrix = [(lit2col(i), 1.0), (lit2col(-i), 1.0)] lp.rows[-1].bounds = 1.0 for clause in expression: lp.rows.add(1) lp.rows[-1].matrix = [(lit2col(lit), 1.0) for lit in clause] lp.rows[-1].bounds = 1, None retval = lp.simplex() if retval is not None: return None if lp.status != 'opt': return None for col in lp.cols: col.kind = int retval = lp.integer(callback=callback, **kwargs) if return_processor: return_processor(retval, lp) if retval is not None: return None if lp.status != 'opt': return None return [col.value > 0.99 for col in lp.cols[::2]]
def testLpxSetMatrix(self): lp = LPX() with self.assertRaises(ValueError) as cm: lp.matrix = [(1, 2, 3, 4)] self.assertIn( 'matrix entry tuple has length 4; 3 is required', str(cm.exception) )
def testLpxErase(self): lp = LPX() lp.cols.add(2) lp.rows.add(2) self.assertEqual(len(lp.cols), 2) self.assertEqual(len(lp.rows), 2) lp.erase() self.assertEqual(len(lp.cols), 0) self.assertEqual(len(lp.rows), 0)
def testLpxKkt(self): lp = LPX() with self.assertRaises(RuntimeError) as cm: lp.kkt() self.assertIn( 'cannot get KKT when primal or dual basic solution undefined', str(cm.exception) )
def create_problem(cobra_model, **kwargs): """Solver-specific method for constructing a solver problem from a cobra.Model. This can be tuned for performance using kwargs """ metabolite_to_index = {r: i for i, r in enumerate(cobra_model.metabolites)} lp = LPX() # Create empty problem instance lp.name = 'cobra' # Assign symbolic name to problem lp.rows.add(len(cobra_model.metabolites)) lp.cols.add(len(cobra_model.reactions)) for r, the_metabolite in zip(lp.rows, cobra_model.metabolites): r.name = the_metabolite.id b = float(the_metabolite._bound) c = the_metabolite._constraint_sense if c == 'E': r.bounds = b, b # Set metabolite to steady state levels elif c == 'L': r.bounds = None, b elif c == 'G': r.bounds = b, None else: raise ValueError("invalid constraint sense") objective_coefficients = [] linear_constraints = [] for c, the_reaction in zip(lp.cols, cobra_model.reactions): c.name = the_reaction.id c.kind = variable_kind_dict[the_reaction.variable_kind] c.bounds = the_reaction.lower_bound, the_reaction.upper_bound objective_coefficients.append(float( the_reaction.objective_coefficient)) for metabolite, coefficient in iteritems(the_reaction._metabolites): metabolite_index = metabolite_to_index[metabolite] linear_constraints.append((metabolite_index, c.index, coefficient)) #Add the new objective coefficients to the problem lp.obj[:] = objective_coefficients #Need to assign lp.matrix after constructing the whole list #linear_constraints.sort() # if we wanted to be 100% deterministic lp.matrix = linear_constraints # make sure the objective sense is set in create_problem objective_sense = kwargs.get("objective_sense", "maximize") set_parameter(lp, "objective_sense", objective_sense) return lp
def create_problem(cobra_model, **kwargs): """Solver-specific method for constructing a solver problem from a cobra.Model. This can be tuned for performance using kwargs """ metabolite_to_index = {r: i for i, r in enumerate(cobra_model.metabolites)} lp = LPX() # Create empty problem instance lp.name = 'cobra' # Assign symbolic name to problem lp.rows.add(len(cobra_model.metabolites)) lp.cols.add(len(cobra_model.reactions)) for r, the_metabolite in zip(lp.rows, cobra_model.metabolites): r.name = the_metabolite.id b = float(the_metabolite._bound) c = the_metabolite._constraint_sense if c == 'E': r.bounds = b, b # Set metabolite to steady state levels elif c == 'L': r.bounds = None, b elif c == 'G': r.bounds = b, None else: raise ValueError("invalid constraint sense") objective_coefficients = [] linear_constraints = [] for c, the_reaction in zip(lp.cols, cobra_model.reactions): c.name = the_reaction.id c.kind = variable_kind_dict[the_reaction.variable_kind] c.bounds = the_reaction.lower_bound, the_reaction.upper_bound objective_coefficients.append(float(the_reaction.objective_coefficient)) for metabolite, coefficient in iteritems(the_reaction._metabolites): metabolite_index = metabolite_to_index[metabolite] linear_constraints.append((metabolite_index, c.index, coefficient)) #Add the new objective coefficients to the problem lp.obj[:] = objective_coefficients #Need to assign lp.matrix after constructing the whole list #linear_constraints.sort() # if we wanted to be 100% deterministic lp.matrix = linear_constraints # make sure the objective sense is set in create_problem objective_sense = kwargs.get("objective_sense", "maximize") set_parameter(lp, "objective_sense", objective_sense) return lp
def testObjectiveAssignment(self): lp = LPX() with self.assertRaises(TypeError) as cm: del(lp.obj[0]) self.assertIn( "objective function doesn't support item deletion", str(cm.exception) )
def testLpxRay(self): lp = LPX() self.assertTrue(lp.ray is None) lp.cols.add(2) x1, x2 = lp.cols[0:2] lp.obj[:] = [-1.0, 1.0] lp.rows.add(2) r1, r2 = lp.rows[0:2] r1.matrix = [1.0, -1.0] r1.bounds = (-3, None) r2.matrix = [-1.0, 2.0] r2.bounds = (-2.0, None) x1.bounds = None x2.bounds = None lp.simplex() self.assertEqual(lp.status, 'unbnd') self.assertTrue(lp.ray.iscol)
def test_transform_row_with_variable_from_other_lp(self): other_lp = LPX() other_lp.cols.add(3) with self.assertRaises(ValueError) as context: self.lp.transform_row([(other_lp.cols[0], 3.0)]) self.assertIn("variable not associated with this LPX", str(context.exception))
def solve_sat(self, expression): """Attempts to satisfy a formula of conjunction of disjunctions. If there are n variables in the expression, this will return a list of length n, all elements booleans. The truth of element i-1 corresponds to the truth of variable i. If no satisfying assignment could be found, None is returned.""" if len(expression) == 0: return [] numvars = max(max(abs(v) for v in clause) for clause in expression) lp = LPX() lp.cols.add(2*numvars) for col in lp.cols: col.bounds = 0.0, 1.0 def lit2col(lit): if lit > 0: return 2*lit-2 return 2*(-lit)-1 for i in range(1, numvars+1): lp.cols[lit2col(i)].name = 'x_%d' % i lp.cols[lit2col(-i)].name = '!x_%d' % i lp.rows.add(1) lp.rows[-1].matrix = [(lit2col(i), 1.0), (lit2col(-i), 1.0)] lp.rows[-1].bounds = 1.0 for clause in expression: lp.rows.add(1) lp.rows[-1].matrix = [(lit2col(lit), 1.0) for lit in clause] lp.rows[-1].bounds = 1, None retval = lp.simplex() if retval is not None: return None if lp.status != 'opt': return None for col in lp.cols: col.kind = int retval = lp.integer() if retval is not None: return None if lp.status != 'opt': return None return [col.value > 0.99 for col in lp.cols[::2]]
def create_problem(cobra_model, objective_sense="maximize", lp=None): if lp is None: lp = LPX() # Create empty problem instance lp.name = cobra_model.id lp.rows.add(len(cobra_model.metabolites)) lp.cols.add(len(cobra_model.reactions)) if objective_sense == 'maximize': lp.obj.maximize = True elif objective_sense == 'minimize': lp.obj.maximize = False else: raise ValueError("objective_sense not 'maximize' or 'minimize'") # create metabolites/constraints as rows for i, r in enumerate(lp.rows): metabolite = cobra_model.metabolites[i] r.name = metabolite.id b = float(metabolite._bound) c = metabolite._constraint_sense # constraint sense is set by changing the bounds if c == 'E': r.bounds = (b, b) elif c == 'L': r.bounds = (None, b) elif c == 'G': r.bounds = (b, None) else: raise ValueError("%s is not a valid constraint_sense" % c) # create reactions/variables as columns for i, c in enumerate(lp.cols): reaction = cobra_model.reactions[i] c.name = reaction.id c.kind = variable_kind_dict[reaction.variable_kind] c.bounds = (reaction.lower_bound, reaction.upper_bound) lp.obj[i] = float(reaction.objective_coefficient) # create S matrix lp.matrix = [(int(i), int(j), c) \ for (i, j), c in cobra_model.to_array_based_model().S.todok().iteritems()] return lp
def setUp(self): lp = self.lp = LPX() lp.rows.add(1) lp.cols.add(2) for c in lp.cols: c.bounds = 0, 1 lp.obj[:] = [1, 1] lp.obj.maximize = True lp.rows[0].matrix = [0.5, 1.0] lp.rows[0].bounds = None, 1 self.num_illegals = 100
def testFreeMps(self): """Test reading/writing free MPS format.""" self.lp.write(freemps=self.f.name) lp = LPX(freemps=self.f.name) self.assertEqual(len(lp.rows), 1) self.assertEqual(len(lp.cols), 2) self.assertEqual(lp.cols[0].name, 'x') self.assertEqual(lp.cols[1].name, 'y') # try to read a non-existing file with self.assertRaises(RuntimeError) as cm: lp = LPX(freemps='not a real file') self.assertIn('Free MPS reader failed', str(cm.exception)) # try to write to a non-existing path with self.assertRaises(RuntimeError) as cm: lp.write(freemps='not/a/real/file') self.assertIn( "writer for 'freemps' failed to write to 'not/a/real/file'", str(cm.exception) )
def setUp(self): lp = self.lp = LPX() lp.rows.add(1) lp.cols.add(2) lp.cols[0].name = 'x' lp.cols[1].name = 'y' for c in lp.cols: c.bounds = 0, 1 lp.obj[:] = [1, 1] lp.obj.maximize = True lp.rows[0].matrix = [0.5, 1.0] lp.rows[0].bounds = None, 1
def testCpxLp(self): """Test reading/writing CPLEX LP format.""" self.lp.write(cpxlp=self.f.name) lp = LPX(cpxlp=self.f.name) self.assertEqual(len(lp.rows), 1) self.assertEqual(len(lp.cols), 2) self.assertEqual(lp.cols[0].name, 'x') self.assertEqual(lp.cols[1].name, 'y') # try to read a non-existing file with self.assertRaises(RuntimeError) as cm: lp = LPX(cpxlp='not a real file') self.assertIn('CPLEX LP reader failed', str(cm.exception)) # try to write to a non-existing path with self.assertRaises(RuntimeError) as cm: lp.write(cpxlp='not/a/real/file') self.assertIn( "writer for 'cpxlp' failed to write to 'not/a/real/file'", str(cm.exception) )
def setUp(self): lp = self.lp = LPX() lp.rows.add(2) lp.cols.add(2) for c in lp.cols: c.bounds = None, None c.kind = int lp.obj[:] = [1, 1] lp.obj.maximize = True lp.rows[0].matrix, lp.rows[1].matrix = [2, 1], [1, 2] lp.rows[0].bounds, lp.rows[1].bounds = (None, 6.5), (None, 6.5) lp.simplex() # This should have both column vars at 2.1666... self.num_illegals = 100
def setUp(self): # create a new temp file for reading/writing to self.f = tempfile.NamedTemporaryFile() lp = self.lp = LPX() lp.rows.add(1) lp.cols.add(2) lp.cols[0].name = 'x' lp.cols[1].name = 'y' for c in lp.cols: c.bounds = 0, 1 lp.obj[:] = [1, 1] lp.obj.maximize = True lp.rows[0].matrix = [0.5, 1.0] lp.rows[0].bounds = None, 1
def setUp(self): lp = self.lp = LPX() lp.rows.add(1) self.z = lp.rows[0] lp.cols.add(2) self.x = lp.cols[0] self.y = lp.cols[1] for c in lp.cols: c.bounds = 0, 1 lp.obj[:] = [1, 1] lp.obj.maximize = True lp.rows[0].matrix = [0.5, 1.0] lp.rows[0].bounds = None, 1 self.lp.simplex()
def testInit(self): with self.assertRaises(TypeError) as cm: LPX(gmp='', mps='') self.assertIn( 'cannot specify multiple data sources', str(cm.exception) ) with self.assertRaises(RuntimeError) as cm: LPX(gmp=('', None, '')) self.assertIn( 'GMP model reader failed', str(cm.exception) ) model = tempfile.NamedTemporaryFile(mode='w') model.write(MODEL) model.flush() data = tempfile.NamedTemporaryFile(mode='w') data.write(DATA) data.flush() with self.assertRaises(RuntimeError) as cm: LPX(gmp=(model.name, '')) self.assertIn( 'GMP data reader failed', str(cm.exception) ) with self.assertRaises(RuntimeError) as cm: LPX(gmp=(model.name, data.name)) self.assertIn( 'GMP generator failed', str(cm.exception) )
def testLpxInteger(self): lp = LPX() with self.assertRaises(RuntimeError) as cm: lp.integer() self.assertIn( 'integer solver without presolve requires existing optimal basic ' 'solution', str(cm.exception) ) with self.assertRaises(ValueError) as cm: lp.integer(ps_tm_lim=-1, presolve=True) self.assertIn('ps_tm_lim must be nonnegative', str(cm.exception)) with self.assertRaises(ValueError) as cm: lp.integer(mip_gap=-1, presolve=True) self.assertIn('mip_gap must be non-negative', str(cm.exception))
def testGlp(self): """Test reading/writing GNU LP format.""" self.lp.write(glp=self.f.name) lp = LPX(glp=self.f.name) self.assertEqual(len(lp.rows), 1) self.assertEqual(len(lp.cols), 2) self.assertEqual(lp.cols[0].name, 'x') self.assertEqual(lp.cols[1].name, 'y') # try to read a non-existing file with self.assertRaises(RuntimeError) as cm: lp = LPX(glp='not a real file') self.assertIn('GLPK LP/MIP reader failed', str(cm.exception)) # try to write to a non-existing path with self.assertRaises(RuntimeError) as cm: lp.write(glp='not/a/real/file') self.assertIn("writer for 'glp' failed to write to 'not/a/real/file'", str(cm.exception))
def testFreeMps(self): """Test reading/writing free MPS format.""" self.lp.write(freemps=self.f.name) lp = LPX(freemps=self.f.name) self.assertEqual(len(lp.rows), 1) self.assertEqual(len(lp.cols), 2) self.assertEqual(lp.cols[0].name, 'x') self.assertEqual(lp.cols[1].name, 'y') # try to read a non-existing file with self.assertRaises(RuntimeError) as cm: lp = LPX(freemps='not a real file') self.assertIn('Free MPS reader failed', str(cm.exception)) # try to write to a non-existing path with self.assertRaises(RuntimeError) as cm: lp.write(freemps='not/a/real/file') self.assertIn( "writer for 'freemps' failed to write to 'not/a/real/file'", str(cm.exception))
from glpk import LPX # set up to maximize the objective function lp = LPX() lp.name = 'example' lp.obj.maximize = True # append 3 rows, named p, q, r row_names = ["p", "q", "r"] lp.rows.add(len(row_names)) for r in lp.rows: r.name = row_names[r.index] lp.rows[0].bounds = None, 100.0 lp.rows[1].bounds = None, 600.0 lp.rows[2].bounds = None, 150.0 # append 3 cols, named x0, x1, x2 lp.cols.add(3) for c in lp.cols: c.name = 'x%d' % c.index c.bounds = 0.0, None # set the objective coefficients and # non-zero entries of the constraint matrix lp.obj[:] = [ 5.0, 3.0, 2.0 ] lp.matrix = [ 1.0, 1.0, 3.0, 10.0, 4.0, 5.0, 1.0, 1.0, 3.0 ] # report the objective function value and structural variables
def _optimize_glpk( cobra_model, new_objective=None, objective_sense='maximize', min_norm=0, the_problem=None, tolerance_optimality=1e-6, tolerance_feasibility=1e-6, tolerance_integer=1e-9, error_reporting=None, print_solver_time=False, lp_method=1, quadratic_component=None, reuse_basis=True, #Not implemented tolerance_barrier=None, lp_parallel=None, copy_problem=None, relax_b=None, update_problem_reaction_bounds=True): """Uses the GLPK (www.gnu.org/software/glpk/) optimizer via pyglpk (http://www.tfinley.net/software/pyglpk/release.html) to perform an optimization on cobra_model for the objective_coefficients in cobra_model._objective_coefficients based on the objective sense. cobra_model: A cobra.Model object new_objective: Reaction, String, or Integer referring to a reaction in cobra_model.reactions to set as the objective. Currently, only supports single objective coeffients. Will expand to include mixed objectives. objective_sense: 'maximize' or 'minimize' min_norm: not implemented the_problem: None or a problem object for the specific solver that can be used to hot start the next solution. tolerance_optimality: Solver tolerance for optimality. tolerance_feasibility: Solver tolerance for feasibility. error_reporting: None or True to disable or enable printing errors encountered when trying to find the optimal solution. print_solver_time: False or True. Indicates if the time to calculate the solution should be displayed. quadratic_component: None. GLPK cannot solve quadratic programs at the moment. reuse_basis: Boolean. If True and the_problem is a model object for the solver, attempt to hot start the solution. Currently, only True is available for GLPK update_problem_reaction_bounds: Boolean. Set to True if you're providing the_problem and you've modified reaction bounds on your cobra_model since creating the_problem. Only necessary for CPLEX lp.simplex() with Salmonella model: cold start: 0.42 seconds hot start: 0.0013 seconds """ from numpy import zeros, array, nan #TODO: Speed up problem creation if hasattr(quadratic_component, 'todok'): raise Exception('GLPK cannot solve quadratic programs please '+\ 'try using the gurobi or cplex solvers') from glpk import LPX from cobra.flux_analysis.objective import update_objective from cobra.solvers.legacy import status_dict, variable_kind_dict status_dict = eval(status_dict['glpk']) variable_kind_dict = eval(variable_kind_dict['glpk']) if new_objective and new_objective != 'update problem': update_objective(cobra_model, new_objective) #Faster to use these dicts than index lists index_to_metabolite = dict( zip(range(len(cobra_model.metabolites)), cobra_model.metabolites)) index_to_reaction = dict( zip(range(len(cobra_model.reactions)), cobra_model.reactions)) reaction_to_index = dict( zip(index_to_reaction.values(), index_to_reaction.keys())) if the_problem == None or the_problem in ['return', 'setup'] or \ not isinstance(the_problem, LPX): lp = LPX() # Create empty problem instance lp.name = 'cobra' # Assign symbolic name to problem lp.rows.add(len(cobra_model.metabolites)) lp.cols.add(len(cobra_model.reactions)) linear_constraints = [] for r in lp.rows: the_metabolite = index_to_metabolite[r.index] r.name = the_metabolite.id b = float(the_metabolite._bound) c = the_metabolite._constraint_sense if c == 'E': r.bounds = b, b # Set metabolite to steady state levels elif c == 'L': r.bounds = None, b elif c == 'G': r.bounds = b, None #Add in the linear constraints for the_reaction in the_metabolite._reaction: reaction_index = reaction_to_index[the_reaction] the_coefficient = the_reaction._metabolites[the_metabolite] linear_constraints.append( (r.index, reaction_index, the_coefficient)) #Need to assign lp.matrix after constructing the whole list lp.matrix = linear_constraints objective_coefficients = [] for c in lp.cols: the_reaction = index_to_reaction[c.index] c.name = the_reaction.id the_reaction = index_to_reaction[c.index] c.kind = variable_kind_dict[the_reaction.variable_kind] c.bounds = the_reaction.lower_bound, the_reaction.upper_bound objective_coefficients.append( float(the_reaction.objective_coefficient)) #Add the new objective coefficients to the problem lp.obj[:] = objective_coefficients else: lp = the_problem #BUG with changing / unchanging the basis if new_objective is not None: objective_coefficients = [] for c in lp.cols: # Iterate over all rows the_reaction = index_to_reaction[c.index] c.name = the_reaction.id c.bounds = the_reaction.lower_bound, the_reaction.upper_bound objective_coefficients.append( float(the_reaction.objective_coefficient)) c.kind = variable_kind_dict[the_reaction.variable_kind] #Add the new objective coefficients to the problem lp.obj[:] = objective_coefficients else: for c in lp.cols: # Iterate over all rows the_reaction = index_to_reaction[c.index] c.name = the_reaction.id c.bounds = the_reaction.lower_bound, the_reaction.upper_bound c.kind = variable_kind_dict[the_reaction.variable_kind] if objective_sense.lower() == 'maximize': lp.obj.maximize = True # Set this as a maximization problem else: lp.obj.maximize = False if the_problem == 'setup': return lp if print_solver_time: start_time = time() the_methods = [1, 2, 3] if lp_method in the_methods: the_methods.remove(lp_method) else: lp_method = 1 if not isinstance(the_problem, LPX): if lp.kind == int: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method) # we first have to solve the LP? lp.integer(tol_int=tolerance_integer) else: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method) # Solve this LP or MIP with the simplex (depending on if integer variables exist). Takes about 0.35 s without hot start if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status != 'optimal': for lp_method in the_methods: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method) if lp.status == 'opt': if lp.kind == int: lp.integer(tol_int=tolerance_integer) break else: if lp.kind == int: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method, tm_lim=100) # we first have to solve the LP? lp.integer(tol_int=tolerance_integer) else: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method, tm_lim=100) #If the solver takes more than 0.1 s with a hot start it is likely stuck if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status != 'optimal': if lp.kind == int: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method) # we first have to solve the LP? lp.integer(tol_int=tolerance_integer) else: for lp_method in the_methods: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method) if lp.status == 'opt': if lp.kind == int: lp.integer(tol_int=tolerance_integer) break if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status != 'optimal': lp = optimize_glpk( cobra_model, new_objective=new_objective, objective_sense=objective_sense, min_norm=min_norm, the_problem=None, print_solver_time=print_solver_time, tolerance_optimality=tolerance_optimality, tolerance_feasibility=tolerance_feasibility)['the_problem'] if lp.status == 'opt': if lp.kind == int: lp.integer(tol_int=tolerance_integer) if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status != 'optimal': lp.simplex(tol_bnd=tolerance_optimality, presolve=True, tm_lim=5000) if lp.kind == int: lp.integer(tol_int=tolerance_integer) if print_solver_time: print 'simplex time: %f' % (time() - start_time) x = [] y = [] x_dict = {} y_dict = {} if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status == 'optimal': objective_value = lp.obj.value [(x.append(float(c.primal)), x_dict.update({c.name: c.primal})) for c in lp.cols] if lp.kind == float: #return the duals as well as the primals for LPs [(y.append(float(c.dual)), y_dict.update({c.name: c.dual})) for c in lp.rows] else: #MIPs don't have duals y = y_dict = None x = array(x) else: x = y = x_dict = y_dict = objective_value = None if error_reporting: print 'glpk failed: %s' % lp.status cobra_model.solution = the_solution = Solution(objective_value, x=x, x_dict=x_dict, y=y, y_dict=y_dict, status=status) solution = {'the_problem': lp, 'the_solution': the_solution} return solution
def _optimize_glpk(cobra_model, new_objective=None, objective_sense='maximize', min_norm=0, the_problem=None, tolerance_optimality=1e-6, tolerance_feasibility=1e-6, tolerance_integer=1e-9, error_reporting=None, print_solver_time=False, lp_method=1, quadratic_component=None, reuse_basis=True, #Not implemented tolerance_barrier=None, lp_parallel=None, copy_problem=None, relax_b=None,update_problem_reaction_bounds=True): """Uses the GLPK (www.gnu.org/software/glpk/) optimizer via pyglpk (http://www.tfinley.net/software/pyglpk/release.html) to perform an optimization on cobra_model for the objective_coefficients in cobra_model._objective_coefficients based on the objective sense. cobra_model: A cobra.Model object new_objective: Reaction, String, or Integer referring to a reaction in cobra_model.reactions to set as the objective. Currently, only supports single objective coeffients. Will expand to include mixed objectives. objective_sense: 'maximize' or 'minimize' min_norm: not implemented the_problem: None or a problem object for the specific solver that can be used to hot start the next solution. tolerance_optimality: Solver tolerance for optimality. tolerance_feasibility: Solver tolerance for feasibility. error_reporting: None or True to disable or enable printing errors encountered when trying to find the optimal solution. print_solver_time: False or True. Indicates if the time to calculate the solution should be displayed. quadratic_component: None. GLPK cannot solve quadratic programs at the moment. reuse_basis: Boolean. If True and the_problem is a model object for the solver, attempt to hot start the solution. Currently, only True is available for GLPK update_problem_reaction_bounds: Boolean. Set to True if you're providing the_problem and you've modified reaction bounds on your cobra_model since creating the_problem. Only necessary for CPLEX lp.simplex() with Salmonella model: cold start: 0.42 seconds hot start: 0.0013 seconds """ from numpy import zeros, array, nan #TODO: Speed up problem creation if hasattr(quadratic_component, 'todok'): raise Exception('GLPK cannot solve quadratic programs please '+\ 'try using the gurobi or cplex solvers') from glpk import LPX from cobra.flux_analysis.objective import update_objective from cobra.solvers.legacy import status_dict, variable_kind_dict status_dict = eval(status_dict['glpk']) variable_kind_dict = eval(variable_kind_dict['glpk']) if new_objective and new_objective != 'update problem': update_objective(cobra_model, new_objective) #Faster to use these dicts than index lists index_to_metabolite = dict(zip(range(len(cobra_model.metabolites)), cobra_model.metabolites)) index_to_reaction = dict(zip(range(len(cobra_model.reactions)), cobra_model.reactions)) reaction_to_index = dict(zip(index_to_reaction.values(), index_to_reaction.keys())) if the_problem == None or the_problem in ['return', 'setup'] or \ not isinstance(the_problem, LPX): lp = LPX() # Create empty problem instance lp.name = 'cobra' # Assign symbolic name to problem lp.rows.add(len(cobra_model.metabolites)) lp.cols.add(len(cobra_model.reactions)) linear_constraints = [] for r in lp.rows: the_metabolite = index_to_metabolite[r.index] r.name = the_metabolite.id b = float(the_metabolite._bound) c = the_metabolite._constraint_sense if c == 'E': r.bounds = b, b # Set metabolite to steady state levels elif c == 'L': r.bounds = None, b elif c == 'G': r.bounds = b, None #Add in the linear constraints for the_reaction in the_metabolite._reaction: reaction_index = reaction_to_index[the_reaction] the_coefficient = the_reaction._metabolites[the_metabolite] linear_constraints.append((r.index, reaction_index, the_coefficient)) #Need to assign lp.matrix after constructing the whole list lp.matrix = linear_constraints objective_coefficients = [] for c in lp.cols: the_reaction = index_to_reaction[c.index] c.name = the_reaction.id the_reaction = index_to_reaction[c.index] c.kind = variable_kind_dict[the_reaction.variable_kind] c.bounds = the_reaction.lower_bound, the_reaction.upper_bound objective_coefficients.append(float(the_reaction.objective_coefficient)) #Add the new objective coefficients to the problem lp.obj[:] = objective_coefficients else: lp = the_problem #BUG with changing / unchanging the basis if new_objective is not None: objective_coefficients = [] for c in lp.cols: # Iterate over all rows the_reaction = index_to_reaction[c.index] c.name = the_reaction.id c.bounds = the_reaction.lower_bound, the_reaction.upper_bound objective_coefficients.append(float(the_reaction.objective_coefficient)) c.kind = variable_kind_dict[the_reaction.variable_kind] #Add the new objective coefficients to the problem lp.obj[:] = objective_coefficients else: for c in lp.cols: # Iterate over all rows the_reaction = index_to_reaction[c.index] c.name = the_reaction.id c.bounds = the_reaction.lower_bound, the_reaction.upper_bound c.kind = variable_kind_dict[the_reaction.variable_kind] if objective_sense.lower() == 'maximize': lp.obj.maximize = True # Set this as a maximization problem else: lp.obj.maximize = False if the_problem == 'setup': return lp if print_solver_time: start_time = time() the_methods = [1, 2, 3] if lp_method in the_methods: the_methods.remove(lp_method) else: lp_method = 1 if not isinstance(the_problem, LPX): if lp.kind == int: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method) # we first have to solve the LP? lp.integer(tol_int=tolerance_integer) else: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method) # Solve this LP or MIP with the simplex (depending on if integer variables exist). Takes about 0.35 s without hot start if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status != 'optimal': for lp_method in the_methods: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method) if lp.status == 'opt': if lp.kind == int: lp.integer(tol_int=tolerance_integer) break else: if lp.kind == int: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method, tm_lim=100) # we first have to solve the LP? lp.integer(tol_int=tolerance_integer) else: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method, tm_lim=100) #If the solver takes more than 0.1 s with a hot start it is likely stuck if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status != 'optimal': if lp.kind == int: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method) # we first have to solve the LP? lp.integer(tol_int=tolerance_integer) else: for lp_method in the_methods: lp.simplex(tol_bnd=tolerance_optimality, tol_dj=tolerance_optimality, meth=lp_method) if lp.status == 'opt': if lp.kind == int: lp.integer(tol_int=tolerance_integer) break if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status != 'optimal': lp = optimize_glpk(cobra_model, new_objective=new_objective, objective_sense=objective_sense, min_norm=min_norm, the_problem=None, print_solver_time=print_solver_time, tolerance_optimality=tolerance_optimality, tolerance_feasibility=tolerance_feasibility)['the_problem'] if lp.status == 'opt': if lp.kind == int: lp.integer(tol_int=tolerance_integer) if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status != 'optimal': lp.simplex(tol_bnd=tolerance_optimality, presolve=True, tm_lim=5000) if lp.kind == int: lp.integer(tol_int=tolerance_integer) if print_solver_time: print 'simplex time: %f'%(time() - start_time) x = [] y = [] x_dict = {} y_dict = {} if lp.status in status_dict: status = status_dict[lp.status] else: status = 'failed' if status == 'optimal': objective_value = lp.obj.value [(x.append(float(c.primal)), x_dict.update({c.name:c.primal})) for c in lp.cols] if lp.kind == float: #return the duals as well as the primals for LPs [(y.append(float(c.dual)), y_dict.update({c.name:c.dual})) for c in lp.rows] else: #MIPs don't have duals y = y_dict = None x = array(x) else: x = y = x_dict = y_dict = objective_value = None if error_reporting: print 'glpk failed: %s'%lp.status the_solution = Solution(objective_value, x=x, x_dict=x_dict, y=y, y_dict=y_dict, status=status) solution = {'the_problem': lp, 'the_solution': the_solution} return solution
def setUp(self): self.lp = LPX() self.r = self.lp.rows self.c = self.lp.cols self.r.add(5) self.c.add(4)
def setUp(self): self.lp = LPX() self.vc = self.lp.cols # Vector collection is the column list. self.moreSetUp()
def setUp(self): self.lp = LPX() self.vc = self.lp.rows # Vector collection is the row list. self.moreSetUp()
def setUp(self): self.lp = LPX()
def setUp(self): self.lp = LPX() param_names = [n for n in dir(self.lp.params) if n[0] != '_'] param_names.remove('reset') self.param_name2default = dict([(n, getattr(self.lp.params, n)) for n in param_names]) # INTEGER PARAMETER VALUES # Have nice lists of, for each parameter, valid values, and # values illegal because they are of bad type or value. p2v, p2bt, p2bv = {}, {}, {} # These have legal values 0, 1 for n in 'price'.split(): p2v[n] = 0, 1 p2bv[n] = -100, -1, 2, 3, 4, 5 # These have legal values 0, 1,2 for n in 'branch mpsobj'.split(): p2v[n] = 0, 1, 2 # These have legal values 0, 1,2, 3 for n in 'msglev scale btrack'.split(): p2v[n] = 0, 1, 2, 3 # These all have the following illegal typed values. illegals = 'hi!', [1], {2: 5}, 0.5, complex(1, 0), self.lp for n in p2v: p2bt[n] = illegals # Set their illegal values. illegal_vals = -100, -1, 2, 3, 4, 5, 1000 for n in p2v: legals = set(p2v[n]) p2bv[n] = tuple([v for v in illegal_vals if v not in legals]) # These may be any positive integer. for n in 'outfrq'.split(): p2v[n] = 1, 2, 3, 100, 1600, 80000, 4000000, 2000000000 p2bt[n] = illegals p2bv[n] = 0, -1, -2, -3, -100, -100000 # These may be any integer. for n in 'itlim'.split(): p2v[n] = illegal_vals p2bt[n] = illegals # Integer in range 255. for n in 'usecuts'.split(): p2v[n] = range(0, 0x100) p2bt[n] = illegals p2bv[n] = tuple(range(-10, 0)) + tuple(range(0x100, 0x110)) # FLOAT PARAMETER VALUES # Previous illegal types included floats. illegals = tuple([iv for iv in illegals if type(iv) != float]) # Floats without bound. for n in 'objll objul outdly tmlim'.split(): p2v[n] = -1e100, -5.23e20, -2.231, -1, 0, 0.5, 1, 3.14159, 1e100 p2bt[n] = illegals # Bounded in [0, 1] range. for n in 'relax'.split(): p2v[n] = 0, .2, .45678, .901, 1 p2bv[n] = -5e6, -1, -0.01, 1.01, 1.5, 1000 p2bt[n] = illegals # Bounded in double-epsilon to 0.001 range. for n in 'tolbnd toldj tolint tolobj tolpiv'.split(): p2v[n] = 2.3e-16, 1e-8, 0.000523, 0.001 p2bv[n] = -1000, -1e-8, 0, 0.0011, 0.1, 5.123, 1e100 p2bt[n] = illegals # BOOLEAN PARAMETER VALUES # These have boolean values. They have no illegal values # owing to PyGLPK's pecularity of having boolean values set to # the bool(value) of value, which is always defined. bname = 'dual mpsfree mpsinfo mpsorig mpsskip mpswide presol round' for n in bname.split(): p2v[n] = False, True # Set up the mapping from parameter names to tuples of legal # values, and illegal params because of value and type. self.param_name2values = p2v self.param_name2bad_values = p2bv self.param_name2bad_type_values = p2bt
from glpk import LPX # set up to maximize the objective function lp = LPX() lp.name = 'foobartendr' lp.obj.maximize = True # append 3 rows row_names = ["ingrednt", "bartendr", "delivery"] lp.rows.add(len(row_names)) for r in lp.rows: r.name = row_names[r.index] lp.rows[0].bounds = None, 100.0 lp.rows[1].bounds = None, 600.0 lp.rows[2].bounds = None, 150.0 # append 3 cols, named x0, x1, x2 lp.cols.add(3) for c in lp.cols: c.name = 'x%d' % c.index c.bounds = 0.0, None # set the objective coefficients and # non-zero entries of the constraint matrix lp.obj[:] = [ 5.0, 3.0, 2.0 ] lp.matrix = [ 1.0, 1.0, 3.0, 10.0, 4.0, 5.0, 1.0, 1.0, 3.0 ] # report the objective function value and structural variables
def testObjectiveName(self): lp = LPX() with self.assertRaises(ValueError) as cm: lp.obj.name = 'a' * 256 self.assertIn('name may be at most 255 chars', str(cm.exception))
def testLpxStatus(self): lp = LPX() self.assertEqual('undef', lp.status_s)
def testObjectiveShift(self): lp = LPX() with self.assertRaises(TypeError) as cm: del(lp.obj.shift) self.assertIn('deletion not supported', str(cm.exception))