Matrizen
Verfasst: Donnerstag 14. Oktober 2004, 12:29
Hi. Wieder einmal was aus dem Schulbedarf: eine Klasse für Matrizen. Ich weis, dass es bereits Module in C gibt, die dasselbe können, aber mir hat es beim lernen geholfen und für kleine Rechenaufgaben reicht es völlig. Da auch bei Inversen Matrizen oft Brüche gebraucht werden, noch gleich eine aktualisierte Form meiner alten Bruchklassen hinterher:
Code: Alles auswählen
import re
try:
from itertools import izip as zip
except ImportError:
def enumerate(seq):
return zip(xrange(len(seq)),seq)
from operator import add
def sum(seq):
return reduce(add,seq,0)
def makeBruchLines(lines):
b=Bruch()
return [[b*num for num in line] for line in lines]
def makeBruchMatrix(matrix):
if not isinstance(matrix,Matrix):
raise TypeError,"Matrix als Argument erwartet"
return Matrix(*makeBruchLines(matrix.getlines()))
class Bruch(object):
__slots__=["_float_regex","z","n"]
_float_regex=re.compile('(\d*)\.(\d*)e?([\+-]?)(\d{0,3})')
def __init__(self,z=1,n=1):
if isinstance(z,Bruch) or isinstance(n,Bruch):
z,n=(z/n).gettuple()
else:
z,n=map(int,(z,n))
if n>=0:
self.z,self.n=z,n
else:
self.z,self.n=[-z,-n]
t = self._ggt(self.z,self.n)
self.z,self.n=self.z/t,self.n/t
if self.n==0:
raise ZeroDivisionError, "integer division or modulo by zero"
def gettuple(self):
"""Gibt das Tupel (Zaehler,Nenner) zureuck"""
return self.z,self.n
def _forceBruch(self,wert):
if isinstance(wert,Bruch):
return wert
elif (type(wert) in (int,long)) or (wert % 1 == 0):
return Bruch(wert,1)
elif type(wert) == float:
temp=self._float_regex.match(repr(wert)).groups()
z=long(temp[0])*(10L**len(temp[1]))+long(temp[1])
n=10L**len(temp[1])
if temp[2]=='+':
z*=10L**long(temp[3])
if temp[2]=='-':
n*=10L**long(temp[3])
return Bruch(z,n)
else:
raise TypeError,"no compatiple type for operation"
def _ggt(self,x,y):
while y > 0:
x,y=y,x%y
return x
def _kgv(self,x,y):
return (x/self._ggt(x,y))*y
def __add__(self,other):
other = self._forceBruch(other)
return Bruch(self.z * other.n + other.z * self.n, self.n * other.n)
def __cmp__(self,other):
try:
other = self._forceBruch(other)
except TypeError:
return cmp(id(self),id(other))
else:
kgv=self._kgv(self.n,other.n)
zself=self.z*(kgv/self.n)
zother=other.z*(kgv/other.n)
return cmp(zself,zother)
def __div__(self,other):
other = self._forceBruch(other)
if other.z==0L:
raise ZeroDivisionError, "integer division or modulo by zero"
return Bruch(self.z * other.n, self.n * other.z)
def __divmod__(self,other):
other = self._forceBruch(other)
return (self.__div__(other),self.__mod__(other))
def __mod__(self,other):
other = self._forceBruch(other)
if other.z==0:
raise ZeroDivisionError, "integer division or modulo by zero"
ns=self._kgv(self.n,other.n)
zself=self.z*(ns/self.n)
zother=other.z*(ns/other.n)
return Bruch(zself%zother,ns)
def __mul__(self,other):
other = self._forceBruch(other)
if other.n==0L:
raise ZeroDivisionError, "integer division or modulo by zero"
return Bruch(self.z * other.z, self.n * other.n)
def __pow__(self,other,z=None):
if (other%1)==0:
other = self._forceBruch(other)
if other.z>=0:
erg=Bruch(self.z**other.z,self.n**other.z)
else:
erg=Bruch(self.n**(-other.z),self.z**(-other.z))
else:
tempself=float(self)
tempother=float(other)
erg=self._forceBruch(tempself**tempother)
if z==None:
return erg
else:
return erg%z
def __radd__(self,other):
return self.__add__(other)
def __rdiv__(self,other):
other = self._forceBruch(other)
if self.z==0L:
raise ZeroDivisionError, "integer division or modulo by zero"
return Bruch(other.z * self.n, other.n * self.z)
def __rdivmod__(self,other):
return (self.__rdiv__(other),self.__rmod__(other))
def __rmod__(self,other):
other = self._forceBruch(other)
if self.z==0:
raise ZeroDivisionError, "integer division or modulo by zero"
ns=self._kgv(self.n,other.n)
zself=self.z*(ns/self.n)
zother=other.z*(ns/other.n)
return Bruch(zother%zself,ns)
def __rmul__(self,other):
return self.__mul__(other)
def __rpow__(self,other,z=None):
if z==None:
return other**float(self)
else:
return (other**float(self))%z
def __rsub__(self,other):
other = self._forceBruch(other)
return Bruch(other.z * self.n - self.z * other.n, other.n * self.n)
def __sub__(self,other):
other = self._forceBruch(other)
return Bruch(self.z * other.n - other.z * self.n, self.n * other.n)
def __abs__(self):
return Bruch(abs(self.z),abs(self.n))
def __float__(self):
return float(self.z)/float(self.n)
def __int__(self):
return int(self.__long__())
def __long__(self):
if self.n==1:
return long(self.z)
else:
return long(float(self.z)/float(self.n))
def __neg__(self):
return Bruch(-self.z,self.n)
def __pos__(self):
return Bruch(self.z,self.n)
def __repr__(self):
return "Bruch(%i,%i)"%(self.z,self.n)
def __str__(self):
return "(%i / %i)"%(self.z,self.n)
class Matrix(object):
__slots__=["lines","type"]
def __init__(self,*lines):
m=len(lines)
self.lines=[]
if m:
temp=[]
for line in lines:
line=tuple(line)
self.lines.append(line)
temp.append(len(line))
temp.sort()
if temp[0]!=temp[-1]:
raise TypeError,"keine gueltige Matrix"
n=temp[0]
del temp
else:
raise TypeError,"keine gueltige Matrix"
self.type=(m,n)
def copy(self):
return Matrix(self.lines)
def getspalte(self,i):
return [line[i] for line in self.lines]
def getzeile(self,j):
return self.lines[j]
def getlines(self):
return self.lines
def adjunkte(self,i,j):
untermat=[l[:j]+l[j+1:] for num,l in enumerate(self.lines) if num!=i]
return ((i+j)%2==0 or -1)*Matrix(*untermat).det()
def det(self):
m,n=self.type
if m!=n:
raise ValueError,"Matrix muss n-reihig sein"
if m==1:
return self.lines[0][0]
elif m==2:
(a,b),(c,d)=self.lines
return a*d-b*c
elif m==3:
(a,b,c),(d,e,f),(g,h,i)=self.lines
return a*e*i+b*f*g+c*d*h-c*e*g-b*d*i-a*f*h
else:
det=0
zeile1=self.lines[0]
for j in xrange(n):
det+=zeile1[j]*self.adjunkte(0,j)
return det
def invert(self):
m,n=self.type
if m!=n:
print m,n
raise ValueError,"Matrix muss n-reihig sein"
d=self.det()
if d==0:
raise ValueError,"Matrix nicht regulaer"
elif d==1:
pass
else:
d=1.0/d
return Matrix(*[[self.adjunkte(i,j) for j in xrange(n)] for i in xrange(n)]).transponiere() * d
def transponiere(self):
return Matrix(*zip(*self.lines))
def __add__(self,other):
if isinstance(other,Matrix):
m,n=self.type
m_o,n_o=other.type
if m!=m_o or n!=n_o:
raise ValueError,"Matrizen nicht verkettbar"
return Matrix(*[[self.lines[i][j]+other.lines[i][j] for j in xrange(n)] for i in xrange(m)])
else:
raise TypeError,"nicht rechenbar (Matrix und %s)"%type(other)
def __div__(self,other):
if isinstance(other,Matrix):
raise ValueError,"nicht durch Matrizen teilbar"
return self.__mul__(1.0/other)
def __mul__(self,other):
if isinstance(other,Matrix):
m,n=self.type
m_o,n_o=other.type
if n!=m_o:
raise ValueError,"Matrizen nicht verkettbar"
newmat=[]
for i in xrange(m):
newmatline=[]
for j in xrange(n_o):
newmatline.append(sum([self.lines[i][k]*other.lines[k][j] for k in xrange(n)]))
newmat.append(newmatline)
return Matrix(*newmat)
else:
return Matrix(*[tuple([element*other for element in line]) for line in self.lines])
def __pow__(self,other):
if other%1!=0:
raise ValueError,"nicht rechenbar (Exponent muss ganzzahlig sein)"
m,n=self.type
if m!=n:
raise ValueError,"Matrix muss n-reihig sein"
mat=Matrix(*[[int(i==j) for j in xrange(n)] for i in xrange(n)])
for i in xrange(abs(other)):
mat*=self
if other < 0:
mat=mat.invert()
return mat
def __rmul__(self,other):
assert not isinstance(other,Matrix)
return Matrix(*[tuple([element*other for element in line]) for line in self.lines])
def __sub__(self,other):
if isinstance(other,Matrix):
m,n=self.type
m_o,n_o=other.type
if m!=m_o or n!=n_o:
raise ValueError,"Matrizen nicht verkettbar"
return Matrix(*[[self.lines[i][j]-other.lines[i][j] for j in xrange(n)] for i in xrange(m)])
else:
raise TypeError,"nicht rechenbar (Matrix und %s)"%type(other)
def __neg__(self):
return -1 * self
def __pos__(self):
return self
def __repr__(self):
return "Matrix( %r )" % self.lines