00001
00002
00003 """
00004
00005 ScrumPy -- Metabolic Modelling with Python
00006
00007 Copyright Mark Poolman 1995 - 2002
00008
00009 This file is part of ScrumPy.
00010
00011 ScrumPy is free software; you can redistribute it and/or modify
00012 it under the terms of the GNU General Public License as published by
00013 the Free Software Foundation; either version 2 of the License, or
00014 (at your option) any later version.
00015
00016 ScrumPy is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00019 GNU General Public License for more details.
00020
00021 You should have received a copy of the GNU General Public License
00022 along with ScrumPy; if not, write to the Free Software
00023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00024
00025 """
00026
00027 import sys, types
00028
00029 from Util import DynMatrix, Seq,Set,Sci,Format, Types
00030
00031
00032 from Parser.lexer import t_Rever, t_Irrev, t_BackIrrev
00033 from Parser.Parser import Sto
00034
00035
00036
00037 NoSuchMet = "No such metabolite"
00038 NoSuchreac = "No such reaction"
00039 DupReac = "Duplicate reaction"
00040
00041 class StoMat(DynMatrix.matrix):
00042
00043 def __init__(self, r=0, c=0, **kwargs):
00044
00045 DynMatrix.matrix.__init__(self,r,c, **kwargs)
00046 self.RevProps = {}
00047 self.Externs = []
00048
00049
00050
00051
00052
00053
00054 def DelRow(self, r):
00055
00056 if type(r) == types.IntType:
00057 r = self.rnames[r]
00058
00059 if r in self.Externs:
00060 self.Externs.remove(r)
00061
00062 DynMatrix.matrix.DelRow(self,r)
00063
00064
00065 def DelReac(self, c):
00066
00067 if type(c) == types.IntType:
00068 c = self.cnames[c]
00069
00070 del self.RevProps[c]
00071 DynMatrix.matrix.DelCol(self,c)
00072
00073
00074 def DeQuote(self):
00075
00076 DynMatrix.matrix.DeQuote(self)
00077
00078 revpropdq = {}
00079 for k in self.RevProps:
00080 revpropdq[self.QuoteD[k]] = self.RevProps[k]
00081 self.RevProps = revpropdq
00082
00083 xnamesd = map(Format.StripQuote,self.Externs)
00084 for n in range(len(xnamesd)):
00085 self.QuoteD[xnamesd[n]] = self.Externs[n]
00086 self.QuoteD[self.Externs[n]] = xnamesd[n]
00087 self.Externs = xnamesd
00088
00089
00090 def ReQuote(self):
00091
00092 revpropdq = {}
00093 for k in self.RevProps:
00094 revpropdq[self.QuoteD[k]] = self.RevProps[k]
00095 self.RevProps = revpropdq
00096 self.Externs = map(lambda x:self.QuoteD[x], self.Externs)
00097 DynMatrix.matrix.ReQuote(self)
00098
00099
00100
00101 def MakeExtern(self, name):
00102
00103 self.DelRow(name)
00104 self.Externs.append(name)
00105
00106 def GetIrrevs(self):
00107 return filter(lambda reac: self.RevProps[reac] != t_Rever, self.cnames)
00108
00109 def MakeIrrev(self,name):
00110
00111 self.RevProps[name] = t_Irrev
00112
00113
00114 def MakeRevers(self,name):
00115
00116 self.RevProps[name] = t_Rever
00117
00118
00119 def InvolvedWith(self, name, crit=None):
00120 if crit==None:
00121 def crit(x):
00122 return x!=0
00123
00124
00125 if name in self.cnames:
00126 list = self.GetCol(name)
00127 namelist = self.rnames
00128 elif name in self.rnames:
00129 list = self.GetRow(name)
00130 namelist = self.cnames
00131 else:
00132 print "name ", name, "not found"
00133 list = []
00134
00135 rv = {}
00136 for idx in range(len(list)):
00137
00138 if crit( list[idx]):
00139 rv[namelist[idx]] = self.Conv(list[idx])
00140
00141 return (rv)
00142
00143
00144 def Products(self, Reaction):
00145 return self.InvolvedWith(Reaction, lambda x: x>0).keys()
00146
00147 def Substrates(self, Reaction):
00148 return self.InvolvedWith(Reaction, lambda x: x<0).keys()
00149
00150 def Reactants(self, Reaction):
00151 """ List of reactant names involved with Reaction """
00152 return self.InvolvedWith(Reaction).keys()
00153
00154 def Transporters(self):
00155 rv = {}
00156 for met in self.Externs:
00157 rv.update(self.InvolvedWith(met))
00158 return rv.keys()
00159
00160
00161 def OrphanMets(self):
00162
00163 rv = []
00164
00165 for met in self.rnames:
00166 if len(self.InvolvedWith(met))==1:
00167 rv.append(met)
00168
00169 return rv
00170
00171
00172 def Delete(self, name):
00173 if name in self.cnames:
00174 self.DelReac(name)
00175 for name in self.rnames:
00176 if Seq.AllEq(self.GetRow(name), 0):
00177 self.DelRow(name)
00178 elif name in self.rnames:
00179 self.DelRow(name)
00180 for name in self.cnames:
00181 if Seq.AllEq(self.GetCol(name), 0):
00182 self.DelReac(name)
00183 else:
00184 print "can't find ", name
00185
00186
00187 def NewReaction(self, reac, StoDic,RevProp=t_Rever):
00188
00189 if reac in self.cnames:
00190 raise DupReac
00191
00192 self.NewCol(name=reac)
00193 for met in StoDic.keys():
00194 if not met in self.rnames:
00195 self.NewRow(name=met)
00196 self[met,reac]=StoDic[met]
00197
00198 self.RevProps[reac] = RevProp
00199
00200
00201 def SetSto(self, reac, Sto, reset = False):
00202 """ pre: reac in self.cnames, Sto = Parser.Sto(...)"""
00203
00204 if reset:
00205 self.MulCol(reac, k=0)
00206
00207 for met in Sto.lhs:
00208 coeff = met[0]
00209 name = met[1]
00210 self[name,reac] = coeff
00211 self[name,reac] *= -1
00212
00213 for met in Sto.rhs:
00214 coeff = met[0]
00215 name = met[1]
00216 self[name,reac] = coeff
00217
00218 self.RevProps[reac] = Sto.Revers
00219
00220
00221
00222 def FirstReaction(self, Name, lhs, rhs, Revers):
00223
00224 print "Deprecated FirstReaction() ?"
00225 self.cnames.append(Name)
00226 for tup in lhs:
00227 if tup[0] in self.rnames:
00228 raise "Duplicate Metabolite"
00229 self.rnames.append(tup[0])
00230 self.rows.append([self.Conv(-tup[1])])
00231
00232 for tup in rhs:
00233 if tup[0] in self.rnames:
00234 raise "DuplicateMetabolite"
00235 self.rnames.append(tup[0])
00236 self.rows.append([self.Conv(tup[1])])
00237
00238 if not Revers:
00239 self.MakeIrrev(Name)
00240
00241
00242 def AddReaction(self, Name, lhs, rhs, Revers=1):
00243
00244 sys.stderr.write("Deprecated: AddReaction - Use NewReaction\n")
00245 raise "Deprecated method", "AddReaction"
00246
00247
00248 def Copy(self, *args,**kwargs):
00249
00250 rv = DynMatrix.matrix.Copy(self,*args, **kwargs)
00251 rv.RevProps = dict(self.RevProps)
00252
00253 rv.Externs = self.Externs[:]
00254
00255 return rv
00256
00257
00258 def ReacToStr(self,reac):
00259
00260 def d2l(d):
00261 rv = []
00262 for k in d.keys():
00263 rv.append(" ".join((str(d[k]),k)))
00264 return rv
00265
00266 substs = self.InvolvedWith(reac, lambda x: x<0)
00267 for k in substs.keys():
00268 substs[k] *= -1
00269 substs = d2l(substs)
00270
00271
00272 prods = d2l(self.InvolvedWith(reac, lambda x: x>0))
00273
00274 sep = self.RevProps[reac].join((" "," "))
00275
00276
00277 rv = reac+":\n\t" + " + ".join(substs) + sep + " + ".join(prods) + "\n\t~\n"
00278
00279 if len(substs) ==0 or len(prods)==0:
00280 print reac, "missing substrate or product !"
00281 rv = "#"+ "\n#".join(rv.split("\n"))+"\n"
00282
00283 return rv
00284
00285 def IntegiseReacs(self):
00286 for reac in self.cnames:
00287 col = self.GetCol(reac)
00288 if Seq.AllEq(col, 0):
00289 self.DelCol(reac)
00290 else:
00291
00292 self.SetCol(reac, Seq.Integise(col))
00293
00294
00295 def NiceOrder(self):
00296
00297 txs = self.Transporters()
00298 interns = Set.Complement(self.cnames,txs)
00299 txs.sort()
00300 interns.sort()
00301 self.ColReorder(txs+interns)
00302
00303
00304 def ElTypeAsScrumPy(self):
00305
00306 return Types.TypeToDirective[type(self.Conv(1))]
00307
00308
00309
00310
00311 def ToScrumPy(self, file=None, FirstLine="Structural()\n",Externs=None, NiceOrder=False):
00312
00313 if self.IsDeQuoted():
00314 FirstLine += "DeQuote()\n"
00315 self.ReQuote()
00316 rv = self.ToScrumPy(file, FirstLine,Externs, NiceOrder)
00317 self.DeQuote()
00318 return rv
00319
00320 if Externs==None:
00321 Externs=self.Externs[:]
00322
00323 for ex in Externs[:]:
00324 if ex.upper()[:2] == "X_":
00325 Externs.remove(ex)
00326
00327 self2 = self.Copy()
00328
00329 self2.ZapZeroes()
00330
00331 if self.Conv != Types.ArbRat:
00332 FirstLine += "ElType("+self.ElTypeAsScrumPy() + ")\n"
00333 if NiceOrder:
00334 self2.NiceOrder()
00335
00336 Header = FirstLine
00337 Body = "\n"
00338 if len(Externs) >0:
00339 Header += "External("+ ", ".join(Externs)+")\n\n"
00340 for reac in self.cnames:
00341 if len(self2.InvolvedWith(reac))==0:
00342 Header += "# Empty Reaction : "+ reac + "\n"
00343 else:
00344 Body += self2.ReacToStr(reac)
00345
00346 rv = Header + Body
00347 if file != None:
00348 if not hasattr(file,"write"):
00349 file = open(file,"w")
00350 file.write(rv)
00351 else:
00352 return rv
00353
00354
00355
00356
00357 def IsIrrev(self,name):
00358 return self.RevProps[name] != t_Rever
00359
00360 def Connectedness(self, met):
00361 return Seq.NumOfMatches(self[met], lambda x: x != 0)
00362
00363 def Unbals(self):
00364 " return list of mets that do not have >0 producer and >0 consumer "
00365
00366 rv = []
00367
00368 for m in self.rnames:
00369 row = self[m]
00370 if not (Seq.HasMatches(row, lambda x: x>0) and Seq.HasMatches(row, lambda x: x<0)):
00371 rv.append(m)
00372 return rv
00373
00374
00375 def SubSys(self, reacs):
00376
00377 if self.IsDeQuoted():
00378 self.ReQuote()
00379 reacsq = []
00380 for reac in reacs:
00381 reacq = '"'+reac+'"'
00382 if reacq in self.cnames:
00383 reacsq.append(reacq)
00384 else:
00385 reacsq.append(reac)
00386
00387 rv = self.SubSys(reacsq)
00388 rv.DeQuote()
00389 self.DeQuote()
00390
00391 else:
00392
00393 rv = StoMat(rnames=self.rnames, cnames=reacs,Conv=self.Conv)
00394
00395 for reac in reacs:
00396 stod = self.InvolvedWith(reac)
00397 for met in stod:
00398 rv[met,reac] = stod[met]
00399
00400 rv.ZapZeroes()
00401 rv.Externs = Set.Intersect(rv.rnames,self.Externs)
00402 for reac in rv.cnames:
00403 rv.RevProps[reac] = self.RevProps[reac]
00404
00405
00406
00407 if self.IsDeQuoted():
00408 for atr in "rnamesq", "cnamesq", "Externsq", "Irrevsq":
00409 setattr(rv, atr, map(self.FindQuoted, getattr(self, atr[:-1])))
00410
00411
00412 return rv
00413
00414
00415
00416
00417 def FindIsoforms(self):
00418 stodic = {}
00419 for reac in self.cnames:
00420 strsto = str(self.InvolvedWith(reac))
00421 if stodic.has_key(strsto):
00422 stodic[strsto].append(reac)
00423 else:
00424 stodic[strsto] = [reac]
00425 rv = []
00426 for reac in stodic.values():
00427 if len(reac)>1:
00428 rv.append(reac)
00429
00430 return rv
00431
00432
00433
00434
00435 def OrthSubSysts(self,tol=1e-6):
00436 """ a list of lists of reaction names of the orthogonal subsystems in self,
00437 The first, possibly empty, list contains the dead reactions """
00438
00439 k = self.OrthNullSpace()
00440 dead = []
00441 for reac in k.rnames[:]:
00442 if max(map(abs, k[reac])) <tol:
00443 dead.append(reac)
00444 k.DelRow(reac)
00445
00446 rv = [dead]
00447
00448 while len(k.rnames) >0:
00449 ref = k.rnames[0]
00450 curss = [ref]
00451
00452 for reac in k.rnames[1:]:
00453 if not Sci.AreOrthogonal(k[ref],k[reac],tol):
00454 curss.append(reac)
00455 k.DelRow(reac)
00456
00457 k.DelRow(ref)
00458 rv.append(curss)
00459 return rv
00460
00461
00462 def ReactionNJTree(self):
00463 k = self.OrthNullSpace()
00464 t = k.RowDiffMtx(Sci.Theta).ToNJTree()
00465 t.Consolidate(thresh= 1e-8)
00466 return t
00467
00468 def AdjMtx(self):
00469 """ The integer adjacency matrix of self """
00470
00471 rv = DynMatrix.matrix(Conv = int, rnames = self.rnames, cnames = self.cnames)
00472 for met in self.rnames:
00473 reacs = self.InvolvedWith(met).keys()
00474 for r in reacs:
00475 for neighbour in self.InvolvedWith(r).keys():
00476 rv[r,neighbour] = 1
00477 return rv
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493