Python中的对角矩阵指数

Python中的对角矩阵指数,python,matrix,numpy,scipy,exponential,Python,Matrix,Numpy,Scipy,Exponential,我在写一个考虑速度的数值算法。我在scipy/numpy中遇到了两个矩阵指数函数(scipy.linalg.expm2,scipy.linalg.expm)。然而,我有一个矩阵,我知道它是对角的。这些scipy函数在运行之前是否检查矩阵是否为对角线?显然,对于对角线矩阵,求幂算法可以快得多,我只是想确保它们在这方面做得很聪明-如果不是,有没有一种简单的方法呢?如果一个矩阵是对角线的,那么它的指数可以通过对主对角线上的每个条目求幂得到,因此,您可以通过以下公式进行计算: np.diag(np.ex

我在写一个考虑速度的数值算法。我在scipy/numpy中遇到了两个矩阵指数函数(scipy.linalg.expm2,scipy.linalg.expm)。然而,我有一个矩阵,我知道它是对角的。这些scipy函数在运行之前是否检查矩阵是否为对角线?显然,对于对角线矩阵,求幂算法可以快得多,我只是想确保它们在这方面做得很聪明-如果不是,有没有一种简单的方法呢?

如果一个矩阵是对角线的,那么它的指数可以通过对主对角线上的每个条目求幂得到,因此,您可以通过以下公式进行计算:

np.diag(np.exp(np.diag(a)))

如果您知道A是对角的,并且需要k次方:

def dpow(a, k):
    return np.diag(np.diag(a) ** k)
检查矩阵是否为对角矩阵:

def isdiag(a):
    return np.all(a == np.diag(np.diag(a)))
因此:

类似地,对于指数(可以从一组pow的展开式中获得),可以:

def dexp(a, k):
    return np.diag(np.exp(np.diag(a)))

def exp(a, k):
    if isdiag(a):
        return dexp(a, k)
    else:
        #use scipy.linalg.expm2 or whatever
d2 = np.ones_like(d); 
diagonal(d2)[:] = np.exp(np.diag(d))

print (d2==np.exp(d)).all()  # True

我已经开发了一个工具,可以帮助更快地执行与HYRY相同的操作,但通过就地执行

def diagonal(array):
    """ Return a **view** of the diagonal elements of 'array' """
    from numpy.lib.stride_tricks import as_strided
    return as_strided(array,shape=(min(array.shape),),strides=(sum(array.strides),))

# generate a random diagonal array
d  = np.diag(np.random.random(4000))

# in-place exponent of the diagonal elements
ddiag = diagonal(d)
ddiag[:] = np.exp(ddiag)

# timeit comparison with HYRY's method
%timeit -n10 np.diag(np.exp(np.diag(d)))   
    # out> 10 loops, best of 3: 52.1 ms per loop
%timeit -n10 ddiag = diagonal(d); ddiag[:] = np.exp(ddiag)
    # out> 10 loops, best of 3: 108 µs per loop
现在,

  • HYRY的方法是二次w.r.t对角线长度(可能是因为新的数组内存分配),因此如果矩阵的维数很小,差异可能不会那么大

  • 您需要对就地计算感到满意

  • 最后,非对角元素是0,所以它们的指数应该是1,不是吗?在我们的两种方法中,非对角线都是0

对于最后一部分,如果希望所有非对角元素都为1,则可以执行以下操作:

def dexp(a, k):
    return np.diag(np.exp(np.diag(a)))

def exp(a, k):
    if isdiag(a):
        return dexp(a, k)
    else:
        #use scipy.linalg.expm2 or whatever
d2 = np.ones_like(d); 
diagonal(d2)[:] = np.exp(np.diag(d))

print (d2==np.exp(d)).all()  # True
但这是线性的w.r.t到数组大小,所以二次的w.r.t到对角线长度。对于4000x4000阵列,时间为90毫秒;对于2000x2000阵列,时间为22.3毫秒

最后,您还可以在适当的位置执行此操作以获得一点速度:

diag = np.diag(d)
d[:]=1
diagonal(d)[:] = np.exp(diag)

Timeit为4000^2数组提供了66.1ms,为2000^2数组提供了16.8ms,我认为
scipy.sparse
对对角矩阵有一些特殊的支持(存储为只包含对角线的一维数组)。你的
isdiag
不起作用;或者,更确切地说,
如果isdiag(a)
不会,因为它返回一个布尔数组。您需要添加一个
.all()
。[我不知道是否有一种更有效的内置方法来测试矩阵是否为对角矩阵,但这不会让我感到惊讶。]如何得到“指数相同?”这不是一回事。。。我想要的是k^a(特别是e^a),而不是a^k。只是让我的答案更精确。难道没有更有效的方法来测试对角性吗?固定收益;你认为什么是对角性测试?非对角元素是不正确的。np.exp(0)应为1。这里是0,我想Doug想要的是矩阵的指数函数,而不是数组中每个元素的指数。对于对角矩阵,在对角线上恰好是相同的。