как работает numpy.linalg.eigh против numpy.linalg.svd? - PullRequest
0 голосов
/ 15 мая 2018

описание проблемы

Для квадратной матрицы можно получить SVD

X= USV'

разложение, используя просто numpy.linalg.svd

u,s,vh = numpy.linalg.svd(X)     

рутина или numpy.linalg.eigh , для вычисления разложения eig на эрмитовой матрице X'X и XX '

Они используют один и тот же алгоритм? Вызываете ту же рутину Лапака?

Есть ли разница в скорости? а стабильность?

Ответы [ 2 ]

0 голосов
/ 17 мая 2018

Действительно, numpy.linalg.svd и numpy.linalg.eigh не вызывают одну и ту же процедуру Лапака.С одной стороны, numpy.linalg.eigh относится к LAPACK dsyevd(), в то время как numpy.linalg.svd использует LAPACK dgesdd().

Общей точкой между этими подпрограммами является использование алгоритма «разделяй и властвуй» Куппена, впервые разработанного для решения трехдиагональных задач на собственные значения.Например, dsyevd() обрабатывает только эрмитову матрицу и выполняет следующие шаги, только если требуются собственные векторы:

  1. Преобразование матрицы в трехдиагональную форму с помощью DSYTRD ()

  2. Вычислить собственные векторы трехдиагональной матрицы с использованием алгоритма «разделяй и властвуй» с помощью DSTEDC ()

  3. Применить отражение Домохозяина, о котором сообщает DSYTRD ()используя DORMTR ().

Напротив, для вычисления SVD dgesdd() выполняет следующие шаги, в случае задания == A (требуются U и VT):

  1. Бидиагонализация A с использованием dgebrd()
  2. Вычисление SVD бидиагональной матрицы с использованием алгоритма «разделяй и властвуй» с использованием DBDSDC()
  3. Отмена бидиагонализации с использованием матриц Pи Q возвращается dgebrd(), применяя dormbr() дважды, один раз для U и один раз для V.

В то время как фактические операции, предусмотренные LAPACK, очень разные, стратегии во всем мире схожи.Это может быть обусловлено тем фактом, что вычисление SVD общей матрицы A аналогично выполнению собственного разложения симметричной матрицы A ^ TA

Относительно точности и характеристик разрыва и захвата SVD Лапака см. Thisобзор методов SVD :

  • Они часто достигают точности SVD на основе QR, хотя это не доказано.
  • Худший случай - O (n ^ 3)если не происходит дефляция, но часто оказывается лучше, чем это.
  • Требуемый объем памяти в 8 раз превышает размер матрицы, что может стать непомерно большим.

Что касается симметричной проблемы собственных значений, сложность составляет 4 / 3n ^ 3 (но часто доказываетлучше, чем это), и объем памяти составляет около 2n ^ 2 плюс размер матрицы.Следовательно, лучший выбор вероятен numpy.linalg.eigh, если ваша матрица симметрична.

Фактическая сложность может быть вычислена для ваших конкретных матриц с использованием следующего кода:

import numpy as np
from matplotlib import pyplot as plt
from scipy.optimize import curve_fit

# see https://stackoverflow.com/questions/41109122/fitting-a-curve-to-a-power-law-distribution-with-curve-fit-does-not-work
def func_powerlaw(x, m, c):
    return np.log(np.abs( x**m * c))

import time

start = time.time()
print("hello")
end = time.time()
print(end - start)

timeev=[]
timesvd=[]
size=[]

for n in range(10,600):
    print n
    size.append(n)
    A=np.zeros((n,n))
    #populate A, 1D diffusion. 
    for j in range(n):
        A[j,j]=2.
        if j>0:
            A[j-1,j]=-1.
        if j<n-1:
            A[j+1,j]=-1.

    #EIG
    Aev=A.copy()
    start = time.time()
    w,v=np.linalg.eigh(Aev,'L')
    end = time.time()
    timeev.append(end-start)
    Asvd=A.copy()
    start = time.time()
    u,s,vh=np.linalg.svd(Asvd)
    end = time.time()
    timesvd.append(end-start)


poptev, pcov = curve_fit(func_powerlaw, size[len(size)/2:], np.log(timeev[len(size)/2:]),p0=[2.1,1e-7],maxfev = 8000)
print poptev

poptsvd, pcov = curve_fit(func_powerlaw, size[len(size)/2:], np.log(timesvd[len(size)/2:]),p0=[2.1,1e-7],maxfev = 8000)
print poptsvd

plt.figure()

fig, ax = plt.subplots()

plt.plot(size,timeev,label="eigh")
plt.plot(size,[np.exp(func_powerlaw(x, poptev[0], poptev[1])) for x in size],label="eigh-adjusted complexity: "+str(poptev[0]))

plt.plot(size,timesvd,label="svd")
plt.plot(size,[np.exp(func_powerlaw(x, poptsvd[0], poptsvd[1])) for x in size],label="svd-adjusted complexity: "+str(poptsvd[0]))


ax.set_xlabel('n')
ax.set_ylabel('time, s')

#plt.legend(loc="upper left")

ax.legend(loc="lower right")
ax.set_yscale("log", nonposy='clip')

fig.tight_layout()



plt.savefig('eigh.jpg')
plt.show()

Для таких одномерных диффузионных матриц восемь опережают SVD, но фактическая сложность аналогична, чуть ниже, чем n ^ 3, что-то вроде n ^ 2.5.,enter image description here

Также можно выполнить проверку точности.

0 голосов
/ 16 мая 2018

Нет, они не используют один и тот же алгоритм, поскольку они делают разные вещи. Они несколько связаны, но также очень разные. Начнем с того, что вы можете делать SVD на m x n матрицах, где m и n не обязательно должны быть одинаковыми.

В зависимости от версии numpy, вы делаете. Вот процедуры на собственные значения в лапаке для двойной точности:
http://www.netlib.org/lapack/explore-html/d9/d8e/group__double_g_eeigen.html
И соответствующие процедуры SVD:
http://www.netlib.org/lapack/explore-html/d1/d7e/group__double_g_esing.html

Есть различия в процедурах. Большие различия Если вы заботитесь о деталях, они очень хорошо указаны в заголовках Фортрана. Во многих случаях имеет смысл выяснить, какую матрицу вы имеете перед собой, чтобы сделать правильный выбор рутины. Является ли матрица симметричной / эрмитовой? Это в верхней диагональной форме? Это положительный полуопределенный? ...

Существуют большие различия во времени выполнения. Но, как правило, EIG дешевле, чем SVD. Но это зависит также от скорости сходимости, которая, в свою очередь, во многом зависит от номера условия матрицы, другими словами, от того, насколько некорректна матрица, ...

SVD, как правило, являются очень надежными и медленными алгоритмами и часто используются для инверсии, оптимизации скорости с помощью усечения, анализа основных компонентов на самом деле с ожиданием того, что матрица, с которой вы имеете дело, представляет собой просто кучу дерьмовых строк;)

...