def selectSubMatrix(self, model, rowFilter = None, columnFilter = None, union = False): regexRow = None regexColumn = None if rowFilter != None: regexRow = re.compile(rowFilter) if columnFilter != None: regexColumn = re.compile(columnFilter) result = LinearModel() for key in model.data.keys(): (rowName,columnName) = key value = model.getData(rowName,columnName) if regexRow: rowCheck = regexRow.match(rowName) else: rowCheck = False if regexColumn: columnCheck = regexColumn.match(columnName) else: columnCheck = False if union: if rowCheck and columnCheck: result.addData(rowName,columnName,value) else: if rowCheck or columnCheck: result.addData(rowName,columnName,value) return result
def _constructDualRegulation(self,model,names,prefix): ''' Construct limit / freedom variable for dual These are the dual analog control variables S'lambda + ... - delta - c' = 0 ''' rName = self.dualRName + prefix jmodel = LinearModel() equation = "%s" % (self.cdName) jmodel = self.parseEquations.applyRelation(jmodel,rName,equation,names,prefixPattern="%s"+prefix) imodel = LinearModel() for name in names: rName = self.dualRName + prefix + name sName = self.cdName + prefix + name imodel.addData(rName,sName,1) imodel.addColumnLimit(sName,(None,None)) if not imodel == jmodel: print "---------------------------------apply equation faliure: Dual control-----------------------------------------" model.addConstraints(imodel) return model
def findBoundaryProduction(originalModel, bounds, combiLimits, objectiveName, productionName): model = LinearModel() model.extend(originalModel) if combiLimits != None: for (targetValues,limit) in combiLimits: model = addCombinationLimit(model, targetValues,limit) #objectiveMap = {objectiveName:-1.0} objectiveMap = {productionName:1.0} model.addColumnLimits(bounds) lp = LPSolver() fluxMap = lp.run(model,objectiveMap) objectiveValue = fluxMap[objectiveName] productionValue = fluxMap[productionName] return (fluxMap,objectiveValue,productionValue)
def findMinMax(self, model, objectiveName, minValue, targets): positive = {} negative = {} imodel = LinearModel() imodel.extend(model) if minValue < 0: imodel.addColumnLimit(objectiveName,(None,minValue)) else: imodel.addColumnLimit(objectiveName,(minValue,None)) lp = LinearOptimization() lp.setModel(model) for t in targets: lp.clearObjective() lp.setObjectiveMap({t: -1}) lp.runSimplex() fluxes = lp.getPredictionMap() lowValue = fluxes[t] negative[t] = lowValue lp.clearObjective() lp.setObjectiveMap({t: 1}) lp.runSimplex() fluxes = lp.getPredictionMap() highValue = fluxes[t] positive[t] = highValue return (positive,negative)
def construct(self,model,controlNames,newObjective): ''' Top Level Function Build Complete Framework ''' self.newObjective = newObjective result = LinearModel() result.addModel(model) sObjective = self._scaleMap(model.getObjective(),self.objectiveCoeffecent) sObjective[self.newObjective] = .01 result.setObjective(sObjective) for (libName,libPrefix) in self.libdata: result = self._constructRegulationObjecive(result, controlNames, libName, libPrefix, -1.0) pass result = self._primalDual(result, result.getObjective()) for (libName,libPrefix) in self.libdata: result = self.constructControl(result,controlNames,libPrefix,libName) if self.rGeneMap != None: self.geneControl(result,libPrefix + "y__",controlNames,libName) if self.simoLimit !=0: result = self._controlValueLimit(result,controlNames,postfix="y__") return result
def generateModel(self, modelName=None): if modelName == None: modelName = self.modelName dir = self.basedir model = None fluxLimits = None objective = None if self.rxnfile != '': rxnFile =dir + self.rxnfile model = self.rxnParser.parse(rxnFile) else: model = LinearModel() if self.fluxlimitfile != '': fluxLimitFile = dir + self.fluxlimitfile fluxLimits = self.limitParser.parse(fluxLimitFile) else: fluxLimits = {} if self.objectivefile != '': objectiveFile = dir + self.objectivefile objective = self.objParser.parse(objectiveFile) else: objective = {} if self.directionCheck: #fluxLimits = self.checkDirectionality(network, fluxLimits) pass model.addColumnLimits(fluxLimits) for (key,value) in objective.items(): model.addObjective(key, value) for name in model.getRowNames(): model.addRowLimit(name, (0.0,0.0)) return model
def _parseNetwork(self,network,limits): result = LinearModel() result.data.rowCache.extend(network.speciesCache) result.data.columnCache.extend(network.reactionCache) result.addDataCache(network.dataCache) rowNames = network.getOrderedSpeciesNames() columnNames = network.getOrderedReactionNames() for rowName in rowNames: result.addRowLimit(rowName,(0.0,0.0)) for columnName in columnNames: if columnName in limits.keys(): (lower,upper) = limits[columnName] result.addColumnLimit(columnName,(lower,upper)) return result
def parse( self, file ): model = LinearModel() rxnParser = ReactionEquationParser() self.startFile(file) d = self.getTagedLine() annotation = {} while d != None: if d != "": (reaction,direction) = rxnParser.parseEquation(d["Equation"]) name = d["Name"] model.addColumn(name, reaction) model.addColumnLimit(name, direction) annotation[name] = d.annotation d = self.getTagedLine() self.closeFile() model.annotation = annotation return model
def _constructControl(self,model,controlNames,binaryPrefix,controlValuePref,regPrefix,climits,zero): ''' Create binary control variables one = off: if y = 0: low < v < high if y = 1: v = 0 v + high*y <= high v + low*y >= low zero = off: if y = 1: 0 < v < d if y = 0: v = 0 v - high*y <= 0 v - low*y >= 0 ==> for v in reaction targets pc: v - high*pc < 0 nc: v - low* < 0 ''' binaryLimitName = "control_" posControlRow = regPrefix+"_pc_" negControlRow = regPrefix+"_nc_" jmodel = LinearModel() if zero: equation1 = "%s_pc_%s:%s + %s %s < 0" % (regPrefix,"%s",controlValuePref,-1.0*self.posControlBound,binaryPrefix) equation2 = "%s_nc_%s:%s + %s %s > 0" % (regPrefix,"%s",controlValuePref,-1.0*self.negControlBound,binaryPrefix) else: equation1 = "%s_pc_%s:%s + %s %s < %s" % (regPrefix,"%s",controlValuePref,self.posControlBound,binaryPrefix,self.posControlBound) equation2 = "%s_nc_%s:%s + %s %s > %s" % (regPrefix,"%s",controlValuePref,self.negControlBound,binaryPrefix,self.negControlBound) jmodel = self.parseEquations.applyRelation(jmodel,posControlRow,equation1,controlNames,prefixPattern="%s") jmodel = self.parseEquations.applyRelation(jmodel,negControlRow,equation2,controlNames,prefixPattern="%s") result = LinearModel() for columnName in controlNames: iCName = binaryPrefix + columnName iDName = controlValuePref + columnName posControlName = regPrefix + "_pc_" + columnName negControlName = regPrefix + "_nc_" + columnName if columnName in climits and False: # this method is currently broken (negBound,posBound) = climits[columnName] if negBound == None: negBound = self.negControlBound if posBound == None: posBound = self.posControlBound else: posBound = self.posControlBound negBound = self.negControlBound ''' y = 1: l < v < u ''' if(zero): result.addData(posControlName,iDName,1.0) result.addData(negControlName,iDName,1.0) result.addData(posControlName,iCName,-posBound) result.addData(negControlName,iCName,-negBound) result.addRowLimit(posControlName,(None,0.0)) result.addRowLimit(negControlName,(0.0,None)) else: result.addData(posControlName, iDName, 1.0) result.addData(negControlName, iDName, 1.0) result.addData(posControlName, iCName, posBound) result.addData(negControlName, iCName, negBound) result.addRowLimit(posControlName,(None,posBound)) result.addRowLimit(negControlName,(negBound,None)) jmodel.columnLimits = {} if not result == jmodel: #print "---------------------------------apply equation failure: control-----------------------------------------" #! currently apply version does not handleA a map/list of boundary values pass model.addConstraints(result) ''' w is limit of controls y is actual control state variable w - y = 0 as starting state ie all controls default to 0 sum w > control min sum w < control max ''' self.parseEquations.defaultLimit = (0.0,1.0) iCName = binaryPrefix iDName = controlValuePref rowName = "_rcr_" + binaryPrefix equation = "_rcr_%s:_rc_%s + -1.0 %s = 0" % (binaryPrefix+"%s",iCName,iCName) jmodel = LinearModel() jmodel = self.parseEquations.applyRelation(jmodel,rowName,equation,controlNames,prefixPattern="%s") jmodel.setMipColumnNames(controlNames,tag=iCName+"%s") self.parseEquations.defaultLimit = (None,None) result = LinearModel() for columnName in controlNames: iCName = binaryPrefix + columnName iDName = controlValuePref + columnName result.setMipColumnName(iCName) result.addColumnLimit(iCName,(0.0,1.0)) result.addColumnLimit("_rc_" + iCName,(0.0,1.0)) result.addData("_rcr_" + iCName, "_rc_" + iCName, 1.0) result.addData("_rcr_" + iCName, iCName, -1.0) result.addRowLimit("_rcr_" + iCName, (0.0,0.0)) if not result == (jmodel): print "---------------------------------apply equation failure: control-----------------------------------------" for columnName in controlNames: iCName = binaryPrefix + columnName iDName = controlValuePref + columnName result.addData(binaryLimitName,"_rc_"+ iCName,1.0) #Limit on control variables result.addRowLimit(binaryLimitName,(self.controlMin,self.controlMax)) model.addConstraints(result) return model
def _constructRegulationObjecive(self,model,names,lib,prefix,dir): ''' Hybrid Objective Z += C'v + A'n Control of adjustment objective in hybrid objective if y = 1: n = v, d=0 if y = 0: n = 0, d=v ==> n + d - v = 0 -G * (y(i)) <= n <= G * (y(i)) : objective coefficient -G * (1-y(i))<= d <= G * (1-y(i)) : slack variable ==> n + d - v = 0 0 <= n + G * y(i) n - G * y(i) <= 0 0 <= d + (1- y(y(i)) * G d - (1 - y(i)) * G <= 0 it is important to only create controls for coefficients that exist in the library ''' #! This is a new addition and may change the way RD works. Added to fix target / lib comparison failure. names = self._confirmControlTargets(lib, names) limits = model.getColumnLimits() rName = prefix + "reg__" jmodel = LinearModel() equation = "%s:n + d + %sI= 0" % (prefix+ "reg__%s",dir) jmodel = self.parseEquations.applyRelation(jmodel,rName,equation,names,prefixPattern=prefix+"%s__") imodel = LinearModel() rName = prefix + "reg__" for name in names: if name in limits: limit = limits[name] else: limit = (self.negfluxControlBound,self.posfluxControlBound) vName = name rName = prefix + "reg__" + name cName = prefix + "n__" + name dName = prefix + "d__" + name imodel.addColumnLimit(cName,(None,None)) imodel.addColumnLimit(dName,(None,None)) #!imodel.addColumnLimit(cName,(limit[0],limit[1])) #!imodel.addColumnLimit(dName,(limit[0],limit[1])) imodel.addRowLimit(rName,(0.0,0.0)) imodel.addData(rName, vName, dir) imodel.addData(rName, cName, 1.0) imodel.addData(rName, dName, 1.0) if not jmodel == imodel: print "----------------------------apply equation failure-----------------------------" model.addConstraints(imodel) ''' Z^hybrid = C^nat*v + C^adj*n ''' objective = {} originalObjective = model.getObjective() objective.update(originalObjective) imodel = LinearModel() #Set coefficients for controls for name in names: iname = prefix + "n__" + name coeffecent = self._getRegulationCoeffecent(lib,name) iCoeffecent = float(coeffecent) * float(self.regCoeffecent) objective[iname] = -iCoeffecent imodel.addData("adjValue",iname,-iCoeffecent) #This constraint maybe cause of failure because of overloading of coefficients * fluxes in dual #This constraint combined with the use of the control penalty causes infeasibility issues #imodel.addRowLimit("adjValue",(None,None)) #model.addConstraints(imodel) jmodel = LinearModel() equation = "adjValue%s:objectiveVar + adjVar = 0" jmodel = self.parseEquations.applyRelation(jmodel,relationName="adjValue",value=equation,targets=[''],prefixPattern="%s") del jmodel.columnLimits["objectiveVar"] jmodel.addColumnLimit("objectiveVar",(None,None)) imodel = LinearModel() imodel.addData("adjValue","objectiveVar",1) imodel.addData("adjValue","adjVar",1) imodel.addRowLimit("adjValue",(0,0)) imodel.addColumnLimit("adjVar",(None,None)) imodel.addColumnLimit("objectiveVar",(None,None)) if not jmodel == imodel: print "---------------------------------apply equation faliure: control objective-----------------------------------------" #This constraint maybe cause of failure because of overloading of coefficients * fluxes in dual #This constraint along with a control penalty causes infeasibility issues in the optimization #model.addConstraints(imodel)#! consider removing to insure that adjValue is not messing up the system model.setObjective(objective) return model
def _primalDual(self,model,objective,prime=True,dual=True,equal=True): ''' class PathwayTarget: @type model: LinearModel @rtype: LinearModel Construct Core Linear Optimization Matrix with primal dual equality row i and column j Primal: min Z = sum(j): [c(j)*v(j)] ST. sum(j) [S(ij)*v(j)] = 0 E i l(j) < v(j) < u(j) E j Hameltonian: Max(lambda,mu,nu): Min(v): sum(j)c(j)*v(j) + sum(i)lambda(i)*S(ij)v(j) + mu(j)(l(j)-v(j)) + nu(j)(v(j)-u(j)) => c'v + lambda*(Sv) + mu(l-v) + nu(v-u) => Max: mu*l - nu*u ST c + lambda*S + mu + nu = 0 Dual: max Z_dual = l*mu - u*nu ST. S'*lambda - mu + nu = -c' mu(j) > 0 E j nu(j) > 0 E j Equality condition: Z = Z_dual ==> sum(j) [c(j)'*v(j)] = sum(j) [l(j)*mu(j) - u(j)*nu] ==> -c*v + mu*l - u*nu = 0 ''' pName = self.pName dName = self.dName result = LinearModel() #Primal: if prime: #S*v for (row, column, value) in model.getSparseMatrix(): result.addData(self.primeRName + row, pName + column, value) #S*v <=> b for row in model.getRowLimits().keys(): result.addRowLimit(self.primeRName + row, model.getRowLimit(row)) #u<=v<=l for column in model.getColumnNames(): result.addColumnLimit(pName + column, model.getColumnLimit(column)) #Dual: if dual: #S'*lambda for (row, column, value) in model.getSparseMatrix(): result.addData(self.dualRName + column, dName + row, value) #lambda <=> +- inf for row in model.getRowLimits().keys(): result.addColumnLimit(dName + row, (None,None)) #S'*lambda = -c' for column in model.getColumnNames(): if column in objective.keys(): value = objective[column] result.addRowLimit(self.dualRName + column, (-value, -value)) else: result.addRowLimit(self.dualRName + column, (0.0, 0.0)) #S'*lambda - mu + nu = -c' for column in model.getColumnLimits().keys(): (lower, upper) = model.getColumnLimit(column) if lower != None: result.addData(self.dualRName + column, '__mu__' + column, -1) result.addColumnLimit('__mu__' + column, (0.0, None)) if upper != None: result.addData(self.dualRName + column, '__nu__' + column, 1) result.addColumnLimit('__nu__' + column, (0.0, None)) if equal: #objective relation #Z^prime = Z^dual # cv = l*mu - u*nu = 0 # -cv + l*mu - u*nu = 0 for column in model.getColumnNames(): if column in objective.keys(): value = objective[column] result.addData(self.equalityRName, pName + column, -value) else: result.addData(self.equalityRName, pName + column, 0) for column in model.getColumnLimits().keys(): (lower, upper) = model.getColumnLimit(column) if lower != None and lower != 0.0: result.addData(self.equalityRName, '__mu__' + column, lower) if upper != None and upper != 0.0: result.addData(self.equalityRName, '__nu__' + column, -upper) result.addRowLimit(self.equalityRName,(0,0)) objective = {} objective[self.pName + self.newObjective] = -1 result.setObjective(objective) return result
def LinearModelVariableBoundarys(originalModel, objectiveName, targets=None, pickleFileName=None, strict=False, minObjectivePercent=None,searchSize=1): ''' Find min and max boundaries for the dependent variables of a linear model. Uses limitMap as constraints on model. Add cumulative boundary persistence as pickle file function. @param linearModel: linear model to be analyzed @type linearModel: LinearModel @param limitMap: map of variable names and lower and upper limits @type limitMap: {variableName, (float, float) @param targets: list of variables to perform analysis on @type targets: list @return: dictionary of lower and upper limits for each variable @rtype: {variableName: (lowerlimit, upperlimit)} ''' linearModel = LinearModel() linearModel.extend(originalModel) if pickleFileName != None: if os.path.isfile(pickleFileName): print "loading saved flux boundaries" pFile = open(pickleFileName) result = pickle.load(pFile) pFile.close() return result originalLimits = linearModel.getColumnLimits() originalObjectiveLimit = originalLimits[objectiveName] objectiveVector = {objectiveName:-1.0} solver = LPSolver() originalValues = solver.run(model=linearModel, objective=objectiveVector) originalObjectiveValue = originalValues[objectiveName] if minObjectivePercent != None: minObjectiveValue = originalObjectiveValue * minObjectivePercent linearModel.addColumnLimit(objectiveName,(minObjectiveValue,None)) if targets == None: targets = linearModel.getColumnNames() targets.add(objectiveName) print "Searching flux boundaries for %s > %s" % (objectiveName, minObjectiveValue) result = {} targetValues = targetValueCombinations(targets, [-1.0,1.0]) controlSubSets = combinations(targetValues,searchSize) xcontrolSubSets = set(controlSubSets) for name in targets: nameTag = name # if name not in linearModel.getColumnNames(): # print "target %s not found in model" # print "boundary discovery not possible" # continue #for iTargetValues in xcontrolSubSets: # name = "testControlValue" # nameTag = iTargetValues # linearModel = combinationLimitBuilder(linearModel, iTargetValues, name) result[name] = (None,None) negObjective = {name:1.0} posObjective = {name:-1.0} solver.clearObjective() negValues = solver.run(linearModel, objective=negObjective) negValue = negValues[name] solver.clearObjective() posValues = solver.run(linearModel, objective=posObjective) posValue = posValues[name] delta = 1e-4 if posValue != 0 or negValue !=0: pass if False: originalValue = originalValues[name] originalLimit = originalLimits[name] if not (negValue - delta <= originalValue <= posValue + delta): print "original value not in boundary" print "objective value [%s] (%s) %s <= %s <= %s (%s)" % (name, originalLimit[0], negValue, originalValue, posValue, originalLimit[1]) #print "value neg code %s pos code %s" % (nscode, pscode) (negValue,posValue) = (originalLimit[0],originalLimit[1]) else: #print "objective value [%s] (%s) %s <= %s <= %s (%s)" % (name, originalLimit[0], negValue, originalValue, posValue, originalLimit[1]) pass if negValue == None or negValue == float("-inf"): continue if posValue == None or posValue == float("-inf"): continue result[nameTag] = (negValue,posValue) print "%s < [%s] < %s " % (negValue,nameTag,posValue) if pickleFileName != None: pFile = open(pickleFileName,'w') pickle.dump(result, pFile) pFile.close() solver.clear() del solver linearModel.addColumnLimit(objectiveName,originalObjectiveLimit) #targets.remove(objectiveName) return result