#/usr/bin/env python

"""
MyMatrix: A skeletal module for matrices.
Note: SquareMatrix is designed so that methods requiring square matrices
get them. No need to check dimensions and raise ValueError.

Test routines run if the module is run by Python; not if it's imported.
"""

import numpy as np
import numpy.linalg as LA

class Matrix:
	"""Make a matrix with nRows rows and nColumns columns.
	   Set entries to zero.
	"""

	def __init__(self, nRows,nColumns):
		self.array = np.zeros(shape=(nRows,nColumns),dtype=float)
		self.nRows	= nRows
		self.nColumns = nColumns

	def __str__(self):
		return str(self.array)

	def __repr__(self):
		return 'Matrix:\n' + str(self.array)

	def __add__(self, other_matrix):
		return self.array+other_matrix.array

	def __sub__(self, other_matrix):
		return self.array-other_matrix.array

	def __mul__(self, other_matrix):
		return np.dot(self.array, other_matrix.array)

	def generalized_inverse(self):
		return LA.pinv(self.array)

	def shape(self):
		return np.shape(self.array)

	def random(self):
		self.array = np.reshape(np.random.random(self.nRows*self.nColumns),
			(self.nRows,self.nColumns))

class SquareMatrix(Matrix):
	"""Make a square matrix with nRows rows and nRows columns.
	   It inherits most of its functions from class Matrix.
	"""

	def __init__(self,nRows):
		Matrix.__init__(self,nRows,nRows)

	def inverse(self):
		return LA.inv(self.array)

	def eigenvalues(self):
		return LA.eigenvalues(self.array)

	def identity(self):
		B.array = np.identity(self.nRows)

	# If Python directly runs this module, these tests are done.
	#
if __name__ == "__main__":
	A = Matrix(3,4)
	print "A rectangular matrix:\n", A
	print "with shape: ",A.shape()
	A.random()
	print "A random matrix with the same shape:\n", A
	B = SquareMatrix(3)
	B.identity()
	print "A square matrix:\n",B
	print "It's inverse:\n",B.inverse()
