繁体   English   中英

如何在不导入模块的情况下在 python 中创建矩阵? 在不导入模块的情况下如何制作张量?

[英]How would I create a matrix in python without importing modules? How would I make a tensor without importing modules?

我正在尝试在 python 中创建矩阵和张量,而不导入任何模块,例如 numpy。 有办法做到这一点吗?

矩阵只是列表的列表。 您可以这样做:

x = [[0, 1, 2, 3, 4],
     [1, 2, 3, 4, 5],
     [3, 4, 5, 6, 7]]

至于在没有 numpy 的情况下执行操作,这将取决于您创建可能使用嵌套循环的函数。

这将是一个列表列表,例如:

matrix = [
    [1, 0, 0],
    [0, 1, 0],
    [0, 0, 0],
]

然后,您必须在该数据结构之上实现所有数学运算(矩阵乘法等)。

Python 为矩阵乘法保留方法名__matmul__

class Matrix:

    def __mul__(left, right):
        print("__mul__ was called")

    def __matmul__(left, right):
        print("__MATMUL__ WAS CALLED")

    def __rmatmul__(right, left):
        print(40*"#")
        print("__rmatmul__")
        print("left == ", left)
        print("right == ", right)
        print(40 * "#")

    def __imatmul__(total, step):
        print("__imatmul__")

a = Matrix()
b = Matrix()

a * b # scalar multiplication __mul__
a @ b # matrix multiplication __matmul__
3 @ b # matrix multiplication __rmatmul__
a @= b

__imatmul__类似于以下内容:

x = 5
x += 2   # __iadd__(x, 2)   `x = x + 2`
x *= 1   # __imul__(x, 3)   `x = x * 3`

每当您编写x * y python 时,都会首先尝试从左侧参数中获取乘法的定义。 也就是说, x * y最初是type(x).__add__(x, y)
然而,有时左边的东西不知道如何将自己与右边的东西相乘。

class K:
    pass

a = K()
result = 55*a
result = type(55).__mul__(55, a)

int class 不知道如何将55和 class K的实例相乘。 如果type(left).__mul__(left, right)失败,则调用备份机制type(right).__rmul__(right, left) 如果您编写自己的矩阵 class,那么当您将标量倍数(如 88)放在前面时,将调用 3 __rmatmul____rmul__

m = Matrix()
88 * m     # __rmul__(m, 88)
88 @ m     # __rmatmul__(m, 88)

实现矩阵的一种方法是作为列表列表:

matrix = [
    [1, 0, 0],
    [0, 1, 0],
    [0, 0, 0],
]

这有几个显着的缺点。 一个是容易select一行的矩阵:

matrix[1] == [0, 1, 0]

但是,选择列的效率会非常低:

def get_column(coli:int):
    coli = 1
    column = list()
    for rowi in range(len(matrix)):
        column.append(matrix[rowi][coli])
    return column

一种解决方案是有两个不同的列表列表:

  1. 一个以“行主要”顺序排列。
  2. 另一个以“列主要”顺序排列。

row_then_col = [
    [[("r0", "c0")], [("r0", "c1")], [("r0", "c2")]],
    [[("r1", "c0")], [("r1", "c1")], [("r1", "c2")]],
    [[("r2", "c0")], [("r2", "c1")], [("r2", "c2")]],
]


ncols = 3
nrows = 3
col_then_row = list()
for coli in range(ncols):
    col_then_row.append([None]*ncols)
    for rowi in range(nrows):
        col_then_row[coli]
        col_then_row[coli][rowi] = row_then_col[rowi][coli]

然后col_then_row[coli]将返回一整列, row_then_col[rowi]将返回一整行。 您可以使用包含一个元素的列表来伪造“指针”。 这将允许row_then_col col_then_row可见,反之亦然,无需更新任何内容。

row_then_col[1][2][0] = "happy"
print(col_then_row[2][1][0]) # "happy"

矩阵乘法有很多算法 我建议实施Strassen 算法 它不是世界上最快的,但它比真正快速的更容易理解。

有很多方法可以实现矩阵。 一种实现的开始如下所示:

import io
import math
import abc

def flatten(container):
    for elem in container:
        if not hasattr(elem, "__iter__"):
            yield elem
        else:
            it_elem = iter(elem)
            subelem = next(it_elem)
            if subelem != elem:
                yield subelem
                for j in flatten(it_elem):
                    yield j


class MatrixNodeState(abc.ABC):
    """
    Abstract Base Class
    """
    pass
MatrixNodeState.MatrixNodeState = MatrixNodeState

class MatrixNodeStateNullNullNullClass(MatrixNodeState):
    @classmethod
    def ERR(cls):
        with io.StringIO() as string_stream:
            print(
                "YOU ARE OFF THE EDGE OF THE MAP!",
                "STOP ITERATING!",
                file=string_stream
            )
            msg = string_stream.getvalue()
        raise cls.OFF_THE_EDGE_OF_THE_MAP(msg)

    class OFF_THE_EDGE_OF_THE_MAP(Exception):
        pass

    def __getattribute__(self, *args):
        type(self).ERR()

    def __setattr__(self, *args):
        type(self).ERR()
MatrixNodeState.nullnullnull = MatrixNodeStateNullNullNullClass()


class MatrixNodeStateNullNullClass(MatrixNodeState):
    def __setattr__(*args):
        pass

    def __getattribute__(self, *args):
        return type(self).nullnullnull

MatrixNodeState.nullnull = MatrixNodeStateNullNullClass()

class MatrixNodeStateNullClass(MatrixNodeState):
    """
    This class exists because `None.left = n`
    would produce an error

    `null.left = k` -----`no operation`.
                          Does nothing
                          Does not set the `left` attribute
                          of the nullnull node.

    `x = node.left`  returns `nullnull`
    """
    def __setattr__(*args):
        pass
    def __getattribute__(self, *args):
        return type(self).nullnull
MatrixNodeState.null = MatrixNodeStateNullClass()

class MatrixNodeStateNonNullNull(MatrixNodeState):
    def __init__(self, data):
        self.data  = data
        self.up    = type(self).null
        self.right = type(self).null
        self.down  = type(self).null
        self.left  = type(self).null
    def __setattr__(self, key, value):
        if isinstance(value, type(self).nullnull):
            value = type(self).null
        elif isinstance(value, type(self).nullnullnull):
            value = type(self).null
        super().__setattr__(self, key, value)


MatrixNodeState.MatrixNodeStateNonNullNull = MatrixNodeStateNonNullNull

class MatrixNode:
    def __init__(self, data=None):
        MatrixNodeState = type(self)
        if data:
            self.state = MatrixNodeState.MatrixNodeStateNonNullNull(data)
        else:
            self.state = MatrixNodeState.nullnull
    def __getattr__(self, attrname):
        return self.state.attrname
    def __setattr__(self, attr_name, attr_value):
        try:
            object.__getattr__(self)
            super().__setattr__(self, attr_name, attr_value)
        except AttributeError:
            setattr(self.state, attr_name, attr_value)

MatrixNode.MatrixNodeState = MatrixNodeState   

class Matrix:
    """

    """
    MatrixNode = MatrixNode

    def __init__(self, xdims, xelems):
        """
        Example 1:
             m = Matrix([3, 3], [1, 0, 0, 0, 1, 0, 0, 0, 1])
        Example 2
            m = Matrix([3, 3], [[1, 0, 0], [0, 1, 0], [0, 0, 1]])
        """
        MatrixNode = type(self).MatrixNode
        idims = tuple(map(int, xdims))
        ielems = iter(flatten(xelems))
        nrows = idims[0]
        ncols = idims[1]
        self.d = dict()
        try:            
            elem_count = 0
            left_node = MatrixNode.nullnull
            up_node = MatrixNode.nullnull 
            for rowi in range(nrows):
                for coli in range(ncols):
                    ielem = next(ielem)
                    elem_count += 1
                    up_node = left_node.up.right
                    node = MatrixNode(ielem)
                    self.d[(rowi, coli)] = node
                    node.left = left_node
                    left_node.right = node
                    node.up = up_node
                    up_node.down = node
                    left_node = node

        except StopIteration:
            with io.StringIO() as string_stream:
                print(
                    "Dimensions", idims, "indicated",
                    "that there should be", math.prod(idims),
                    "elements.", "Instead, only ", elem_count,
                    "elements were found.",
                    file=string_stream
                )
                msg = string_stream.getvalue()
            raise TypeError(msg)

    def __getitem__(self, xkey):
        ikey = tuple(map(int, iter(flatten(xkey))))
        return self.d[ikey].data

    def __setitem__(self, xkey, xval):
        ikey = tuple(map(int, iter(flatten(xkey))))
        self.d[ikey].data = xval
        return

    def get_column(self, coli):
        coli = int(str(coli))

    def get_row(self, rowi):
        rowi = int(str(rowi))

    def __mul__(left, right):
        print("__mul__ was called")
        raise NotImplementedError()

    def __rmul__(right, left):
        """
        m = Matrix([1, 2, 3])
        88 * m
        """
        print("__rmul__ was called")
        raise NotImplementedError()

    def __matmul__(left, right):
        print("__MATMUL__ WAS CALLED")
        raise NotImplementedError()

    def __rmatmul__(right, left):
        print(40*"#")
        print("__rmatmul__")
        print("left == ", left)
        print("right == ", right)
        print(40 * "#")
        raise NotImplementedError()

    def __imatmul__(total, step):
        print("__imatmul__")
        raise NotImplementedError()

    def __str__(self):
        raise NotImplementedError()

    def __repr__(self):
        return type(self) + str(self)


row_then_col = [
    [[("r0", "c0")], [("r0", "c1")], [("r0", "c2")]],
    [[("r1", "c0")], [("r1", "c1")], [("r1", "c2")]],
    [[("r2", "c0")], [("r2", "c1")], [("r2", "c2")]],
]

a = Matrix([3, 3], row_then_col)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM