使用 Python 中的乘法运算符进行矩阵乘法:如何?

Matrix-matrix-multiplication using the multiplication operator in Python: How?

我想重载 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'

我做错了什么?

感谢您的提前帮助。

您必须通过定义 def __mul__(self, m):

来重载

经过咨询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)])