def __init__(self, Aeq, beq=None, Aineq=None, bineq=None, lb=None, ub=None, solver=solvers['default']): """ initialize the nonlinear problem Keyword arguments: Aeq -- matrix of equality constrains (Aeq * v = beq) beq -- right-hand side vector of equality constraints Aineq -- matrix of inequality constrains (Aineq * v <= bineq) bineq -- right-hand side vector of inequality constraints lb -- list of lower bounds (indexed like matrix columns) ub -- list of upper bounds (indexed like matrix columns) solver -- solver to be used for Nonlinear Programming """ LinearProblem.__init__(self, Aeq, beq, Aineq, bineq, lb, ub, solver) if solver.lower() in LinearProblem.solvers: # If problem has been raised from a linear problem, use default # solver. self.solver = NonLinearProblem.solvers["default"] self.obj = None self.d_obj = None self.nlc = None self.d_nlc = None self.x0 = [0.] * len(lb) self.iterator = None self.rlist = None
def __init__(self, Aeq, beq=None, Aineq=None, bineq=None, lb=None, ub=None, solver=solvers['default']): """ initialize the quadratic problem Keyword arguments: Aeq -- matrix of equality constrains (Aeq * v = beq) beq -- right-hand side vector of equality constraints Aineq -- matrix of inequality constrains (Aineq * v <= bineq) bineq -- right-hand side vector of inequality constraints lb -- list of lower bounds (indexed like matrix columns) ub -- list of upper bounds (indexed like matrix columns) solver -- solver to be used for Quadratic Programming """ LinearProblem.__init__(self, Aeq, beq, Aineq, bineq, lb, ub, solver) self.obj = QuadraticProblem.OoQp() if _cvxmod_avail: self.cvxmodMatrix = cvxmod_matrix(array(Aeq)) self.cvxmodV = optvar('v', self.cvxmodMatrix.size[1], 1) if _cvxpy_avail: self.cvxpyMatrix = array(Aeq) self.cvxpyV = Variable(self.cvxpyMatrix.shape[1], 1, name='v')
def run(self, objective, matrix, lb, ub, threshold=1.0, eqs=[], ineqs=[]): """ successively formulate and solve linear problems for each metabolite flux with inequality constraint 'objective value <= threshold' Arguments refer to split fluxes (i.e. non-negative flux variables). Keyword arguments: objective -- coefficient vector for linear objective function matrix -- stoichiometric matrix of the metabolic network lb -- list of lower bounds (indexed like matrix columns) ub -- list of upper bounds (indexed like matrix columns) threshold -- objective function threshold eqs -- list of (coefficient vector, right-hand side) pairs for additional equality constraints ineqs -- list of - '' - for additional inequality constraints Returns: list of minimum values, indexed like metabolites """ matrix = array(matrix) nMetabolites, nCols = matrix.shape if nMetabolites == 0: return [] # Nothing to do # Construct matrices of original equality and inequality constraints Aeq, beq, Aineq, bineq = FbAnalyzer.makeConstraintMatrices( matrix, eqs, ineqs) # Combine original inequality constraints and # 'objective function <= threshold' if Aineq is None: Aineq = [objective] bineq = [threshold] else: Aineq = vstack((Aineq, [objective])) bineq = append(bineq, threshold) result = [] ubVec = [] for i in range(nCols): # Impose artificial upper bounds so that all LPs are bounded if isinf(ub[i]): ubVec.append(LARGE_NUM) else: ubVec.append(ub[i]) psSplit = LinearProblem(Aeq, beq, Aineq, bineq, array(lb), array(ubVec), self.solver) # Compute coefficient vectors of producing metabolite fluxes # - pick only positive coefficients from stoichiometric matrix posMatrix = matrix.copy() for i in range(nMetabolites): for j in range(nCols): if posMatrix[i, j] < 0.: posMatrix[i, j] = 0. # Successively minimize each flux for index in range(nMetabolites): try: psSplit.setObjective(map(float, posMatrix[index, :])) except Exception: # Skip all-zero rows result.append(0.) continue minval, s = psSplit.minimize() psSplit.resetObjective() if len(s) == 0: result.append(nan) else: result.append(minval) return result
def run(self, objective, matrix, lb, ub, threshold=.95, eqs=[], ineqs=[]): """ successively formulate and solve linear problems for each flux with inequality constraint 'objective value <= threshold' Keyword arguments: objective -- coefficient vector for linear objective function matrix -- stoichiometric matrix lb -- list of lower bounds, indexed like reactions ub -- list of upper bounds, indexed like reactions threshold -- objective function threshold eqs -- list of (coefficient vector, right-hand side) pairs for additional equality constraints ineqs -- list of - '' - for additional inequality constraints Returns: list of pairs (minimum, maximum), indexed like reactions """ # Construct matrices of original equality and inequality constraints Aeq, beq, Aineq, bineq = FbAnalyzer.makeConstraintMatrices( matrix, eqs, ineqs) #lb = [-1000]*939 #ub = [1000]*939 # Combine original inequality constraints and # 'objective function <= threshold' if Aineq is None: Aineq = [objective] bineq = [threshold] else: Aineq = vstack((Aineq, [objective])) bineq = append(bineq, threshold) nReactions = len(lb) lbVec, ubVec = [], [] for i in range(nReactions): if isinf(lb[i]): lbVec.append(-LARGE_NUM) else: lbVec.append(lb[i]) if isinf(ub[i]): ubVec.append(LARGE_NUM) else: ubVec.append(ub[i]) ps = LinearProblem(Aeq, beq, Aineq, bineq, lbVec, ubVec, self.solver) minmax = [None] * nReactions # First maximize each flux for index in range(nReactions): ps.setObjective([0.] * index + [-1.] + [0.] * (nReactions - index - 1)) s = ps.minimize()[1] ps.resetObjective() # catch random infeasible solution that resolves if the solver is recreated if len(s) == 0: ps = LinearProblem(Aeq, beq, Aineq, bineq, lbVec, ubVec, self.solver) ps.setObjective([0.] * index + [-1.] + [0.] * (nReactions - index - 1)) s = ps.minimize()[1] ps.resetObjective() if len(s) != 0: maxval = s[index] else: maxval = nan s = None minmax[index] = maxval # Now minimize each flux for index in range(nReactions): ps.setObjective([0.] * index + [1.] + [0.] * (nReactions - index - 1)) s = ps.minimize()[1] ps.resetObjective() # catch random infeasible solution that resolves if the solver is recreated if len(s) == 0: ps = LinearProblem(Aeq, beq, Aineq, bineq, lbVec, ubVec, self.solver) ps.setObjective([0.] * index + [-1.] + [0.] * (nReactions - index - 1)) s = ps.minimize()[1] ps.resetObjective() if len(s) != 0: minval = s[index] else: minval = nan s = None minmax[index] = minval, minmax[index] return minmax
class FbAnalyzer(object): """ Class for flux-balance analysis """ def __init__(self, solver="default"): """ initialize FBA class Keyword arguments: solver -- name of the solver to be used for the LP/QP/NLP """ self.solver = solver @staticmethod def splitFluxes(matrix, reaction_names, lb, ub): """ split the fluxes into non-negative components This is done by duplicating and negating matrix columns for reversible reactions and just negating the matrix columns corresponding to flipped irreversible reactions. Keyword arguments: matrix -- the stoichiometric matrix reaction_names -- list of reactions (indexed like matrix columns) lb -- list of lower bounds (indexed like matrix columns) ub -- list of upper bounds (indexed like matrix columns) Returns: matrixSplit, reactionsSplit, lbSplit, ubSplit matrixSplit -- matrix with extra columns for negative flux components reactionsSplit -- dictionary { name : pair of indexes } - indexes can be None; if both are not None, the first is the pos. and the second is the neg. component (v = v[0] - v[1]) lbSplit -- list of lower bounds (indexed like columns of matrixSplit) ubSplit -- list of upper bounds ( - '' - ) """ matrixSplit = matrix.copy() # Perform deep copy reactionsSplit = {} lbSplit = [] ubSplit = [] newIndex = 0 # Index in matrixSplit for i in range(len(reaction_names)): rea = reaction_names[i] if lb[i] >= 0.: # Reaction is irreversible (pos. flux only or restricted to 0) reactionsSplit[rea] = (newIndex, None) lbSplit.append(lb[i]) ubSplit.append(ub[i]) elif ub[i] <= 0.: # Reaction is irreversible & flipped => negate reactionsSplit[rea] = (None, newIndex) matrixSplit[:, newIndex] *= -1 lbSplit.append(-ub[i]) ubSplit.append(-lb[i]) else: # Reaction is reversible => split (copy, then negate the copy) reactionsSplit[rea] = (newIndex, newIndex + 1) matrixSplit = insert(matrixSplit, newIndex + 1, -matrixSplit[:, newIndex], axis=1) lbSplit.append(0.) ubSplit.append(ub[i]) lbSplit.append(0.) ubSplit.append(-lb[i]) newIndex += 1 newIndex += 1 return matrixSplit, reactionsSplit, lbSplit, ubSplit @staticmethod def splitFluxVector(vec, reaction_names, reactionsSplit): """ split the given vector as described by reactionsSplit Keyword arguments: vec -- the flux vector to be split reaction_names -- list of reactions corresponding to entries of vec reactionsSplit -- dictionary { name : tuple of indexes } - indexes can be None; if both are not None, the first is the pos. and the second is the neg. component (v = v[0] - v[1]) (as computed by FbAnalyzer.splitFluxes) Returns: split vector (containing only non-negative values) """ vecSplit = [] for i in range(len(reaction_names)): rea = reaction_names[i] indexPos, indexNeg = reactionsSplit[rea] if len(reactionsSplit[rea]) != 2: raise TypeError("reactionsSplit tuples must exactly 2 entries") if vec[i] == 0.: if indexPos is not None: vecSplit.append(0.) if indexNeg is not None: vecSplit.append(0.) elif vec[i] > 0.: if indexPos is None: print rea, indexPos, indexNeg raise ValueError("Value %u (%g) out of range in split " "vector (must not be positive)" % (i, vec[i])) vecSplit.append(vec[i]) if indexNeg is not None: vecSplit.append(0.) else: if indexPos is not None: vecSplit.append(0.) if indexNeg is None: raise ValueError("Value %u (%g) out of range in split " "vector (must not be negative)" % (i, vec[i])) vecSplit.append(-vec[i]) return vecSplit @staticmethod def rejoinFluxes(solutionSplit, reactionsSplit, reactions): """ rejoin the fluxes in the given solution by applying reactionsSplit This assumes that solutionSplit has been obtained by performing FBA on the split matrix corresponding to reactionsSplit. This function combines the split fluxes by subtracting the negative component from the positive one. Keyword arguments: solutionSplit -- vector of non-negative fluxes reactionsSplit -- dictionary { name : tuple of indexes } - indexes can be None; if both are not None, the first is the pos. and the second is the neg. component (v = v[0] - v[1]) (as computed by FbAnalyzer.splitFluxes) reactions -- dictionary of all reactions { name : original matrix column } Returns: joined flux vector (indexed like original matrix columns) """ if len(solutionSplit) == 0: return solutionSplit # Nothing to do solution = [0.] * len(reactions) for rea in reactionsSplit: rea_index_orig = reactions[rea] indexPos, indexNeg = reactionsSplit[rea] if indexPos is not None: solution[rea_index_orig] += solutionSplit[indexPos] if indexNeg is not None: solution[rea_index_orig] -= solutionSplit[indexNeg] return solution @staticmethod def makeConstraintMatrices(matrix, eqs, ineqs): """ transform the given matrix and equality and inequality constraints to left-hand-side matrices and right-hand-side vectors of equality and inequality constraints Keyword arguments: matrix -- the stoichiometric matrix of the metabolic network eqs -- list of (coefficient vector, right-hand side) pairs for the equality constraints ineqs -- list of - '' - for the inequality constraints """ if eqs: Aeq = vstack((matrix, array([row[0] for row in eqs]))) beq = array([0.] * len(matrix) + [row[1] for row in eqs]) else: Aeq = matrix beq = array([0.] * len(matrix)) if ineqs: Aineq = array([row[0] for row in ineqs]) bineq = array([row[1] for row in ineqs]) else: Aineq, bineq = None, None return Aeq, beq, Aineq, bineq def run(self, reactions, matrix, lb, ub, fbaParams): """ analyze objective function, and solve the LP/QP/NLP Keyword arguments: reactions -- dictionary of all reactions { name : matrix column } or { name : tuple of indices } for split fluxes matrix -- the stoichiometric matrix of the metabolic network lb -- list of lower bounds (indexed like matrix columns) ub -- list of upper bounds (indexed like matrix columns) fbaParams -- optimization parameters (incl. objective function) Returns: obj_value, solution obj_value -- optimal value of objective function solution -- a solution where the objective function assumes obj_value """ maxmin, objStr, numIter = (fbaParams.maxmin, fbaParams.objStr, fbaParams.numIter) # Multiply by -1 for maximization maxmin_factor = -1. if maxmin == True else 1. nCols = len(lb) threshold = 0.95 nReactions = len(lb) # Get additional linear equality and inequality constraints try: Aeq, beq, Aineq, bineq = self.makeConstraintMatrices( matrix, *ParamParser.linConstraintsToVectors(fbaParams.linConstraints, reactions, nCols)) except ValueError: # If any linear constraint is contradictory, return empty solution return 0., [] try: objective = ParamParser.convertObjFuncToLinVec( objStr, reactions, nCols, maxmin) except Exception, strerror: print( "Error while trying to build coefficient vector of " "linear objective function:") print strerror exit() if fbaParams.nlc == []: if Aineq is None: Aineq = [objective] bineq = [threshold] else: Aineq = vstack((Aineq, [objective])) bineq = append(bineq, threshold) # Linear function and linear constraints only # If flux variables are not split, use GLPK through OpenOpt solver = (_OOGLPK if self.solver.lower() == _GLPK and nCols == len(reactions) else self.solver) try: ps = LinearProblem(Aeq, beq, Aineq, bineq, lb, ub, solver) except ValueError, strerror: print strerror exit() #print "lb:", len(lb) minmax = [None] * nReactions # First maximize each flux for index in range(nReactions): ps.setObjective([0.] * index + [-1.] + [0.] * (nReactions - index - 1)) #print len([0.]*index+[-1.]+[0.]*(nReactions-index-1)) obj_value, solution = ps.minimize() ps.resetObjective() minmax[index] = obj_value print minmax
exit() if start_value_total is None or start_value_total < 0.: start_value_total = float(len(reactions)) # Prepare left and right border for binary search l = start_value_total / 2. r = start_value_total * 1.5 m = start_value_total # Use GLPK through OpenOpt solver = (_OOGLPK if (self.solver.lower() == _GLPK or self.solver.lower() == "default") else self.solver) try: ps = LinearProblem(Aeq, beq, Aineq, bineq + [m], lb, ub, solver) # ps = LinearProblem(Aeq, beq, lb=lb, ub=ub, solver=solver) except ValueError, strerror: print strerror exit() ps.setObjective(objective) # ps.setInequalityConstraints(Aineq, bineq+[m]) try: m_value = ps.minimize()[0] except ValueError, strerror: if self.solver == "default": print "Default solver reported an error:" else: print "Solver %s reported an error:" % self.solver
objective = ParamParser.convertObjFuncToLinVec(objStr, reactions, nCols, maxmin) except Exception, strerror: print ("Error while trying to build coefficient vector of " "linear objective function:") print strerror exit() if fbaParams.nlc == []: # Linear function and linear constraints only # If flux variables are not split, use GLPK through OpenOpt solver = (_OOGLPK if self.solver.lower() == _GLPK and nCols == len(reactions) else self.solver) try: ps = LinearProblem(Aeq, beq, Aineq, bineq, lb, ub, solver) except ValueError, strerror: print strerror exit() #print "lb:", len(lb) ps.setObjective(objective) else: # Linear function but nonlinear constraints try: ps = NonLinearProblem(Aeq, beq, Aineq, bineq, lb, ub, self.solver) except ValueError, strerror: print strerror exit() ps.setObjective(lambda x : dot(x, objective))