Джулия: функция eigs() возвращает не все собственные значения

#arrays #julia

#массивы #джулия

Вопрос:

Я использую функцию eigs() (из пакета Arpack), чтобы найти собственные значения разреженной матрицы (eigen () не работает для запасных матриц). По-видимому, eigs () не может найти все собственные значения, даже в очень простом случае:

 using Arpack
M = spdiagm(0 => [1,2,3])
eigs(M, nev = 3)
  

Вывод последней строки представляет собой вектор, содержащий только 2 собственных значения, «2» и «3» («1» отсутствует). Чего я не понимаю? Существует ли другая функция для вычисления собственных значений разреженной матрицы (фактическая разреженная матрица намного больше, чем указанное выше M).

Ответ №1:

На самом деле это отображается при предупреждении:

 julia> eigs(Matrix(M), nev = 3);
┌ Warning: Adjusting nev from 3 to 2
└ @ Arpack c:JuliaPkgJulia1.5.0packagesArpacko35I5srcArpack.jl:82
  

Глядя на исходный код, это может вернуть максимум LinearAlgebra.checksquare(M) - 1 значений.

Что вы могли бы попытаться сделать, так это использовать BandedMatrix вместо этого, который также является разреженным:

 julia> m=BandedMatrix(0=>1:3)
3×3 BandedMatrix{Int64,Array{Int64,2},Base.OneTo{Int64}}:
 1  ⋅  ⋅
 ⋅  2  ⋅
 ⋅  ⋅  3

julia> eigen(m)
Eigen{Float64,Float64,Array{Float64,2},Array{Float64,1}}
values:
3-element Array{Float64,1}:
 1.0
 2.0
 3.0
vectors:
3×3 Array{Float64,2}:
 1.0  0.0  0.0
 0.0  1.0  0.0
 0.0  0.0  1.0
  

Комментарии:

1. Спасибо! Поскольку фактическая матрица намного больше 3, и, как отметил Мейсон, мне не нужны все собственные значения (определенно не LinearAlgebra.checksquare(M)), eigs () подойдет просто отлично.

Ответ №2:

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

Сообщение об ошибке, которое вы получили eigen , немного неудачно. Желательно было бы также упомянуть, что если ваш массив небольшой, вы должны просто collect преобразовать его в плотную матрицу, например

 julia> using SparseArrays, LinearAlgebra

julia> M = spdiagm(0 => [1,2,3])
3×3 SparseMatrixCSC{Int64,Int64} with 3 stored entries:
  [1, 1]  =  1
  [2, 2]  =  2
  [3, 3]  =  3

julia> eigen(collect(M))
Eigen{Float64,Float64,Array{Float64,2},Array{Float64,1}}
values:
3-element Array{Float64,1}:
 1.0
 2.0
 3.0
vectors:
3×3 Array{Float64,2}:
 1.0  0.0  0.0
 0.0  1.0  0.0
 0.0  0.0  1.0
  

Если ваша матрица слишком велика, чтобы поместиться в памяти, и вы должны использовать разреженную матрицу, то я подозреваю, что вам не нужны все собственные значения.

Комментарии:

1. Спасибо. Ваше подозрение верно, мне действительно не нужны все собственные значения. Похоже, что это один из тех случаев, когда тестирование вашего кода на небольшом вводе не помогает.