Матрица-матрица-умножение с использованием оператора умножения в Python: как? - PullRequest
0 голосов
/ 10 июня 2019

Я хочу перегрузить оператор умножения в Python. Что я хочу сделать, так это выполнить умножение матрицы на матрицу с помощью оператора * в Python. Использование Numpy запрещено.

import math
class Vec4():
    def __init__(self, x = 0, y = 0, z = 0, w = 0):
        """Constructor for Vec4
        DO NOT MODIFY THIS METHOD"""
        self.values = [x,y,z,w]

    def __str__(self):
        """Returns the vector as a string representation
        DO NOT MODIFY THIS METHOD"""
        toReturn = ''
        if self is None: return '0.00 0.00 0.00 0.00'
        for c in range(0,4):
                toReturn += "%.2f" % self.values[c]
                if c != 3:
                    toReturn += ' '
        return toReturn

class Matrix4():
    def __init__(self, row1=None, row2=None, row3=None, row4=None):
        """Constructor for Matrix4
        DO NOT MODIFY THIS METHOD"""
        if row1 is None: row1 = Vec4()
        if row2 is None: row2 = Vec4()
        if row3 is None: row3 = Vec4()
        if row4 is None: row4 = Vec4()
        self.m_values = [row1,row2,row3,row4]

    def __str__(self):
        """Returns a string representation of the matrix
        DO NOT MODIFY THIS METHOD"""
        toReturn = ''
        if self is None: return '0.00 0.00 0.00 0.00\n0.00 0.00 0.00 0.00\n0.00 0.00 0.00 0.00\n0.00 0.00 0.00 0.00'
        for r in range(0,4):
            for c in range(0,4):
                toReturn += "%.2f" % self.m_values[r].values[c]
                if c != 3:
                    toReturn += ' '
            toReturn += '\n'
        return toReturn

   def __matmul__(self, m):
        x = self.m_values[0].values[0]*m.m_values[0].values[0]+self.m_values[0].values[1]*m.m_values[1]*values[0]+self.m_values[0].values[2]*m.m_values[2].values[0]+self.m_values[0].values[3]*m.m_values[3].values[0]
        y = self.m_values[1].values[0]*m.m_values[0].values[1]+self.m_values[1].values[1]*m.m_values[1]*values[1]+self.m_values[1].values[2]*m.m_values[2].values[1]+self.m_values[1].values[3]*m.m_values[3].values[1]
        z = self.m_values[2].values[0]*m.m_values[0].values[2]+self.m_values[2].values[1]*m.m_values[1]*values[2]+self.m_values[2].values[2]*m.m_values[2].values[2]+self.m_values[2].values[3]*m.m_values[3].values[2]
        w = self.m_values[3].values[0]*m.m_values[0].values[3]+self.m_values[3].values[1]*m.m_values[1]*values[3]+self.m_values[3].values[2]*m.m_values[2].values[3]+self.m_values[3].values[3]*m.m_values[3].values[3]
        return Matrix4()

Вместо получения результата, подобного следующему:

A = Matrix4(Vec4(1, 0, 0, 0),
            Vec4(0, 1, 0, 0),
            Vec4(0, 0, 1, 0),
            Vec4(0, 0, 0, 1))

B = Matrix4(Vec4(1,2,3,4),
            Vec4(1,2,3,4),
            Vec4(1,2,3,4),
            Vec4(1,2,3,4))

print(A * B)

Вывод должен быть:

1.00 2.00 3.00 4.00
1.00 2.00 3.00 4.00
1.00 2.00 3.00 4.00
1.00 2.00 3.00 4.00

Но в моем случае это вызывает ошибку:

Traceback (most recent call last):
  File "<pyshell#14>", line 1, in <module>
    print(A*B)
  File "C:\Users\xxx\Downloads\Download-Stuff\Gmail\TransformMatrix.py", line 45, in __mul__
    x = self.m_values[0].values[0]*v.values[0]+self.m_values[1].values[0]*v.values[1]+self.m_values[2].values[0]*v.values[2]+self.m_values[3].values[0]*v.values[3]
AttributeError: 'Matrix4' object has no attribute 'values'

Что я делаю не так?

Спасибо за помощь заранее.

Ответы [ 2 ]

1 голос
/ 10 июня 2019

После консультации https://en.wikipedia.org/wiki/Matrix_multiplication, я сначала реализовал dot_product() и попытался получить более общее решение:

import math
class Vec4():
    def __init__(self, x = 0, y = 0, z = 0, w = 0):
        """Constructor for Vec4
        DO NOT MODIFY THIS METHOD"""
        self.values = [x,y,z,w]

    def __str__(self):
        """Returns the vector as a string representation
        DO NOT MODIFY THIS METHOD"""
        toReturn = ''
        if self is None: return '0.00 0.00 0.00 0.00'
        for c in range(0,4):
                toReturn += "%.2f" % self.values[c]
                if c != 3:
                    toReturn += ' '
        return toReturn

class Matrix4():
    def __init__(self, row1=None, row2=None, row3=None, row4=None):
        """Constructor for Matrix4
        DO NOT MODIFY THIS METHOD"""
        if row1 is None: row1 = Vec4()
        if row2 is None: row2 = Vec4()
        if row3 is None: row3 = Vec4()
        if row4 is None: row4 = Vec4()
        self.m_values = [row1,row2,row3,row4]

    def __str__(self):
        """Returns a string representation of the matrix
        DO NOT MODIFY THIS METHOD"""
        toReturn = ''
        if self is None: return '0.00 0.00 0.00 0.00\n0.00 0.00 0.00 0.00\n0.00 0.00 0.00 0.00\n0.00 0.00 0.00 0.00'
        for r in range(0,4):
            for c in range(0,4):
                toReturn += "%.2f" % self.m_values[r].values[c]
                if c != 3:
                    toReturn += ' '
            toReturn += '\n'
        return toReturn

    def get_column(self, j):
        return [vec.values[j] for vec in self.m_values]

    def get_row(self, i):
        return self.m_values[i].values

    def dot_product(self, m, i, j):
        return sum([x * y for x, y in zip(self.get_row(i), \
                                      m.get_column(j))])

    def shape(self):
        return len(self.m_values), len(self.m_values[0].values)

    def __mul__(self, mat):
        # m = len(self.m_values[0].values)
        n = self.shape()[0]
        p = mat.shape()[1]
        return Matrix4(*[Vec4(*[self.dot_product(mat, i, j)  for j in range(p)])  for i in range(n)])


A = Matrix4(Vec4(1, 0, 0, 0),
            Vec4(0, 1, 0, 0),
            Vec4(0, 0, 1, 0),
            Vec4(0, 0, 0, 1))

B = Matrix4(Vec4(1,2,3,4),
            Vec4(1,2,3,4),
            Vec4(1,2,3,4),
            Vec4(1,2,3,4))

print(A * B)

# 1.00 2.00 3.00 4.00
# 1.00 2.00 3.00 4.00
# 1.00 2.00 3.00 4.00
# 1.00 2.00 3.00 4.00

Общее решение

Для матриц произвольного размера.И с __repr__(), так что не всегда нужно печатать print(), чтобы увидеть строковое представление.

class Vec4():
    def __init__(self, *args):
        """Generalized constructor for Vec4"""
        self.values = args

    def __str__(self):
        """Returns the vector as a string representation"""
        if self.values == []: 
            return "Empy Vector of class Vec4"
        else:
            return ' '.join(["{0:.2f}".format(c) for c in self.values])

    def __repr__(self):
        return self.__str__()

class Matrix4():
    def __init__(self, *args):
        """Constructor for Matrix4"""
        self.values = args

    def __str__(self):
        """Returns a string representation of the matrix"""
        if self.values == []:
            return "Empty Matrix of class Matrix4"
        else:
            return '\n'.join([str(v) for v in self.values])

    def __repr__(self):
        return self.__str__()

    def get_column(self, j):
        return [vec.values[j] for vec in self.values]

    def get_row(self, i):
        return self.values[i].values

    def dot_product(self, m, i, j):
        return sum([x * y for x, y in zip(self.get_row(i), \
                                      m.get_column(j))])

    def shape(self):
        return len(self.values), len(self.values[0].values)

    def __mul__(self, mat):
        # m = len(self.values[0].values)
        n = self.shape()[0]
        p = mat.shape()[1]
        return Matrix4(*[Vec4(*[self.dot_product(mat, i, j)  for j in range(p)])  for i in range(n)])
1 голос
/ 10 июня 2019

Вы должны перегрузить, определив def __mul__(self, m):

...