Welcome, guest | Sign In | My Account | Store | Cart
import random
import operator
import sys
import unittest

__version__
= "0.3"

class MatrixError(Exception):
   
""" An exception class for Matrix """
   
pass

class Matrix(object):
   
""" A simple Python matrix class with
    basic operations and operator overloading """

   
   
def __init__(self, m, n, init=True):
       
if init:
           
self.rows = [[0]*n for x in range(m)]
       
else:
           
self.rows = []
       
self.m = m
       
self.n = n
       
   
def __getitem__(self, idx):
       
return self.rows[idx]

   
def __setitem__(self, idx, item):
       
self.rows[idx] = item
       
   
def __str__(self):
        s
='\n'.join([' '.join([str(item) for item in row]) for row in self.rows])
       
return s + '\n'

   
def __repr__(self):
        s
=str(self.rows)
        rank
= str(self.getRank())
        rep
="Matrix: \"%s\", rank: \"%s\"" % (s,rank)
       
return rep
   
   
def reset(self):
       
""" Reset the matrix data """
       
self.rows = [[] for x in range(self.m)]
                     
   
def transpose(self):
       
""" Transpose the matrix. Changes the current matrix """
       
       
self.m, self.n = self.n, self.m
       
self.rows = [list(item) for item in zip(*self.rows)]

   
def getTranspose(self):
       
""" Return a transpose of the matrix without
        modifying the matrix itself """

       
        m
, n = self.n, self.m
        mat
= Matrix(m, n)
        mat
.rows =  [list(item) for item in zip(*self.rows)]
       
       
return mat

   
def getRank(self):
       
return (self.m, self.n)

   
def __eq__(self, mat):
       
""" Test equality """

       
return (mat.rows == self.rows)
       
   
def __add__(self, mat):
       
""" Add a matrix to this matrix and
        return the new matrix. Doesn't modify
        the current matrix """

       
       
if self.getRank() != mat.getRank():
           
raise MatrixError, "Trying to add matrixes of varying rank!"

        ret
= Matrix(self.m, self.n)
       
       
for x in range(self.m):
            row
= [sum(item) for item in zip(self.rows[x], mat[x])]
            ret
[x] = row

       
return ret

   
def __sub__(self, mat):
       
""" Subtract a matrix from this matrix and
        return the new matrix. Doesn't modify
        the current matrix """

       
       
if self.getRank() != mat.getRank():
           
raise MatrixError, "Trying to add matrixes of varying rank!"

        ret
= Matrix(self.m, self.n)
       
       
for x in range(self.m):
            row
= [item[0]-item[1] for item in zip(self.rows[x], mat[x])]
            ret
[x] = row

       
return ret

   
def __mul__(self, mat):
       
""" Multiple a matrix with this matrix and
        return the new matrix. Doesn't modify
        the current matrix """

       
        matm
, matn = mat.getRank()
       
       
if (self.n != matm):
           
raise MatrixError, "Matrices cannot be multipled!"
       
        mat_t
= mat.getTranspose()
        mulmat
= Matrix(self.m, matn)
       
       
for x in range(self.m):
           
for y in range(mat_t.m):
                mulmat
[x][y] = sum([item[0]*item[1] for item in zip(self.rows[x], mat_t[y])])

       
return mulmat

   
def __iadd__(self, mat):
       
""" Add a matrix to this matrix.
        This modifies the current matrix """


       
# Calls __add__
        tempmat
= self + mat
       
self.rows = tempmat.rows[:]
       
return self

   
def __isub__(self, mat):
       
""" Add a matrix to this matrix.
        This modifies the current matrix """


       
# Calls __sub__
        tempmat
= self - mat
       
self.rows = tempmat.rows[:]    
       
return self

   
def __imul__(self, mat):
       
""" Add a matrix to this matrix.
        This modifies the current matrix """


       
# Possibly not a proper operation
       
# since this changes the current matrix
       
# rank as well...
       
       
# Calls __mul__
        tempmat
= self * mat
       
self.rows = tempmat.rows[:]
       
self.m, self.n = tempmat.getRank()
       
return self

   
def save(self, filename):
        open
(filename, 'w').write(str(self))
       
   
@classmethod
   
def _makeMatrix(cls, rows):

        m
= len(rows)
        n
= len(rows[0])
       
# Validity check
       
if any([len(row) != n for row in rows[1:]]):
           
raise MatrixError, "inconsistent row length"
        mat
= Matrix(m,n, init=False)
        mat
.rows = rows

       
return mat
       
   
@classmethod
   
def makeRandom(cls, m, n, low=0, high=10):
       
""" Make a random matrix with elements in range (low-high) """
       
        obj
= Matrix(m, n, init=False)
       
for x in range(m):
            obj
.rows.append([random.randrange(low, high) for i in range(obj.n)])

       
return obj

   
@classmethod
   
def makeZero(cls, m, n):
       
""" Make a zero-matrix of rank (mxn) """

        rows
= [[0]*n for x in range(m)]
       
return cls.fromList(rows)

   
@classmethod
   
def makeId(cls, m):
       
""" Make identity matrix of rank (mxm) """

        rows
= [[0]*m for x in range(m)]
        idx
= 0
       
       
for row in rows:
            row
[idx] = 1
            idx
+= 1

       
return cls.fromList(rows)
   
   
@classmethod
   
def readStdin(cls):
       
""" Read a matrix from standard input """
       
       
print 'Enter matrix row by row. Type "q" to quit'
        rows
= []
       
while True:
            line
= sys.stdin.readline().strip()
           
if line=='q': break

            row
= [int(x) for x in line.split()]
            rows
.append(row)
           
       
return cls._makeMatrix(rows)

   
@classmethod
   
def readGrid(cls, fname):
       
""" Read a matrix from a file """

        rows
= []
       
for line in open(fname).readlines():
            row
= [int(x) for x in line.split()]
            rows
.append(row)

       
return cls._makeMatrix(rows)

   
@classmethod
   
def fromList(cls, listoflists):
       
""" Create a matrix by directly passing a list
        of lists """


       
# E.g: Matrix.fromList([[1 2 3], [4,5,6], [7,8,9]])

        rows
= listoflists[:]
       
return cls._makeMatrix(rows)
       

class MatrixTests(unittest.TestCase):

   
def testAdd(self):
        m1
= Matrix.fromList([[1, 2, 3], [4, 5, 6]])
        m2
= Matrix.fromList([[7, 8, 9], [10, 11, 12]])        
        m3
= m1 + m2
       
self.assertTrue(m3 == Matrix.fromList([[8, 10, 12], [14,16,18]]))

   
def testSub(self):
        m1
= Matrix.fromList([[1, 2, 3], [4, 5, 6]])
        m2
= Matrix.fromList([[7, 8, 9], [10, 11, 12]])        
        m3
= m2 - m1
       
self.assertTrue(m3 == Matrix.fromList([[6, 6, 6], [6, 6, 6]]))

   
def testMul(self):
        m1
= Matrix.fromList([[1, 2, 3], [4, 5, 6]])
        m2
= Matrix.fromList([[7, 8], [10, 11], [12, 13]])
       
self.assertTrue(m1 * m2 == Matrix.fromList([[63, 69], [150, 165]]))
       
self.assertTrue(m2*m1 == Matrix.fromList([[39, 54, 69], [54, 75, 96], [64, 89, 114]]))

   
def testTranspose(self):

        m1
= Matrix.makeRandom(25, 30)
        zerom
= Matrix.makeZero(25, 30)
        m2
= m1 + zerom
       
        m1
.transpose()
        m1
.transpose()
       
self.assertTrue(m2 == m1)

       
# Also test getTranspose
        m2
= m1.getTranspose()
        r2
= m2.getRank()

       
self.assertTrue(r2==(30,25))
        m2
.transpose()

       
self.assertTrue(m2 == m1)

   
def testId(self):

        m1
= Matrix.makeId(10)
        m2
= Matrix.makeRandom(4, 10)
        m3
= m2*m1
       
self.assertTrue(m3 == m2)

if __name__ == "__main__":
    unittest
.main()

Diff to Previous Revision

--- revision 2 2012-05-14 10:34:06
+++ revision 3 2012-05-14 13:34:31
@@ -3,7 +3,7 @@
 
import sys
 
import unittest
 
-__version__ = "0.2"
+__version__ = "0.3"
 
 
class MatrixError(Exception):
     
""" An exception class for Matrix """
@@ -13,8 +13,11 @@
     
""" A simple Python matrix class with
     basic operations and operator overloading """

     
-    def __init__(self, m, n):
-        self.rows = [[0]*n for x in range(m)]
+    def __init__(self, m, n, init=True):
+        if init:
+            self.rows = [[0]*n for x in range(m)]
+        else:
+            self.rows = []
         
self.m = m
         
self.n = n
         
@@ -41,30 +44,17 @@
     
def transpose(self):
         
""" Transpose the matrix. Changes the current matrix """
         
-        # Rows become columns and columns become rows
-        indexed = [i for row in self.rows for i in enumerate(row)]
-        rows = sorted(indexed, key=operator.itemgetter(0))
         
self.m, self.n = self.n, self.m
-        
-        self.rows = [[] for x in range(self.m)]
-        
-        for key, val in rows:
-            self.rows[key].append(val)
+        self.rows = [list(item) for item in zip(*self.rows)]
 
     
def getTranspose(self):
         
""" Return a transpose of the matrix without
         modifying the matrix itself """

         
-        indexed = [i for row in self.rows for i in enumerate(row)]
-        rows = sorted(indexed, key=operator.itemgetter(0))
         m
, n = self.n, self.m
         mat
= Matrix(m, n)
-        
-        mat.reset()
-        
-        for key, val in rows:
-            mat.rows[key].append(val)
-
+        mat.rows =  [list(item) for item in zip(*self.rows)]
+        
         
return mat
 
     
def getRank(self):
@@ -158,6 +148,9 @@
         
self.m, self.n = tempmat.getRank()
         
return self
 
+    def save(self, filename):
+        open(filename, 'w').write(str(self))
+        
     
@classmethod
     
def _makeMatrix(cls, rows):
 
@@ -166,7 +159,7 @@
         
# Validity check
         
if any([len(row) != n for row in rows[1:]]):
             
raise MatrixError, "inconsistent row length"
-        mat = Matrix(m,n)
+        mat = Matrix(m,n, init=False)
         mat
.rows = rows
 
         
return mat
@@ -175,10 +168,9 @@
     
def makeRandom(cls, m, n, low=0, high=10):
         
""" Make a random matrix with elements in range (low-high) """
         
-        obj = Matrix(m, n)
+        obj = Matrix(m, n, init=False)
         
for x in range(m):
-            for y in range(n):
-                obj[x][y] = random.randrange(low, high)
+            obj.rows.append([random.randrange(low, high) for i in range(obj.n)])
 
         
return obj
 
@@ -188,7 +180,20 @@
 
         rows
= [[0]*n for x in range(m)]
         
return cls.fromList(rows)
-        
+
+    @classmethod
+    def makeId(cls, m):
+        """ Make identity matrix of rank (mxm) """
+
+        rows = [[0]*m for x in range(m)]
+        idx = 0
+        
+        for row in rows:
+            row[idx] = 1
+            idx += 1
+
+        return cls.fromList(rows)
+    
     
@classmethod
     
def readStdin(cls):
         
""" Read a matrix from standard input """
@@ -264,7 +269,13 @@
         m2
.transpose()
 
         
self.assertTrue(m2 == m1)
-        
+
+    def testId(self):
+
+        m1 = Matrix.makeId(10)
+        m2 = Matrix.makeRandom(4, 10)
+        m3 = m2*m1
+        self.assertTrue(m3 == m2)
 
 
if __name__ == "__main__":
     unittest
.main()

History