00001
00002 """
00003 ScrumPyLP - (c) Mark Poolman 2008 onwards.
00004 A module to allow LP optimisation and analysis of of metabolic models with ScrumPy.
00005
00006
00007 This module is still experimental and is
00008
00009 ************************* NOT TO BE REDISTRIBUTED ***************************
00010
00011 without the prior consent of the author.
00012
00013 """
00014
00015
00016
00017
00018
00019
00020 import sys, types, exceptions
00021
00022 SysStderr = sys.stderr
00023 NullF = open("/dev/null", "w")
00024
00025
00026 import glpk
00027
00028 from Util import Set, DynMatrix
00029 from Data import DataSets
00030 from Structural import StoMat
00031
00032
00033 def SplitRev(sm,Conv=float):
00034
00035 rv = sm.Copy(Conv)
00036 rv.Reversed = reversed = []
00037 rv.Backs = backs = []
00038
00039 for r in sm.cnames:
00040 if sm.RevProps[r] == StoMat.t_Rever:
00041 sto = sm.InvolvedWith(r)
00042 rback = r+"_back"
00043 rv.NewReaction(rback,sto)
00044 rv.MulCol(rback,k=-1)
00045 backs.append(rback)
00046
00047 elif sm.RevProps[r] == StoMat.t_BackIrrev:
00048 sm.MulCol(r, k=-1)
00049 reversed.append(r)
00050
00051 return rv
00052
00053 def SplitRevOld(sm,Conv=float):
00054 sm = sm.Copy(Conv)
00055 revs = Set.Complement(sm.cnames, sm.Irrevs)
00056 backs = []
00057 for r in revs:
00058 sto = sm.InvolvedWith(r)
00059 for met in sto:
00060 sto[met] *= -1
00061 rback = r+"_back"
00062 sm.NewReaction(rback,sto)
00063 backs.append(rback)
00064 sm.Irrevs = sm.cnames[:]
00065 sm.Backs = backs
00066 return sm
00067
00068
00069
00070 def SplitAll(sm,Conv=float):
00071
00072 sm = sm.Copy(Conv)
00073 irbacks = []
00074 for r in sm.cnames[:]:
00075 sto = sm.InvolvedWith(r)
00076 for met in sto:
00077 sto[met] *= -1
00078 newreac = r+"_back"
00079 sm.NewReaction(newreac,sto)
00080 if r in sm.Irrevs:
00081 irbacks.append(newreac)
00082
00083 sm.Irrevs = sm.cnames[:]
00084 sm.irbacks = irbacks
00085 return sm
00086
00087
00088
00089 class lp(glpk.lp):
00090
00091 def __init__(self, model):
00092
00093 name = model.FileName.split("/")[-1].split(".")[0]
00094 sm = self.sm = SplitRev(model.sm)
00095
00096 glpk.lp.__init__(self,name)
00097 self.AddRows(sm.rnames[:])
00098 self.AddCols(sm.cnames[:])
00099 for reac in sm.cnames:
00100 self.SetColBounds(reac,0)
00101
00102 for row in sm.rnames:
00103 self.SetRowVals(row, map(float, sm[row]))
00104 self.SetRowBounds(row, 0,0)
00105
00106
00107 def _irrev_check(self,reac,rate):
00108 print "_irev_check disabled"
00109 return
00110
00111
00112
00113
00114
00115
00116
00117 def _BackReac(self, reac):
00118
00119 rback = reac + "_back"
00120 if rback in self.sm.Backs:
00121 return rback
00122 return None
00123
00124
00125 def SetObjective(self,reacs):
00126
00127 if type(reacs)==types.DictType:
00128 reacs = dict(reacs)
00129 for reac in reacs.keys():
00130 back = self._BackReac(reac)
00131 if back != None:
00132 reacs[back] = reacs[reac]
00133 self.SetObjCoefsFromDic(reacs)
00134
00135 else:
00136 reacs = reacs[:]
00137 for reac in reacs:
00138 back = self._BackReac(reac)
00139 if back != None and back not in reacs:
00140 reacs.append(back)
00141 self.SetObjCoefsFromLists(reacs,[1]*len(reacs))
00142
00143 def SetObjCoef(self, c, coef):
00144
00145 glpk.lp.SetObjCoef(self, c, coef)
00146
00147 if not self.sm.IsIrrev(c):
00148 glpk.lp.SetObjCoef(self, c+"_back", coef)
00149
00150
00151
00152
00153
00154 def SetFixedFlux(self, reacs):
00155
00156 for reac in reacs:
00157
00158 rate = reacs[reac]
00159 if reac in self.sm.Reversed:
00160 rate *= -1
00161
00162 rback = reac + "_back"
00163 hasback = rback in self.sm.Backs
00164
00165 if rate >= 0:
00166 self.SetColBounds(reac, rate, rate)
00167 if hasback:
00168 self.SetColBounds(rback, 0,0)
00169 else:
00170 if not hasback:
00171 sys.stderr.write("! Setting inconsitant flux in irreversible reaction %s\n" % reac)
00172 self.SetColBounds(reac, rate, rate)
00173 else:
00174 self.SetColBounds(reac, 0, 0)
00175 self.SetColBounds(rback, -rate, -rate)
00176
00177
00178 def UnboundFlux(self, reac):
00179
00180 self.SetColBounds(reac, 0, None)
00181
00182 rback = self._BackReac(reac)
00183 if rback != None:
00184 self.SetColBounds(rback, 0, None)
00185
00186
00187 def FiniteBoundFlux(self, reac, lo, hi):
00188
00189 if hi < lo:
00190 lo,hi = hi,lo
00191
00192 rback = self._BackReac(reac)
00193 if rback == None:
00194 if lo < 0:
00195 raise exceptions.ValueError, "attempt to set -ve bound on irreversible "+reac
00196 self.SetColBounds(reac, lo,hi)
00197 else:
00198 if hi < 0:
00199 self.SetColBounds(reac,0,0)
00200 self.SetColBounds(rback, -hi, -lo)
00201 elif lo < 0:
00202 self.SetColBounds(reac,0,hi)
00203 self.SetColBounds(rback, 0, -lo)
00204 else:
00205 self.SetColBounds(reac,lo,hi)
00206 self.SetColBounds(rback, 0, 0)
00207
00208
00209
00210
00211 def SetFluxBounds(self, reacs):
00212 """ Pre: reacs = {name:(lo,hi)...}, (lo<=hi OR hi==None) """
00213
00214 for reac in reacs:
00215
00216 lo, hi = reacs[reac]
00217
00218 if lo == hi == None:
00219 self.UnboundFlux(reac)
00220
00221 elif lo == hi:
00222 self.SetFixedFlux({reac:lo})
00223
00224 elif not None in (lo,hi):
00225 self.FiniteBoundFlux(reac, lo, hi)
00226
00227 else:
00228 rback = self._BackReac(reac)
00229
00230 if rback == None:
00231 self.SetColBounds(reac, lo, hi)
00232 else:
00233 if lo == None:
00234 if hi < 0.0:
00235 self.SetColBounds(reac, 0,0)
00236 self.SetColBounds(rback, -hi, None)
00237 else:
00238 self.SetColBounds(reac, 0, hi)
00239 self.SetColBounds(rback, 0, None)
00240 else:
00241 if lo < 0.0:
00242 self.SetColBounds(reac, 0,None)
00243 self.SetColBounds(rback, 0, -lo)
00244 else:
00245 self.SetColBounds(reac, lo,None)
00246 self.SetColBounds(rback, 0, 0)
00247
00248 def SetSumFluxConstraint(self, reacs, total, name):
00249
00250 self.AddRows([name])
00251 nc =self.GetDims()[1]
00252 vals = [0.0] * nc
00253 reacs = reacs[:]
00254 for r in reacs[:]:
00255 rback = self._BackReac(r)
00256 if rback != None:
00257 reacs.append(rback)
00258 idxs = glpk.SubOne(self.GetColIdxs(reacs))
00259 print idxs
00260 for idx in idxs:
00261 vals[idx] = 1.0
00262 self.SetRowVals(name,vals)
00263 self.SetRowBounds(name, total, total)
00264
00265 print "SetSumFluxCostraint testing !"
00266
00267
00268
00269
00270
00271 def Solve(self,PrintStatus=True):
00272 glpk.lp.Solve(self)
00273 if PrintStatus:
00274 print self.GetStatusMsg()
00275
00276
00277 def GetPrimSol(self, IncZeroes=False,FixBack=True,AsMtx=False):
00278
00279 sol = {}
00280
00281 if self.GetStatusMsg()=="Optimal":
00282 for r in range(len(self.sm.cnames)):
00283 name = self.sm.cnames[r]
00284 val = self._glp_lpx_get_col_prim(r+1)
00285 if IncZeroes or not glpk.IsZero(val):
00286 sol[name] = self._glp_lpx_get_col_prim(r+1)
00287
00288 for rev in Set.Intersect(self.sm.Reversed, sol.keys()):
00289 sol[rev] *= -1
00290
00291 if FixBack:
00292 for reac in sol.keys():
00293 if reac.endswith("_back"):
00294 val = sol[reac]
00295 if not glpk.IsZero(val):
00296 r2 = reac[:-5]
00297 if not sol.has_key(r2):
00298 sol[r2] = 0.0
00299 sol[r2] -= val
00300 del sol[reac]
00301
00302 if AsMtx:
00303 rv = StoMat.StoMat(cnames=["lp_sol"],rnames=sol.keys(),Conv=float)
00304 for r in sol:
00305 rv[r][0] = sol[r]
00306 else:
00307 rv = sol
00308
00309 return rv
00310
00311
00312 def GetSimplexAsMtx(self):
00313
00314 rnames = self.GetRowNames()
00315 cnames = self.GetColNames()
00316 rows = self.GetRowsAsLists()
00317
00318 rv = DynMatrix.matrix(rnames=rnames, cnames=cnames, Conv=float)
00319 rv.rows =rows
00320
00321 return rv
00322
00323
00324
00325
00326
00327
00328
00329
00330 def MatchFlux(self,fluxes, IncZeroes=False, AsMtx=False, SupressWarnings=True):
00331
00332 if SupressWarnings:
00333 sys.stderr = NullF
00334
00335 self.SetFixedFlux(fluxes)
00336 self.SetObjective(self.sm.cnames)
00337 self.Solve()
00338
00339 if SupressWarnings:
00340 sys.stderr = SysStderr
00341
00342 return self.GetPrimSol(IncZeroes=IncZeroes, AsMtx=AsMtx)
00343
00344
00345
00346
00347 def FixedFluxScan(self, reaction, lo, hi, n_p):
00348
00349 rv = DataSets.DataSet(ItemNames=[reaction,"ObjVal"])
00350 lo = float(lo)
00351 hi = float(hi)
00352
00353 inc = (hi - lo)/(n_p-1)
00354 cur = lo
00355
00356 for n in range(n_p):
00357 self.SetFixedFlux({reaction:cur})
00358 self.Solve(False)
00359
00360 sol = self.GetPrimSol()
00361
00362 if len(sol)==0:
00363 obval = float("NaN")
00364 else:
00365 obval = self.GetObjVal()
00366
00367 sol["ObjVal"] = obval
00368 sol[reaction] = cur
00369 rv.UpdateFromDic(sol)
00370
00371 cur += inc
00372
00373 return rv
00374
00375
00376
00377
00378
00379