Python 矩阵的对称积

Python 矩阵的对称积,python,matrix-multiplication,Python,Matrix Multiplication,Python:是否有任何函数 输入:两个矩阵A和B,两个数字 输出:矩阵的对称乘积 例如: F(A,B,1,1)=AB+BA F(A,B,2,1)=A^2B+ABA+BA^2(2表示乘积中的两个A矩阵,1表示乘积中的一个B矩阵),依此类推 此功能对于以下问题是必需的: 计算各种m和n的矩阵C(0大多数复杂问题的解决方案都涉及到分解成更小的问题并分别解决它们 我们可以将此问题改写为两部分: 生成操作序列 例如对于F(A,B,2,1)->AAB+ABA+BAA(隐式矩阵乘法) 计算(有效地)这些

Python:是否有任何
函数

输入:两个矩阵A和B,两个数字

输出:矩阵的对称乘积

例如:

F(A,B,1,1)=AB+BA
F(A,B,2,1)=A^2B+ABA+BA^2
(2表示乘积中的两个A矩阵,1表示乘积中的一个B矩阵),依此类推

此功能对于以下问题是必需的:


计算各种m和n的矩阵C(0大多数复杂问题的解决方案都涉及到分解成更小的问题并分别解决它们

我们可以将此问题改写为两部分:

  • 生成操作序列

    例如对于
    F(A,B,2,1)->AAB+ABA+BAA
    (隐式矩阵乘法)

  • 计算(有效地)这些运算。我们可以注意到,一些计算将被执行多次。例如,当我们计算
    AAB+ABA+BAA
    时,我们可以将所有
    AA
    乘法分组,并存储结果,以便以后需要时使用

为了生成序列,我们可以使用
更多的itertools
不同的排列
。通过将
A
编码为
0
B
编码为
1
,它生成我们想要的计算序列

要对一个序列执行计算,我们应该利用以前的计算。我们可以使用记忆来记忆以前的结果,并且只执行一次

# /!\ IMPORTANT: This initialization is wrong in some case, see the EDIT.
memo = {(0,): A, 
        (1,): B
       }  # should be initialized everytimes A, or B changes.

def matmul_perm(A, B, perm):
    if perm in memo:  # If previously computed, return result
        return memo[perm]

    mid = len(perm) // 2

    memo[perm] = (matmul_perm(A, B, perm[:mid]) @ 
                  matmul_perm(A, B, perm[mid:]))  # Split computation in 2 equal part and store result
    return memo[perm]
现在我们可以定义我们的函数:

def F(A, B, na, nb):
    s = 0
    for perm in distinct_permutations((0,)*na + (1,)*nb):
        s += matmul_perm(A, B, perm)
    return s
最后测试我们的程序:

A = np.random.randn(50, 50)

B = np.random.randn(50, 50)

memo = {(1,): B, (0,): A}

np.max(np.abs(F(A, B, 2, 2) - (A@A@B@B + A@B@A@B + B@A@A@B + A@B@B@A + B@A@B@A + B@B@A@A)))
>>> 1.8189894035458565e-12
用大小为
50×50
A
B
以及一份新的备忘录计算
F(A,B,10,10)
大约需要6秒。(不到一秒的时间重新计算)

编辑

当使用
na=nb=0
调用时,此实现将永远递归。最简单的修复方法是将
memo
初始化更改为

memo = {(0,): A, 
        (1,): B,
        (): np.eye(*A.shape)  # Empty product !
       }

大多数解决复杂问题的方法都是将问题分解成更小的问题,然后分别解决

我们可以将此问题改写为两部分:

  • 生成操作序列

    例如对于
    F(A,B,2,1)->AAB+ABA+BAA
    (隐式矩阵乘法)

  • 计算(有效地)这些运算。我们可以注意到,一些计算将被执行多次。例如,当我们计算
    AAB+ABA+BAA
    时,我们可以将所有
    AA
    乘法分组,并存储结果,以便以后需要时使用

为了生成序列,我们可以使用
更多的itertools
不同的排列
。通过将
A
编码为
0
B
编码为
1
,它生成我们想要的计算序列

要对一个序列执行计算,我们应该利用以前的计算。我们可以使用记忆来记忆以前的结果,并且只执行一次

# /!\ IMPORTANT: This initialization is wrong in some case, see the EDIT.
memo = {(0,): A, 
        (1,): B
       }  # should be initialized everytimes A, or B changes.

def matmul_perm(A, B, perm):
    if perm in memo:  # If previously computed, return result
        return memo[perm]

    mid = len(perm) // 2

    memo[perm] = (matmul_perm(A, B, perm[:mid]) @ 
                  matmul_perm(A, B, perm[mid:]))  # Split computation in 2 equal part and store result
    return memo[perm]
现在我们可以定义我们的函数:

def F(A, B, na, nb):
    s = 0
    for perm in distinct_permutations((0,)*na + (1,)*nb):
        s += matmul_perm(A, B, perm)
    return s
最后测试我们的程序:

A = np.random.randn(50, 50)

B = np.random.randn(50, 50)

memo = {(1,): B, (0,): A}

np.max(np.abs(F(A, B, 2, 2) - (A@A@B@B + A@B@A@B + B@A@A@B + A@B@B@A + B@A@B@A + B@B@A@A)))
>>> 1.8189894035458565e-12
用大小为
50×50
A
B
以及一份新的备忘录计算
F(A,B,10,10)
大约需要6秒。(不到一秒的时间重新计算)

编辑

当使用
na=nb=0
调用时,此实现将永远递归。最简单的修复方法是将
memo
初始化更改为

memo = {(0,): A, 
        (1,): B,
        (): np.eye(*A.shape)  # Empty product !
       }

你可以从numpy中的矩阵乘法开始,并以此为基础:对称积是如何定义的?例如,在
F(A,B,3,1)
?F(A,B,3,1)的情况下,它的行为如何=A^3B+A^2BA+ABA^2+BA^3请看上面m=3的问题,n=1你可以从numpy中的矩阵乘法开始,并以此为基础:对称积是如何定义的?例如,在
F(A,B,3,1)
?F(A,B,3,1)=A^3B+A^2BA+ABA^2+BA^3的情况下,它会如何表现?请看上面m=3的问题,n=1下面的片段:循环打印(F(A,B,i,j)),其中i和j在范围内变化(2)给出错误:递归错误:超过了最大递归深度。但如果我多次调用F,它运行良好。是否有可能绕过此问题?我认为问题是当使用
na
nb
=0调用它时。对此有一个修复方法,我将进行编辑。以下代码片段:循环打印(F(A,B,i,j)),其中i和j在范围内变化(2)给出错误:递归错误:超过了最大递归深度。但如果我多次调用F,它运行良好。是否有可能绕过此问题?我认为问题是当使用
na
nb
=0调用它时。对此有一个修复方法,我将进行编辑。