Matrizen

Code-Stücke können hier veröffentlicht werden.
Antworten
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

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
Antworten