• Main Page
  • Namespaces
  • Classes
  • Files
  • File List

/home/mark/model/software/ScrumPy/ScrumPy/Util/DynMatrix.py

00001 
00002 
00003 
00004 """
00005 
00006 ScrumPy -- Metabolic Modelling with Python
00007 
00008 Copyright Mark Poolman 1995 - 2002 Copy
00009 
00010  This file is part of ScrumPy.
00011 
00012     ScrumPy is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     ScrumPy is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with ScrumPy; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 
00026 """
00027 """
00028 M. Poolman 10/01/01
00029 Dynamic matrix class
00030 """
00031 
00032 
00033 
00034 
00035 import  types,math,sys,exceptions
00036 Pi = math.pi
00037 PiOver2 = Pi/2
00038 
00039 
00040 import  Sci,Seq,Sorter,Types,Format, LaTeX,  Tree
00041 
00042 try:
00043     from ScrumPy import wxGUI as GUI
00044     HaveGUI = True
00045 except:
00046     HaveGUI = False
00047 
00048 DefaultConv = Types.ArbRat
00049 DynMatrixError = "Dynamic Matrix Error"
00050 Tol = 1e-9 # tolerance for floating point error checks etc.
00051 
00052 def DepWarn(Str):
00053     sys.stderr.write( "!! Deprecated " + Str+" !!" )
00054 
00055 
00056 def GetIdent(n, Conv=DefaultConv, mul=1):
00057     rv = matrix(nrow=n,ncol=n,Conv=Conv)
00058     rv.MakeIdent(mul)
00059     return rv
00060 
00061 def FromVec(vec, Conv=None):
00062 
00063     if not Conv:
00064         vtype = type(vec[0]).__name__
00065         try:
00066             Conv = {
00067                 'float' : float,
00068                 'int' : int,
00069                 'long int' : long
00070                 }[vtype]
00071         except:
00072             Conv = DefaultConv
00073 
00074     size = len(vec)
00075     rv = matrix(size,size,Conv)
00076     for n in range(size):
00077         rv[n,n] = Conv(vec[n])
00078 
00079     return rv
00080 
00081 
00082 
00083 
00084 
00085 
00086 class matrix:
00087 
00088     def __init__(self, nrow=0, ncol=0,rnames=[],cnames=[], Conv=DefaultConv, FromMtx=None):
00089 
00090         self.Conv = Conv
00091         self.rnames = []
00092         self.cnames = []
00093         self.rows = []
00094 
00095 
00096         if FromMtx != None:
00097             try:
00098                 self.FromDynMatrix(FromMtx)
00099                 return
00100             except:
00101                 try:
00102                     self.FromNumPyMtx(FromMtx)
00103                 except:
00104                     self.FromList(FromMtx)
00105 
00106             if len(rnames) != 0 and len(rnames) != len(self):
00107                 raise exceptions.IndexError, "len(rnames) != len(FromMtx)"
00108             else:
00109                 self.rnames = rnames[:]
00110 
00111             if len(cnames) != 0 and len(cnames) != len(self.rows[0]):
00112                 raise exceptions.IndexError, "len(cnames) != len(FromMtx[0])"
00113             else:
00114                 self.cnames = cnames[:]
00115 
00116             return
00117 
00118         if len(rnames) != 0:
00119             self.rnames = rnames[:]
00120         else:
00121             for r in range(nrow):
00122                 self.rnames.append("row"+str(r))
00123 
00124         if len(cnames) != 0:
00125             self.cnames = cnames[:]
00126         else:
00127             for c in range(ncol):
00128                 self.cnames.append("col"+str(c))
00129 
00130         self.MakeZero()
00131 
00132 
00133 
00134     def _getrc(self,rc):
00135         if type(rc) == types.TupleType:
00136             r = rc[0]
00137             c = rc[1]
00138         else:
00139             r = rc
00140             c = None
00141 
00142         return r,c
00143 
00144 
00145     def __len__(self):
00146         return len(self.rows)
00147 
00148 
00149     def __getitem__(self,rc):
00150         r,c = self._getrc(rc)
00151 
00152         try:
00153             row =  self.rows[r]
00154         except:
00155             try:
00156                 row =  self.rows[self.rnames.index(r)]
00157             except:
00158                 raise IndexError, r
00159 
00160         if  c==None:
00161             return row
00162 
00163         try:
00164             return row[c]
00165         except:
00166             try:
00167                 return row[self.cnames.index(c)]
00168             except:
00169                 raise IndexError, c
00170 
00171 
00172     def __setitem__(self,rc, val):
00173 
00174         r,c = self._getrc(rc)
00175 
00176         if type(r) == types.StringType:
00177             try:
00178                 r = self.rnames.index(r)
00179             except:
00180                 raise IndexError, r
00181 
00182         if  c==None:
00183             self.rows[r] = map(self.Conv, val)
00184         else:
00185             if type(c) == types.StringType:
00186                 try:
00187                     c = self.cnames.index(c)
00188                 except:
00189                     raise IndexError, c
00190 
00191             self.rows[r][c] = self.Conv(val)
00192 
00193 
00194     def __getslice__(self,lo,hi):
00195         rv = matrix(Conv=self.Conv)
00196         rv.rows = self.rows[lo:hi]
00197         rv.rnames = self.rnames[lo:hi]
00198         rv.cnames = self.cnames[:]
00199         return rv
00200 
00201 
00202     def __str__(self):
00203         retstr = "    "
00204         for cname in self.cnames:
00205             retstr += str(cname) + " "
00206         retstr += "\n"
00207         for r in range(len(self.rnames)):
00208             retstr += "\n " + str(self.rnames[r])
00209             for el in self[r]:
00210                 retstr +=" "+str(el)+ " "
00211 
00212         return retstr
00213 
00214 
00215     def __repr__(self):
00216         try:
00217             return str(self)
00218         except:
00219             return "can't generate string rep'n for this matrix"
00220 
00221     def Show(self):
00222         if HaveGUI:
00223             GUI.Mtx.SimpleView(self).Show()
00224         else:
00225             print self
00226 
00227 
00228     def index(self,row):
00229 
00230         for i in range(len(self.rows)):
00231             if Seq.AreEqual(self.rows[i], row):
00232                 return i
00233 
00234         raise "ValueError", "matrix.index(row): row not in matrix"
00235 
00236 
00237 
00238     def DeQuote(self):
00239         """ replace double quoted strings in row and col names with unquoted
00240             (preserves mappings in self.QuoteD) """
00241 
00242         self.QuoteD = {}
00243         rnamesd = map(Format.StripQuote,self.rnames)
00244         cnamesd = map(Format.StripQuote,self.cnames)
00245 
00246         for n in range(len(rnamesd)):
00247             self.QuoteD[rnamesd[n]] = self.rnames[n]
00248             self.QuoteD[self.rnames[n]] = rnamesd[n]
00249 
00250         for n in range(len(cnamesd)):
00251             self.QuoteD[cnamesd[n]] = self.cnames[n]
00252             self.QuoteD[self.cnames[n]] = cnamesd[n]
00253 
00254         self.rnames = rnamesd
00255         self.cnames = cnamesd
00256 
00257 
00258 
00259     def IsDeQuoted(self):
00260         """ bool: self is DeQuote()ed """
00261 
00262         return hasattr(self, "QuoteD")
00263 
00264 
00265     def ReQuote(self):
00266         """ undo DeQuote """
00267 
00268         if  self.IsDeQuoted():
00269 
00270             for n in range(len(self.rnames)):
00271                 name = self.rnames[n]
00272                 if self.QuoteD.has_key(name):  # because might have added something sunce DeQuote
00273                     self.rnames[n] = self.QuoteD[name]
00274 
00275             for n in range(len(self.cnames)):
00276                 name = self.cnames[n]
00277                 if self.QuoteD.has_key(name):
00278                     self.cnames[n] = self.QuoteD[name]
00279 
00280             del self.QuoteD
00281 
00282     def ResetRowNames(self):
00283         """ pre: True
00284            post: self.rnames==["Row_0".."Row_n"] """
00285 
00286         self.rnames = map(lambda n: "Row_"+str(n),range(len(self)))
00287 
00288 
00289     def ChangeType(self, Conv):
00290         self.Conv = Conv
00291         for r in self.rnames:
00292             self[r] = self.MakeSeqSelfType(self[r])
00293 
00294     def MakeSeqSelfType(self, seq):
00295 
00296         return map(self.Conv, seq)
00297 
00298 
00299     def MakeZero(self):
00300         Conv = self.Conv
00301         self.rows = []
00302         for n in range(len(self.rnames)):
00303             self.rows.append(map(self.Conv, [0]*len(self.cnames)))
00304 
00305 
00306     def Clear(self):
00307         "erase all row and col data"
00308 
00309         self.cnames, self.rnames, self.rows = [],[],[]
00310 
00311 
00312 
00313     def Copy(self, Conv=None,tx=False):#,_Super=None):
00314         """ pre: True
00315            post: Copy of self, with Element type Conv (self.Conv if Conv==None)
00316                     tx => Copy is transposed """
00317 
00318         if Conv==None:
00319             Conv=self.Conv
00320 
00321 
00322         rv = self.__class__(Conv=Conv)
00323         rv.cnames = self.cnames[:]
00324         rv.rnames = self.rnames[:]
00325         if Conv==self.Conv:
00326             for row in self.rows:
00327                 rv.rows.append(row[:])
00328         else:
00329             for row in self.rows:
00330                 rv.rows.append(map(Conv, row))
00331 
00332         if tx:
00333             rv.Transpose()
00334 
00335         return rv
00336 
00337     def ReadFile(self, FileName):
00338         """ pre: (FileName != None) -> (File conforms to FileSpec)
00339            post: contents of self are those of FileName  """
00340 
00341         f = open(FileName, "r")
00342         self.Clear()
00343         Titles = f.readline()
00344         for t in Titles.split():
00345             self.NewCol(name=t)
00346 
00347         for row in f.readlines():
00348             row = row.split()
00349             try:
00350                 self.NewRow(row[1:], row[0])
00351             except:
00352                 print "problem with row", row, "ignoring it"
00353 
00354 
00355 
00356     def WriteFile(self,File,WithHash=False,WithRNames=True,Delim="\t"):
00357         """ pre: (ColOrder == None) || (complete and exclusive list of column headings of self)
00358            post: FileName contains FileSpec representation of self
00359                  (ColOrder != None) => Columns in ColOrder
00360                  ELSE Exception """
00361 
00362         if type(File) == types.StringType:
00363             f = open(File, "w")
00364         else:
00365             f = File
00366 
00367         first = {True:["#"],
00368                  False:[""]
00369                  }[WithHash]
00370 
00371         print >>f, Delim.join(first+self.cnames)
00372 
00373         if WithRNames:
00374             for n in range(len(self)):
00375                 print >>f, Delim.join([self.rnames[n]]+map(str,self.rows[n]))
00376         else:
00377             for n in len(self):
00378                 print >>f, Delim.join(map(str,self.rows[n]))
00379 
00380 
00381 
00382     def ToFile(self, fname):
00383         f = open(fname,"w")
00384         f.write(str(self))
00385 
00386     def ToList(self):
00387         """ return a list of lists of tuples. Each list corresponds to a  row,
00388              each tuple is (name,value) of the column and value of the non zero elements within that row """
00389 
00390         rv = []
00391         for row in self:
00392             curlist = []
00393             curidxs = Seq.IdxListOfMatches(row, lambda x: x!=0)
00394             for idx in curidxs:
00395                 curlist.append((self.cnames[idx], row[idx]))
00396             rv.append(curlist)
00397 
00398         return rv
00399 
00400 
00401 
00402     def ToDict(self):
00403         """ return dictionary in which keys are row names and values lists of tuples (colnames, elval) for elval != 0 """
00404 
00405         l = self.ToList()
00406         rv = {}
00407         for idx in range(len(self)):
00408             rv[self.rnames[idx]] = l[idx]
00409         return rv
00410 
00411 
00412     def UpTri(self):
00413         """ return upper triangular elements of self as a single list """
00414 
00415         rv = []
00416         for i in range(len(self)):
00417             rv.extend(self[i][i+1:])
00418         return rv
00419 
00420 
00421     def FromDicDic(self,d):
00422         """ pre: d is a dictionary of rows,
00423         in which each value is a dictionary mapping col names to values
00424             post: self'[r,c] == d[r,c] for non-zero values, all other values in self are zero """
00425 
00426         self.rnames = []
00427         self.rows = []
00428         self.cnames = []
00429 
00430         for kr in d.keys():              # kr - key of row
00431             self.NewRow(name=kr)
00432             rd = d[kr]                      # rd - row dictionary
00433             for kc in rd.keys():        # kc - key of col
00434                 if not kc in self.cnames:
00435                     self.NewCol(name=kc)
00436 
00437                 self[kr,kc] = d[kr][kc]
00438 
00439 
00440 
00441 
00442     def ToColList(self):
00443         """ as ToList, but returns list of columns """
00444 
00445         rv = []
00446         for cn in self.cnames:
00447             col = self.GetCol(cn)
00448             curidxs = Seq.IdxListOfMatches(col, lambda x: x!=0)
00449             curlist = []
00450             for idx in curidxs:
00451                 curlist.append((self.rnames[idx],col[idx]))
00452             rv.append(curlist)
00453         return rv
00454 
00455 
00456     def ToColDict(self):
00457         """ return dictionary in which keys are col names and values lists of tuples (rownames, elval) for elval != 0 """
00458 
00459         l = self.ToColList()
00460         rv = {}
00461         for idx in range(len(self.cnames)):
00462             rv[self.cnames[idx]] = l[idx]
00463         return rv
00464 
00465 
00466 
00467 
00468 
00469     def ToSciMtx(self,Conv=None):
00470 
00471         sys.stderr.write("ToSciMtx: why do we need this ?\n")
00472 
00473         if not Conv:
00474             return Sci.matrix(self.rows)
00475 
00476         return Sci.matrix(self.Copy(Conv).rows)
00477 
00478 
00479     def FromNumPyMtx(self, mtx, Conv=None):
00480         sys.stderr.write("FromNumPyMtx: use from SciMtx ?\n")
00481         return self.FromSciMtx(mtx,  Conv)
00482 
00483     def FromSciMtx(self, mtx, Conv=None):
00484 
00485         sys.stderr.write("FromSciMtx: why do we need this ?\n")
00486 
00487         nrow,ncol = mtx.shape
00488         if Conv!=None:
00489             self.Conv = Conv
00490         self.cnames = map(lambda x: "col"+str(x),range(ncol))
00491         self.rnames = map(lambda x: "row"+str(x),range(nrow))
00492 
00493         self.rows = mtx.tolist() # ! no - do this in the Sci module.
00494 
00495 
00496 
00497 
00498 
00499 
00500     def ToOctaveMtx(self, name, Conv = float):
00501         """ pre: True
00502            post: returns a string that when printed assigns the octave matrix, name, to current contents
00503                     using Conv as a type converter
00504         """
00505         rv = name + "= ["
00506         for row in self.rows:
00507             rv += "\n  ["
00508             for el in  row[:-1]:
00509                 rv += str(Conv(el)) + ", "
00510             rv += str(Conv(row[-1])) + "]"
00511         rv += "\n]\n"
00512 
00513         return rv
00514 
00515 
00516     def ToCMtx(self, name, Conv = float):
00517         """ pre: True
00518            post: returns a string that when printed declares a C matrix, name, of current contents
00519                     type will need editing for non-default Conv, which as ever, is the type converter
00520         """
00521 
00522         c_nrows = name + "_nRows"
00523         c_ncols = name + "_nCols"
00524         strlenrow  = str(len(self.rows))
00525         strlencol = str(len(self.rows[0]))
00526         rv = "  const int "
00527 
00528         rv += c_nrows + " = " + strlenrow + ", " +   c_ncols + " = " + strlencol + ";"
00529 
00530         rv += "\n  double " +  name + "[" + c_nrows + "]" + "[" + c_ncols + "] = {\n"
00531         for row in self.rows[:-1]:
00532             rv += "\t{"
00533             for el in row[:-1]:
00534                 rv += str(Conv(el)) + ", "
00535             rv += str(Conv(row[-1])) + "},\n"
00536 
00537         row = self.rows[-1]
00538         rv += "\t{"
00539         for el in row[:-1]:
00540             rv += str(Conv(el)) + ", "
00541         rv += str(Conv(row[-1])) + "} \n  } ;"
00542 
00543         return rv
00544 
00545 
00546     def ToStr(self):
00547         """ return  an easy-to-interpret string repn of self, reflecting information content
00548              rather than matrix notation -NOT- the same as __str__ or __repr__"""
00549 
00550         rv = ""
00551         list = self.ToList()
00552         for row in list:
00553             rowstr = "    "
00554             for el in row:
00555                 elstr = str(el[1]) + " " + el[0]
00556                 if el[1] < 0:
00557                     rowstr = elstr + "  " + rowstr
00558                 else:
00559                     rowstr += "  " + elstr
00560             rv += rowstr + "\n"
00561         return rv
00562 
00563 
00564     def ToTexTab(self, RowLabels=True):
00565         "return a string representation in Latex tabular form"
00566 
00567         if RowLabels:
00568             colheads = ["Row"] + self.cnames
00569         else:
00570             colheads = self.cnames[:]
00571 
00572         ncols = len(colheads)
00573         rv = LaTeX.Tabular(ncols)
00574         rv.AddRow(colheads)
00575 
00576         if self.Conv == float:
00577             TeXConv = Float2Tex
00578         else:
00579             TeXConv = str
00580 
00581         if RowLabels:
00582             for r in self.rnames:
00583                 rv.AddRow([r]+map(TeXConv,self[r]))
00584         else:
00585             for r in self.rows:
00586                 rv.AddRow(map(TeXConv,r))
00587 
00588         return str(rv)
00589 
00590 
00591 
00592     def FromDynMatrix(self,other):
00593 
00594         self.Conv = other.Conv
00595         self.cnames = other.cnames[:]
00596         self.rnames = other.rnames[:]
00597         self.rows = []
00598         for r in other.rows:
00599             self.rows.append(r[:])
00600 
00601 
00602 
00603 
00604     def InitRows(self, rnames):
00605         """ pre: rnames is a list of strings
00606            post: self is an empty (r x 0) matrix, using rnames as row names """
00607         self.rnames = rnames[:]
00608         self.rows = []
00609 
00610 
00611 
00612     def Transpose(self):
00613         NewRows = []
00614         for c in range(len(self.cnames)):
00615            NewRows.append(self.GetCol(c))
00616         self.rows = NewRows
00617 
00618         tmp = self.cnames
00619         self.cnames = self.rnames
00620         self.rnames = tmp
00621 
00622 
00623     def RowReorder(self, NewOrder):
00624         tmp = matrix(Conv=self.Conv,ncol = len(self.cnames))
00625 
00626         for n in NewOrder:
00627             if type(n)==int:
00628                 name = self.rnames[n]
00629             else:
00630                 name = n
00631             tmp.NewRow(self[n], name)
00632 
00633         self.rows = tmp.rows
00634         self.rnames = tmp.rnames
00635 
00636 
00637     def ColReorder(self, NewOrder):
00638         self.Transpose()
00639         self.RowReorder(NewOrder)
00640         self.Transpose()
00641 
00642     def RandRowOrder(self):
00643         self.RowReorder(Seq.RandOrder(self.rnames))
00644 
00645     def RandColOrder(self):
00646         self.ColReorder(Seq.RandOrder(self.cnames))
00647 
00648     def RandOrder(self):
00649         self.RandRowOrder()
00650         self.RandColOrder()
00651 
00652 
00653     def SortBy(self,cname,Descend=False):
00654 
00655         origc = self.GetCol(cname)
00656         sortc = sorted(origc,reverse=Descend)
00657         mark = min(origc)-1  # ie a number known not to be in the list
00658 
00659         neworder=[]
00660         for x in sortc:
00661             idx = origc.index(x)
00662             neworder.append(idx)
00663             origc[idx] = mark
00664 
00665         self.RowReorder(neworder)
00666 
00667 
00668 
00669 
00670     def RowNamesFromIdxs(self,idxs=[]):
00671         rv = []
00672         for i in idxs:
00673             rv.append(self.rnames[i])
00674         return rv
00675 
00676 
00677     def ColNamesFromIdxs(self,idxs=[]):
00678         rv = []
00679         for i in idxs:
00680             rv.append(self.cnames[i])
00681         return rv
00682 
00683 
00684     def RowNZIdxs(self,r,Abs=True):
00685         "list of indices to nonzero elements of r, sorted by ascending (Abs => absolute) element value "
00686 
00687         return Seq.NZIdxs(self[r],Abs)
00688 
00689 
00690     def ColNZIdxs(self,c,Abs=True):
00691         "list of indices to nonzero elements of c, sorted by ascending (Abs => absolute) element value "
00692 
00693         return Seq.NZIdxs(self.GetCol(c),Abs)
00694 
00695 
00696 
00697     def Sort(self, fun, **fundat):
00698         """ sort rows in ascending order of fun(row,mtx,fundat) where:
00699             fun returns a numeric type
00700             row is an index into mtx
00701             mtx is self
00702             fundat is optional named args"""
00703 
00704         s = Sorter.Sorter()
00705         for r in self.rnames:
00706             s.append(r)
00707         self.RowReorder(s.Sort(fun, mtx=self, **fundat))
00708 
00709 
00710 
00711 
00712     def MakeIdent(self, mul):
00713 
00714         r = 0
00715         for row in self.rows:
00716             row = map(lambda x: 0, row)
00717             row[r] = mul
00718             self.rows[r] = self.MakeSeqSelfType(row)
00719             r = r + 1
00720 
00721     def SetEl(self, row, col, val):
00722 
00723         DepWarn("DynMatrix.matrix.SetEl()")
00724 
00725         if type(row) != types.IntType:
00726             row = self.rnames.index(row)
00727         if type(col) != types.IntType:
00728             col = self.cnames.index(col)
00729 
00730         self.rows[row][col] = self.Conv(val)
00731 
00732 
00733     def NewEl(self, rname, cname, val):
00734         """ pre: true
00735            post: self[rname,cname] == val
00736                  (rows and cols created if needed)
00737         """
00738 
00739         if not rname in self.rnames:
00740             self.NewRow(name=rname)
00741         if not cname in self.cnames:
00742             self.NewCol(name=cname)
00743         self[rname,cname] = self.Conv(val)
00744 
00745 
00746 
00747     def NewCol(self,  col=None, name=None):
00748 
00749         if name == None:
00750             name = "col" + str(len(self.cnames)+1)
00751 
00752         self.cnames.append(name)
00753 
00754         if col == None:
00755             col = [0] *len(self.rnames)
00756 
00757         if len(self.rnames)==0:
00758             for i in range(len(col)):
00759                 self.rows.append([self.Conv(col[i])])
00760                 self.rnames.append("row_" + str(i))
00761 
00762         elif len(col) != len(self.rnames):
00763             raise exceptions.IndexError, "wrong length for new col"
00764 
00765         else:
00766             for i in range(len(self.rows)):
00767                 self[i].append(self.Conv(col[i]))
00768 
00769 
00770 
00771 
00772     def DelCol(self, c=0):
00773 
00774         if type(c) == types.StringType:
00775             c = self.cnames.index(c)
00776 
00777         del self.cnames[c]
00778         for row in self.rows:
00779             del row[c]
00780 
00781 
00782     def GetCol(self, c):
00783         if type(c) == types.StringType:
00784             c = self.cnames.index(c)
00785         col = []
00786         for row in self.rows:
00787             col.append(row[c])
00788 
00789         return col
00790 
00791 
00792     def SetCol(self, c, vals):
00793         if type(c) == types.StringType:
00794             c = self.cnames.index(c)
00795         vals = self.MakeSeqSelfType(vals)
00796         r = 0
00797         for row in self.rows:
00798             row[c] = vals[r]
00799             r = r + 1
00800 
00801 
00802     def AddCol(self, c, vals=None, k = None):
00803         #DepWarn("AddCol")
00804         if vals !=None:
00805             self.SetCol(c, map(lambda x,y: x+y, self.GetCol(c), vals))
00806         else:
00807             self.SetCol(c, map(lambda x: x+k, self.GetCol(c)))
00808 
00809     def SubCol(self, c, vals=None, k=None):
00810         #DepWarn("SubCol")
00811         if vals != None:
00812             self.SetCol(c, map(lambda x,y: x-y, self.GetCol(c), vals))
00813         else:
00814             self.SetCol(c, map(lambda x: x-k, self.GetCol(c)))
00815 
00816     def MulCol(self, c, vals=None, k=None):
00817         #DepWarn("MulCol")
00818         if vals!=None:
00819             self.SetCol(c, map(lambda x,y: x*y, self.GetCol(c), vals))
00820         else:
00821             self.SetCol(c, map(lambda x: x*k, self.GetCol(c)))
00822 
00823     def DivCol(self, c, vals=None, k=None):
00824         #DepWarn("DivCol")
00825         if vals!=None:
00826             self.SetCol(c, map(lambda x,y: x/y, self.GetCol(c), vals))
00827         else:
00828             self.SetCol(c, map(lambda x: x/k, self.GetCol(c)))
00829 
00830 
00831     def FunCol(self, c, Fun):
00832         self.SetCol(c, map(Fun, self.GetCol(c)))
00833 
00834     def MaxInCol(self, c):
00835         return max(self.GetCol(c))
00836 
00837     def MinInCol(self, c):
00838         return min(self.GetCol(c))
00839 
00840     def PosOfValsInCol(self, c, val):
00841         return Seq.PosOfValsInSeq(self.GetCol(c), val)
00842 
00843     def NZeroesInCol(self,c):
00844         return len(self.PosOfValsInCol(c,0))
00845 
00846 
00847     def NonZeroesInCols(self):
00848         """ returns a list vector, one element per col,
00849         each element being the number of non-zero elements in the coresponding col """
00850 
00851         rv = []
00852         for c in range(len(self.cnames)):
00853             rv.append(self.NZeroesInCol(c))
00854 
00855         return rv
00856 
00857     def NamesNonZeroesInCols(self):
00858         """ return a list (one el per col) lists of row names that have no zero element in corresponding col """
00859 
00860         rows = self.rows
00861         rnames = self.rnames
00862         rv = []
00863 
00864         for c in range(len(self.cnames)):
00865             res = []
00866             for r in range(len(self)):
00867                 if rows[r][c] != 0:
00868                     res.append(rnames[r])
00869             rv.append(res)
00870         return rv
00871 
00872 
00873     def MaxInRange(self,names):
00874         """ pre: self.rnames == self.cnames, Set.IsSubset(names, self.rnames)
00875            post: greatest value of self[names[x],names[y]] """
00876 
00877         rv = 0.0
00878         for n1 in names:
00879             for n2 in names[names.index(n1):]:
00880                 if self[n1,n2] > rv:
00881                     rv = self[n1,n2]
00882 
00883         return rv
00884 
00885 
00886 
00887 
00888     def SwapCol(self, c1, c2):
00889 
00890         if type(c1).__name__ == 'string':
00891             c1 = self.cnames.index(c1)
00892 
00893         if type(c2).__name__ == 'string':
00894             c2 = self.cnames.index(c2)
00895 
00896         tmp = self.GetCol(c1)
00897         self.SetCol(c1, self.GetCol(c2))
00898         self.SetCol(c2, tmp)
00899 
00900         tmp = self.cnames[c1]
00901         self.cnames[c1] = self.cnames[c2]
00902         self.cnames[c2] = tmp
00903 
00904 
00905     def AugCol(self, m):
00906         for c in range(len(m.cnames)):
00907             self.NewCol(m.GetCol(c),m.cnames[c])
00908 
00909     def MakeLastCol(self, c):
00910         if type(c) == types.StringType:
00911             cname = c
00912             c = self.cnames.index(c)
00913         else:
00914             cname = self.cnames[c]
00915 
00916         col = self.GetCol(c)
00917         self.DelCol(c)
00918         self.NewCol(col, cname)
00919 
00920 
00921     def MakeFirstCol(self, c):
00922         if type(c) == types.StringType:
00923             cname = c
00924             c = self.cnames.index(c)
00925         else:
00926             cname = self.cnames[c]
00927 
00928         col = self.GetCol(c)
00929         self.DelCol(c)
00930         self.cnames.insert(0,cname)
00931         for idx in range(len(col)):
00932             self.rows[idx].insert(0,col[idx])
00933 
00934 
00935 
00936 
00937 
00938     def NewRow(self,  r=None, name=None):
00939 
00940         if name == None:
00941             name = "row" + str(len(self.rows)+1)
00942 
00943         self.rnames.append(name)
00944 
00945         if r == None:
00946             r = [0] *len(self.cnames)
00947         elif len(r) != len(self.cnames):
00948             raise exceptions.IndexError, "wrong length for new row"
00949 
00950         self.rows.append(self.MakeSeqSelfType(r))
00951 
00952 
00953     def DelRow(self, r):
00954         if type(r) == types.StringType:
00955             r = self.rnames.index(r)
00956 
00957         del self.rows[r]
00958         del self.rnames[r]
00959 
00960 
00961     def GetRow(self, r):
00962         if type(r) == types.StringType:
00963             r = self.rnames.index(r)
00964         return(self.rows[r][:])
00965 
00966 
00967     def SetRow(self, r, vals):
00968         if type(r) == types.StringType:
00969             r = self.rnames.index(r)
00970         self.rows[r] = self.MakeSeqSelfType(vals)
00971 
00972 
00973     def AddRow(self, r, vals=None, k=None):
00974         if vals and k:
00975             self[r] = map(lambda x,y: x+y, self[r], map(lambda x,mul=k: x*mul,vals))
00976         elif vals:
00977             self[r] = map(lambda x,y: x+y, self[r], vals)
00978         else:
00979             self[r] = map(lambda x,add=k: x+add,vals)
00980 
00981 
00982     def InsertRow(self, pos, Val=0, Name=None):
00983 
00984         r = map(lambda x,v=Val: v, range(0,len(self.cnames)))
00985         self.rows.insert(pos, self.MakeSeqSelfType(r))
00986         if Name:
00987             self.rnames.insert(pos,Name)
00988 
00989 
00990     def SubRow(self, r, vals):
00991         DepWarn("SubRow")
00992         self.rows[r] = map(lambda x,y: x-y, self.rows[r], vals)
00993 
00994 
00995     def MulRow(self, r, vals=None, k=None):
00996         if vals and k:
00997             self[r] = map(lambda x,y: x*y, self[r], map(lambda x,mul=k: x*mul,vals))
00998         elif vals:
00999             self[r] = map(lambda x,y: x*y, self[r], vals)
01000         else:
01001             self[r] = map(lambda x,mul=k: x*mul,self[r])
01002 
01003 
01004     def DivRow(self, r, vals=None, k=None):
01005         if type(r) != types.IntType:
01006             r = self.rnames.index(r)
01007         if vals and k:
01008             self.rows[r] = map(lambda x,y: x/y, self.rows[r], map(lambda x,mul=k: x*mul,vals))
01009         elif vals:
01010             self.rows[r] = map(lambda x,y: x/y, self.rows[r], vals)
01011         else:
01012             self.rows[r] = map(lambda x,den=k: x/den,self.rows[r])
01013 
01014 
01015     def AddAndRemoveRows(self, rows):
01016         """ pre: rows is subset of self.rnames
01017            post: self'[rows[0]] """
01018 
01019         r0 = rows[0]
01020         for r in rows[1:]:
01021             self.AddRow(r0,self[r])
01022         for r in rows[1:]:
01023             self.DelRow(r)
01024 
01025     def FunRow(self, r, fun):
01026         self.rows[r] = map(fun, self.rows[r])
01027 
01028     def MaxInRow(self, r):
01029         return max(self[r])
01030 
01031     def MinInRow(self, c):
01032         return min(self[r])
01033 
01034     def PosOfValsInRow(self, r, val):
01035         return Seq.PosOfValsInSeq(self.rows[r], val)
01036 
01037 
01038 
01039     def FunAllRows(self, fun):
01040         for r in range(len(self.rows)):
01041             self.rows[r] = fun(self.rows[r])
01042 
01043     def DupRows(self):
01044         """ pre: True
01045            post: self.DupRows()  a (possibly empty) list of lists of names of rows with identical elements
01046         """
01047 
01048         rv = []
01049         rows = self.rows
01050         rnames = self.rnames
01051         ridxs = range(len(self.rows))
01052         while len(ridxs)>0:
01053             r = ridxs[0]
01054             duplist = [r]
01055             for r2 in ridxs[1:]:
01056                 if Seq.AreEqual(rows[r], rows[r2]):
01057                     duplist.append(r2)
01058 
01059             for d in duplist:
01060                 del ridxs[ridxs.index(d)]
01061             if len(duplist)> 1:
01062                 rv.append(map(lambda x,rn = self.rnames: rn[x],duplist))
01063 
01064         return rv
01065 
01066 
01067 
01068     def DelDupRows(self):
01069         """pre: True
01070           post: len(self.DupRows())==0
01071         """
01072 
01073         for dups in self.DupRows():
01074             for d in dups[1:]:  # leave the first one !!
01075                 self.DelRow(d)
01076 
01077 
01078     def MaxCountRow(self, val):
01079         """ return the row name with the greatest number of elements of value val
01080             in the event of a tie the first matching row name is returned
01081             if no rows contain val the first row name is returned """
01082 
01083         rv = self.rnames[0]
01084         best = 0
01085         for r in self.rnames:
01086             hits = self[r].count(val)
01087             if hits > best:
01088                 best = hits
01089                 rv = r
01090         return rv
01091 
01092 
01093 
01094     def RowsWithSingCols(self):
01095         "return list of idxs of rows with at least one non-zero element unique to the column"
01096         rv = []
01097         for c in self.cnames:
01098             col = self.GetCol(c)
01099             idx = Seq.IdxOfUnique(col, lambda x: x!=0)
01100             if idx != None and not idx in rv:
01101                 rv.append(idx)
01102         return rv
01103 
01104 
01105     def SwapRow(self, r1, r2):
01106 
01107         if type(r1).__name__ == 'string':
01108             r1 = self.rnames.index(r1)
01109 
01110         if type(r2).__name__ == 'string':
01111             r2 = self.rnames.index(r2)
01112 
01113         tmp = self.rows[r1]
01114         self.rows[r1] = self.rows[r2]
01115         self.rows[r2] = tmp
01116 
01117         tmp = self.rnames[r1]
01118         self.rnames[r1] = self.rnames[r2]
01119         self.rnames[r2] = tmp
01120 
01121 
01122     def MakeFirstRow(self, r):
01123 
01124         row = self[r]
01125         if type(r)==types.StringType:
01126             name = r
01127         else:
01128             name = self.rnames[r]
01129 
01130         self.DelRow(r)
01131         self.rows.insert(0,row)
01132         self.rnames.insert(0,name)
01133 
01134 
01135     def MakeLastRow(self, r):
01136 
01137         row = self[r]
01138         if type(r)==types.StringType:
01139             name = r
01140         else:
01141             name = self.rnames[r]
01142 
01143         self.DelRow(r)
01144         self.rows.append(row)
01145         self.rnames.append(name)
01146 
01147 
01148     def AugRow(self, m):
01149         for r in range(len(m.rnames)):
01150             self.NewRow(m.rows[r], m.rnames[r] )
01151 
01152 
01153     def NonZeroR(self, seed=[], thresh=1e-6):
01154         """pre: mtx has no empty rows, and numrical elements
01155           post: return a seed + list of list of rownames for which r(a,b)> thresh
01156                   where r is sample correlaation coeff,
01157                   ** self is empty  -DESTRUCTIVE ! ** """
01158 
01159 
01160         lenself = len(self)
01161 
01162         if lenself==0:
01163             return seed
01164         elif lenself==1:
01165             return seed+self.rnames[:]
01166 
01167         FirstRow = self.rnames[0]
01168         rv = [FirstRow]
01169         for ThisRow in self.rnames[1:]:
01170             if abs(Seq.CosTheta(self[FirstRow],self[ThisRow])) > thresh:
01171                 rv.append(ThisRow)
01172                 self.DelRow(ThisRow)
01173         self.DelRow(FirstRow)
01174         return self.NonZeroR(seed+[rv], thresh)
01175 
01176 
01177 
01178     def RowDiffMtxFull(self, fun= None, Conv=float):
01179 
01180         rv = matrix(rnames=self.rnames, cnames=self.rnames, Conv=Conv)
01181         lenself = len(self)
01182         for r1 in range(lenself):
01183             for r2 in range(lenself):
01184                 rv[r1,r2] = fun(self[r1],self[r2])
01185 
01186         return rv
01187 
01188 
01189 
01190 
01191     def RowDiffMtx(self, fun=None,Conv=float):
01192         """ pre:  fun(self[r1],self[r2]) for 0 <= r1,r2  < len(self) returns type Conv
01193                      fun(r1,r2) == fun(r2,r1)
01194            post: returns M such that M[r1,r2] = fun(self[r1],self[r2])
01195             """
01196 
01197         if fun == None:
01198             fun = lambda x,y: abs(Sci.CosTheta(x,y))
01199 
01200         rv = matrix(rnames=self.rnames, cnames=self.rnames, Conv=Conv)
01201         lenself = len(self)
01202         for r1 in range(lenself):
01203             for r2 in range(r1, lenself):
01204                 rv.rows[r1][r2] = rv.rows[r2][r1] = fun(self[r1],self[r2])
01205 
01206         return rv
01207 
01208 
01209     def RowDiffMtx2(self,fun):
01210         """ as above, but fun takes self, r1, and r2 as args, and no type conversion is done """
01211 
01212         rv = matrix(rnames=self.rnames, cnames=self.rnames, Conv=self.Conv)
01213         lenself = len(self)
01214         for r1 in range(lenself):
01215             for r2 in range(r1+1, lenself):
01216                 rv[r1,r2] = rv[r2,r1] =  fun(self,r1,r2)
01217 
01218         return rv
01219 
01220 
01221     def ToNJTree(self):
01222         """pre:  self is square difference matrix
01223           post:  A string representing the NJ tree, based on row differences, as calculated by fun """
01224 
01225         def FindNearestRows(mtx):
01226 
01227             rv = mtx.rnames[0] ,mtx.cnames[1],mtx[0,1]
01228             if len(mtx) == 2:
01229                 return rv
01230 
01231             for r in range(len(mtx)):
01232                 for c in range(r):
01233                     el =  mtx[r,c]
01234                     if el == 0:
01235                        return mtx.rnames[r],mtx.cnames[c],0
01236                     else:
01237                         if el < rv[2]:
01238                             rv = mtx.rnames[r],mtx.cnames[c],mtx[r,c]
01239             return rv
01240 
01241         nodes = {}
01242         mtx = self.Copy()
01243         for r in mtx.rnames:
01244             nodes[r] = t = Tree.Tree()
01245             t.add_feature("name", r)
01246 
01247         while len(mtx) >1:
01248             print ".",
01249             m0,m1,dist = FindNearestRows(mtx)
01250             ch0 = nodes[m0]
01251             ch0.add_feature("dist", dist)
01252             ch1 = nodes[m1]
01253             ch1.add_feature("dist", dist)
01254 
01255             p = Tree.Tree()
01256             p.add_child(ch0)
01257             p.add_child(ch1)
01258 
01259             pname = m0+m1
01260             nodes[pname] = p
01261 
01262             mtx.NewRow(name=pname)
01263             mtx.NewCol(name=pname)
01264 
01265 
01266             for i in range(len(mtx)):
01267                 mtx[pname,i] = mtx[i,pname] = (mtx[m0,i]+mtx[m1,i])/2
01268 
01269             for m in m0, m1:
01270                 mtx.DelRow(m)
01271                 mtx.DelCol(m)
01272                 del nodes[m]
01273 
01274         return nodes.values()[0]
01275 
01276 
01277 
01278 
01279 
01280     def ToNJTreeOld(self):
01281         """pre:  self is square difference matrix
01282           post:  A string representing the NJ tree, based on row differences, as calculated by fun """
01283 
01284         def FindNearestRows(mtx):
01285 
01286             rv = 0,1,mtx[0,1]
01287             if len(mtx) == 2:
01288                 return rv
01289 
01290             for r in range(len(mtx)):
01291                 for c in range(r):
01292                     el =  mtx[r,c]
01293                     if el == 0:
01294                        return r,c,0
01295                     else:
01296                         if el < rv[2]:
01297                             rv = r,c,mtx[r,c]
01298             return rv
01299 
01300         while len(self) >1:
01301             m0,m1,v = FindNearestRows(self)
01302             strv = ":"+str(v)
01303             self.rnames[m0] = "(" + self.rnames[m0] + strv + "," + self.rnames[m1] + strv+")"
01304             for i in range(len(self)):
01305                 self[m0,i] = self[i,m0] = (self[m0,i]+self[m1,i])/2
01306 
01307             self.DelRow(m1)
01308             self.DelCol(m1)
01309 
01310         return self.rnames[0] + ";"
01311 
01312 
01313     def IntegiseR(self):
01314         """pre: Seq.Integise(r) for all r in self.rows
01315          post: all denominators = 1, ratios unchanged
01316 
01317         !!! Will Fail **SILENTLY** if self[r,c].GetNum() > max(int) !!!
01318 
01319             """
01320 
01321         self.Conv=int
01322         for r in self.rnames:
01323             self[r] = map(int,Seq.Integise(self[r]))
01324 
01325     def IntegiseC(self):
01326 
01327         self.Conv=int
01328         for c in self.cnames:
01329             self.SetCol(c, map(int,Seq.Integise(self.GetCol(c))))
01330 
01331 
01332     def ZapZeroes(self):
01333 
01334         for r in range(len(self)-1, -1, -1):
01335             if Seq.AllEq(self[r],0):
01336                 self.DelRow(r)
01337 
01338     def Mul(self, other):
01339         try:
01340             rows = (Sci.matrix(self.rows) *Sci.matrix(other.rows)).tolist()
01341             rv = self.__class__(rnames=self.rnames, cnames=other.cnames,Conv=self.Conv)
01342             rv.rows  = rows
01343             return rv
01344         except: # problem in Sci.mul, fall back to slower method
01345             print "Matrix.Mul() ?",
01346             selfr = len(self)
01347             otherr = len(other)
01348             selfc = len(self.cnames)
01349             otherc = len(other.cnames)
01350 
01351             if  selfc != otherr:
01352                 raise exceptions.ArithmeticError, "inconsistant matrices for multiplication"
01353 
01354             rv = self.__class__(selfr,otherc,Conv=self.Conv)
01355             other.Transpose()
01356             for i in range(selfr):
01357                 for j in range(otherc):
01358                     rv.rows[i][j] = sum(map(lambda x,y:x*y,self.rows[i],other.rows[j]))
01359             other.Transpose()
01360             rv.cnames = other.cnames[:]
01361             rv.rnames = self.rnames[:]
01362             return rv
01363 
01364 
01365     def OrthNullSpace(self):
01366         "orthogonal nullspace as matrix of floats"
01367 
01368         try:
01369             N = Sci.matrix(self.rows,float)
01370             K = Sci.null(N)
01371             Z = N*K
01372             Fail = Z.max() > Sci.TOL or Z.min() < -Sci.TOL
01373             if Fail:
01374                 print "OrthNullSpace out of tol"
01375         except:
01376             Fail = True   # possbility of unknown exceptions from low level math libs
01377             print "Sci.null() fails !"
01378 
01379         if not Fail:
01380             rv = matrix(FromMtx=K,Conv=float)
01381             rv.rnames = self.cnames[:]
01382             rv.cnames =map(lambda x: "c_"+str(x), range(len(rv[0])))
01383         else:
01384             print "falling back to (slow) GaussJ + GramS\n"
01385             if not self.Conv == Types.ArbRat:
01386                 rv = self.Copy(Conv=Types.ArbRat).NullSpace()
01387             else:
01388                 rv = self.NullSpace()
01389             rv.Orthogonalise()
01390 
01391         return rv
01392 
01393 
01394     def Orthogonalise(self):
01395         """ Use Gram-Schmidt orthogonalisation to make self orthognal"""
01396 
01397         self.Transpose() # transposing lets us use more efficient row (aot col) operations
01398         self.ChangeType(float)
01399 
01400         for j in range(len(self)):
01401             vj = self[j][:]
01402             for i in range(j):
01403                 ui = self[i]
01404                 vjui = -Seq.DotProd(vj,ui)
01405                 self.AddRow(j, map(lambda x: x*vjui, ui))
01406             NormJ = math.sqrt(sum(map(lambda x:x*x,self[j])))
01407             self.DivRow(j,k=NormJ)
01408         self.Transpose()
01409 
01410 
01411     def PseudoInverse(self,  AsSci=False):
01412 
01413         if self.Conv != float:
01414             rows = self.Copy(float).rows
01415         else:
01416             rows = self.rows
01417 
01418         rvrows = Sci.pinv(rows)
01419         if AsSci:
01420             rv = rvrows
01421         else:
01422             nrows, ncols = len(rvrows), len(rvrows[0])
01423             rv = self.__class__(nrows, ncols, Conv=float)
01424             rv.rows = rvrows.tolist
01425         return rv
01426 
01427 
01428     def SetPivot(self,Row):
01429 
01430         GotOne = 0
01431         vals=self.GetCol(Row)
01432 
01433         vals = map(abs, vals)[Row:]
01434         PivVal = max(vals)
01435         if PivVal != 0:
01436             GotOne = 1
01437             PivIdx = Row+vals.index(PivVal)
01438             if PivIdx != Row:
01439                 self.SwapRow(PivIdx,Row)
01440 
01441         return GotOne
01442 
01443 
01444     def ElimCol(self, Row):
01445         "pre: self.GetEl(Row,Row)==1"
01446 
01447         RowVals = self.rows[Row]
01448         for r in range(len(self.rows)):
01449             if r != Row and self.rows[r][Row] != 0:
01450                 mul = -self.rows[r][Row]
01451                 self.AddRow(r, RowVals, mul)
01452 
01453 
01454     def RedRowEch(self):
01455         """ put self in reduced row echelon form,
01456         uses col swaps in pivoting """
01457 
01458         CurRow = 0
01459         done = 0
01460         if self.Conv == float:
01461             Flatten = Seq.Flatten
01462         else:
01463             Flatten = lambda x,y: 0
01464 
01465         while not done:
01466             if Seq.AllEq(self.rows[CurRow], 0):
01467                 self.DelRow(CurRow)
01468             else:
01469                 if self.SetPivot(CurRow):
01470                     self.DivRow(CurRow,vals=None, k=self.rows[CurRow][CurRow])
01471                     self.ElimCol(CurRow)
01472                     Flatten(self[CurRow], 1e-6)
01473                     CurRow += 1
01474                 else:
01475                     self.MakeLastCol(CurRow)
01476 
01477             done = CurRow == len(self.rows)
01478 
01479 
01480     def NullSpace(self):
01481 
01482         rv = self.Copy(Conv=DefaultConv)
01483         rv.RedRowEch()
01484         nsrnames = rv.cnames[:]   # because we do col xchs in RedRowEch names get reordered and rv is othrewise mangled
01485         slice = len(rv.rows)
01486         if len(rv.cnames) != slice:
01487             for r in range(len(rv.rows)):
01488                 rv.rows[r] = rv.rows[r][slice:]
01489             rv.cnames = map(lambda x: "c_"+str(x), range(len(rv[0])))
01490             id = GetIdent(len(rv.cnames),Conv=self.Conv, mul = -1)
01491             rv.AugRow(id)
01492             rv.rnames = nsrnames
01493             rv.RowReorder(self.cnames) # so now  (self * rv) == 0
01494         else:
01495             # special case, invertible matrix, zero dimensional NullSpace
01496             rv.cnames = []
01497             rv.rnames = self.cnames[:]
01498             rv.rows = map(lambda x:[], rv.rnames)
01499         return rv
01500 
01501 
01502 

Generated on Tue Sep 4 2012 15:38:02 for ScrumPy by  doxygen 1.7.1