计算矢量v的矩阵的“v ^ T A v”

时间:2013-08-30 21:40:23

标签: numpy

我有一个k*n矩阵X和一个k*k矩阵A.对于X的每一列,我想计算标量

X[:, i].T.dot(A).dot(X[:, i])

(或者,数学上,Xi' * A * Xi)。

目前,我有一个for循环:

out = np.empty((n,))
for i in xrange(n):
    out[i] = X[:, i].T.dot(A).dot(X[:, i])

但由于n很大,如果可能的话我想更快地做到这一点(即使用一些NumPy函数而不是循环)。

3 个答案:

答案 0 :(得分:5)

这似乎做得很好: (X.T.dot(A)*X.T).sum(axis=1)

编辑:这有点快。 np.einsum('...i,...i->...', X.T.dot(A), X.T)。如果XA是Fortran连续的话,两者都会更好。

答案 1 :(得分:3)

您可以使用numpy.einsum

np.einsum('ji,jk,ki->i',x,a,x)

这将得到相同的结果。让我们看看它是否更快:

enter image description here

看起来dot仍然是更快的选择,特别是因为它使用线程BLAS,而不是在一个核心上运行的einsum

import perfplot
import numpy as np


def setup(n):
    k = n
    x = np.random.random((k, n))
    A = np.random.random((k, k))
    return x, A


def loop(data):
    x, A = data
    n = x.shape[1]
    out = np.empty(n)
    for i in range(n):
        out[i] = x[:, i].T.dot(A).dot(x[:, i])
    return out


def einsum(data):
    x, A = data
    return np.einsum('ji,jk,ki->i', x, A, x)


def dot(data):
    x, A = data
    return (x.T.dot(A)*x.T).sum(axis=1)


perfplot.show(
    setup=setup,
    kernels=[loop, einsum, dot],
    n_range=[2**k for k in range(10)],
    logx=True,
    logy=True,
    xlabel='n, k'
    )

答案 2 :(得分:0)

除非你将整个事物并行化,否则你不能更快地完成它:每列一个线程。你仍然会使用循环 - 你无法摆脱它。

Map reduce是一个很好的方法来查看这个问题:map步骤倍数,减少步长。