diff --git a/NEWS.md b/NEWS.md index fa94eee055a6d..f4b309e0d3d71 100644 --- a/NEWS.md +++ b/NEWS.md @@ -713,6 +713,21 @@ Deprecated or removed `lu!`, `schur!`, `lq!`, `qr!`, `ldlt!`, `svd!`, `bunchkaufman!`, `hessenberg!`, and `eigen!` ([#27159]). + * `eig(A[, args...])` has been deprecated in favor of `eigen(A[, args...])`. + Whereas the former returns a tuple of arrays, the latter returns an `Eigen` object. + So for a direct replacement, use `(eigen(A[, args...])...,)`. But going forward, + consider using the direct result of `eigen(A[, args...])` instead, either + destructured into its components (`vals, vecs = eigen(A[, args...])`) or + as an `Eigen` object (`X = eigen(A[, args...])`) ([#26997], [#27159], [#27212]). + + * `eig(A::AbstractMatrix, B::AbstractMatrix)` and `eig(A::Number, B::Number)` + have been deprecated in favor of `eigen(A, B)`. Whereas the former each return + a tuple of arrays, the latter returns a `GeneralizedEigen` object. So for a direct + replacement, use `(eigen(A, B)...,)`. But going forward, consider using the + direct result of `eigen(A, B)` instead, either destructured into its components + (`vals, vecs = eigen(A, B)`), or as a `GeneralizedEigen` object + (`X = eigen(A, B)`) ([#26997], [#27159], [#27212]). + * Indexing into multidimensional arrays with more than one index but fewer indices than there are dimensions is no longer permitted when those trailing dimensions have lengths greater than 1. Instead, reshape the array or add trailing indices so the dimensionality and number of indices diff --git a/stdlib/LinearAlgebra/docs/src/index.md b/stdlib/LinearAlgebra/docs/src/index.md index 3a988193d3d81..a78fdfa506e2e 100644 --- a/stdlib/LinearAlgebra/docs/src/index.md +++ b/stdlib/LinearAlgebra/docs/src/index.md @@ -198,7 +198,7 @@ Legend: ### Matrix factorizations -| Matrix type | LAPACK | [`eig`](@ref) | [`eigvals`](@ref) | [`eigvecs`](@ref) | [`svd`](@ref) | [`svdvals`](@ref) | +| Matrix type | LAPACK | [`eigen`](@ref) | [`eigvals`](@ref) | [`eigvecs`](@ref) | [`svd`](@ref) | [`svdvals`](@ref) | |:------------------------- |:------ |:------------- |:----------------- |:----------------- |:------------- |:----------------- | | [`Symmetric`](@ref) | SY | | ARI | | | | | [`Hermitian`](@ref) | HE | | ARI | | | | @@ -331,7 +331,6 @@ LinearAlgebra.lq! LinearAlgebra.lq LinearAlgebra.bunchkaufman LinearAlgebra.bunchkaufman! -LinearAlgebra.eig LinearAlgebra.eigvals LinearAlgebra.eigvals! LinearAlgebra.eigmax diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 3519202b8c428..3442861f3fc8c 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -80,7 +80,6 @@ export diagind, diagm, dot, - eig, eigen, eigen!, eigmax, diff --git a/stdlib/LinearAlgebra/src/deprecated.jl b/stdlib/LinearAlgebra/src/deprecated.jl index e59db95719f7c..bbe481cbf306b 100644 --- a/stdlib/LinearAlgebra/src/deprecated.jl +++ b/stdlib/LinearAlgebra/src/deprecated.jl @@ -1410,3 +1410,44 @@ export eigfact! @deprecate(cholfact!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}, ::Val{true}; tol = 0.0), cholesky!(A, Val(true); tol=tol)) @deprecate(cholfact!(A::RealHermSymComplexHerm{<:Real}, ::Val{true}; tol = 0.0), cholesky!(A, Val(true); tol=tol)) @deprecate(cholfact!(A::StridedMatrix, ::Val{true}; tol = 0.0), cholesky!(A, Val(true); tol=tol)) + +# deprecate eig in favor of eigen and destructuring via iteration +# deprecate eig(...) in favor of eigfact and factorization destructuring +export eig +function eig(A::Union{Number, StridedMatrix}; permute::Bool=true, scale::Bool=true) + depwarn(string("`eig(A[, permute, scale])` has been deprecated in favor of ", + "`eigen(A[, permute, scale])`. Whereas `eig(A[, permute, scale])` ", + "returns a tuple of arrays, `eigen(A[, permute, scale])` returns ", + "an `Eigen` object. So for a direct replacement, use ", + "`(eigen(A[, permute, scale])...,)`. But going forward, consider ", + "using the direct result of `eigen(A[, permute, scale])` instead, ", + "either destructured into its components ", + "(`vals, vecs = eigen(A[, permute, scale])`) ", + "or as an `Eigen` object (`X = eigen(A[, permute, scale])`)."), :eig) + return (eigen(A; permute=permute, scale=scale)...,) +end +function eig(A::AbstractMatrix, args...) + depwarn(string("`eig(A, args...)` has been deprecated in favor of ", + "`eigen(A, args...)`. Whereas `eig(A, args....)` ", + "returns a tuple of arrays, `eigen(A, args...)` returns ", + "an `Eigen` object. So for a direct replacement, use ", + "`(eigen(A, args...)...,)`. But going forward, consider ", + "using the direct result of `eigen(A, args...)` instead, ", + "either destructured into its components ", + "(`vals, vecs = eigen(A, args...)`) ", + "or as an `Eigen` object (`X = eigen(A, args...)`)."), :eig) + return (eigen(A, args...)...,) +end +eig(A::AbstractMatrix, B::AbstractMatrix) = _geneig(A, B) +eig(A::Number, B::Number) = _geneig(A, B) +function _geneig(A, B) + depwarn(string("`eig(A::AbstractMatrix, B::AbstractMatrix)` and ", + "`eig(A::Number, B::Number)` have been deprecated in favor of ", + "`eigen(A, B)`. Whereas the former each return a tuple of arrays, ", + "the latter returns a `GeneralizedEigen` object. So for a direct ", + "replacement, use `(eigen(A, B)...,)`. But going forward, consider ", + "using the direct result of `eigen(A, B)` instead, either ", + "destructured into its components (`vals, vecs = eigen(A, B)`), ", + "or as a `GeneralizedEigen` object (`X = eigen(A, B)`)."), :eig) + return (eigen(A, B)...,) +end diff --git a/stdlib/LinearAlgebra/src/eigen.jl b/stdlib/LinearAlgebra/src/eigen.jl index d63c79ed90c43..af40aa2082f92 100644 --- a/stdlib/LinearAlgebra/src/eigen.jl +++ b/stdlib/LinearAlgebra/src/eigen.jl @@ -126,38 +126,6 @@ function eigen(A::StridedMatrix{T}; permute::Bool=true, scale::Bool=true) where end eigen(x::Number) = Eigen([x], fill(one(x), 1, 1)) -function eig(A::Union{Number, StridedMatrix}; permute::Bool=true, scale::Bool=true) - F = eigen(A, permute=permute, scale=scale) - F.values, F.vectors -end - -""" - eig(A::Union{SymTridiagonal, Hermitian, Symmetric}, irange::UnitRange) -> D, V - eig(A::Union{SymTridiagonal, Hermitian, Symmetric}, vl::Real, vu::Real) -> D, V - eig(A, permute::Bool=true, scale::Bool=true) -> D, V - -Computes eigenvalues (`D`) and eigenvectors (`V`) of `A`. -See [`eigen`](@ref) for details on the -`irange`, `vl`, and `vu` arguments -(for [`SymTridiagonal`](@ref), [`Hermitian`](@ref), and -[`Symmetric`](@ref) matrices) -and the `permute` and `scale` keyword arguments. -The eigenvectors are returned columnwise. - -# Examples -```jldoctest -julia> eig([1.0 0.0 0.0; 0.0 3.0 0.0; 0.0 0.0 18.0]) -([1.0, 3.0, 18.0], [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]) -``` - -`eig` is a wrapper around [`eigen`](@ref), extracting all parts of the -factorization to a tuple; where possible, using [`eigen`](@ref) is recommended. -""" -function eig(A::AbstractMatrix, args...) - F = eigen(A, args...) - F.values, F.vectors -end - """ eigvecs(A; permute::Bool=true, scale::Bool=true) -> Matrix @@ -416,39 +384,6 @@ end eigen(A::Number, B::Number) = eigen(fill(A,1,1), fill(B,1,1)) -""" - eig(A, B) -> D, V - -Computes generalized eigenvalues (`D`) and vectors (`V`) of `A` with respect to `B`. - -`eig` is a wrapper around [`eigen`](@ref), extracting all parts of the -factorization to a tuple; where possible, using [`eigen`](@ref) is recommended. - -# Examples -```jldoctest -julia> A = [1 0; 0 -1] -2×2 Array{Int64,2}: - 1 0 - 0 -1 - -julia> B = [0 1; 1 0] -2×2 Array{Int64,2}: - 0 1 - 1 0 - -julia> eig(A, B) -(Complex{Float64}[0.0+1.0im, 0.0-1.0im], Complex{Float64}[0.0-1.0im 0.0+1.0im; -1.0-0.0im -1.0+0.0im]) -``` -""" -function eig(A::AbstractMatrix, B::AbstractMatrix) - F = eigen(A,B) - F.values, F.vectors -end -function eig(A::Number, B::Number) - F = eigen(A,B) - F.values, F.vectors -end - """ eigvals!(A, B) -> values diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 9b0755cb2626d..874d8f233747f 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -2156,7 +2156,7 @@ function log(A0::UpperTriangular{T}) where T<:BlasFloat R[i,i+1] = i / sqrt((2 * i)^2 - 1) R[i+1,i] = R[i,i+1] end - x,V = eig(R) + x,V = eigen(R) w = Vector{Float64}(undef, m) for i = 1:m x[i] = (x[i] + 1) / 2 diff --git a/stdlib/LinearAlgebra/test/bidiag.jl b/stdlib/LinearAlgebra/test/bidiag.jl index 1f4fa2d41b637..efbf5d3e437eb 100644 --- a/stdlib/LinearAlgebra/test/bidiag.jl +++ b/stdlib/LinearAlgebra/test/bidiag.jl @@ -231,8 +231,8 @@ srand(1) @testset "Eigensystems" begin if relty <: AbstractFloat - d1, v1 = eig(T) - d2, v2 = eig(map(elty<:Complex ? ComplexF64 : Float64,Tfull)) + d1, v1 = eigen(T) + d2, v2 = eigen(map(elty<:Complex ? ComplexF64 : Float64,Tfull)) @test (uplo == :U ? d1 : reverse(d1)) ≈ d2 if elty <: Real test_approx_eq_modphase(v1, uplo == :U ? v2 : v2[:,n:-1:1]) diff --git a/stdlib/LinearAlgebra/test/eigen.jl b/stdlib/LinearAlgebra/test/eigen.jl index c4e3c087e4b3d..7862ae8d78822 100644 --- a/stdlib/LinearAlgebra/test/eigen.jl +++ b/stdlib/LinearAlgebra/test/eigen.jl @@ -28,12 +28,12 @@ aimg = randn(n,n)/2 α = rand(eltya) β = rand(eltya) - eab = eig(α,β) - @test eab[1] == eigvals(fill(α,1,1),fill(β,1,1)) - @test eab[2] == eigvecs(fill(α,1,1),fill(β,1,1)) + eab = eigen(α,β) + @test eab.values == eigvals(fill(α,1,1),fill(β,1,1)) + @test eab.vectors == eigvecs(fill(α,1,1),fill(β,1,1)) @testset "non-symmetric eigen decomposition" begin - d, v = eig(a) + d, v = eigen(a) for i in 1:size(a,2) @test a*v[:,i] ≈ d[i]*v[:,i] end @@ -70,7 +70,7 @@ aimg = randn(n,n)/2 @test eigvecs(f) === f.vectors @test_throws ErrorException f.Z - d,v = eig(asym_sg, a_sg'a_sg) + d,v = eigen(asym_sg, a_sg'a_sg) @test d == f.values @test v == f.vectors end @@ -89,7 +89,7 @@ aimg = randn(n,n)/2 @test eigvecs(a1_nsg, a2_nsg) == f.vectors @test_throws ErrorException f.Z - d,v = eig(a1_nsg, a2_nsg) + d,v = eigen(a1_nsg, a2_nsg) @test d == f.values @test v == f.vectors end @@ -98,11 +98,11 @@ end @testset "eigenvalue computations with NaNs" begin for eltya in (NaN16, NaN32, NaN) - @test_throws(ArgumentError, eig(fill(eltya, 1, 1))) - @test_throws(ArgumentError, eig(fill(eltya, 2, 2))) + @test_throws(ArgumentError, eigen(fill(eltya, 1, 1))) + @test_throws(ArgumentError, eigen(fill(eltya, 2, 2))) test_matrix = rand(typeof(eltya),3,3) test_matrix[2,2] = eltya - @test_throws(ArgumentError, eig(test_matrix)) + @test_throws(ArgumentError, eigen(test_matrix)) end end diff --git a/stdlib/LinearAlgebra/test/lu.jl b/stdlib/LinearAlgebra/test/lu.jl index 4b4353f6e4d36..8bcfbe3e41046 100644 --- a/stdlib/LinearAlgebra/test/lu.jl +++ b/stdlib/LinearAlgebra/test/lu.jl @@ -51,7 +51,6 @@ dimg = randn(n)/2 -eps(real(one(eltya)))/4 eps(real(one(eltya)))/2 -1.0 0; -0.5 -0.5 0.1 1.0]) F = eigen(A, permute=false, scale=false) - eig(A, permute=false, scale=false) @test F.vectors*Diagonal(F.values)/F.vectors ≈ A F = eigen(A) # @test norm(F.vectors*Diagonal(F.values)/F.vectors - A) > 0.01 diff --git a/stdlib/LinearAlgebra/test/schur.jl b/stdlib/LinearAlgebra/test/schur.jl index 6299e9da71a1d..e5d1efb868321 100644 --- a/stdlib/LinearAlgebra/test/schur.jl +++ b/stdlib/LinearAlgebra/test/schur.jl @@ -26,7 +26,7 @@ aimg = randn(n,n)/2 view(apd, 1:n, 1:n))) ε = εa = eps(abs(float(one(eltya)))) - d,v = eig(a) + d,v = eigen(a) f = schur(a) @test f.vectors*f.Schur*f.vectors' ≈ a @test sort(real(f.values)) ≈ sort(real(d)) diff --git a/stdlib/LinearAlgebra/test/symmetric.jl b/stdlib/LinearAlgebra/test/symmetric.jl index 54172dfcb2af7..54cf0ee6c74b1 100644 --- a/stdlib/LinearAlgebra/test/symmetric.jl +++ b/stdlib/LinearAlgebra/test/symmetric.jl @@ -218,14 +218,12 @@ end @testset "symmetric eigendecomposition" begin if eltya <: Real # the eigenvalues are only real and ordered for Hermitian matrices - d, v = eig(asym) + d, v = eigen(asym) @test asym*v[:,1] ≈ d[1]*v[:,1] @test v*Diagonal(d)*transpose(v) ≈ asym @test isequal(eigvals(asym[1]), eigvals(asym[1:1,1:1])) @test abs.(eigen(Symmetric(asym), 1:2).vectors'v[:,1:2]) ≈ Matrix(I, 2, 2) - eig(Symmetric(asym), 1:2) # same result, but checks that method works @test abs.(eigen(Symmetric(asym), d[1] - 1, (d[2] + d[3])/2).vectors'v[:,1:2]) ≈ Matrix(I, 2, 2) - eig(Symmetric(asym), d[1] - 1, (d[2] + d[3])/2) # same result, but checks that method works @test eigvals(Symmetric(asym), 1:2) ≈ d[1:2] @test eigvals(Symmetric(asym), d[1] - 1, (d[2] + d[3])/2) ≈ d[1:2] # eigen doesn't support Symmetric{Complex} @@ -233,14 +231,12 @@ end @test eigvecs(Symmetric(asym)) ≈ eigvecs(asym) end - d, v = eig(aherm) + d, v = eigen(aherm) @test aherm*v[:,1] ≈ d[1]*v[:,1] @test v*Diagonal(d)*v' ≈ aherm @test isequal(eigvals(aherm[1]), eigvals(aherm[1:1,1:1])) @test abs.(eigen(Hermitian(aherm), 1:2).vectors'v[:,1:2]) ≈ Matrix(I, 2, 2) - eig(Hermitian(aherm), 1:2) # same result, but checks that method works @test abs.(eigen(Hermitian(aherm), d[1] - 1, (d[2] + d[3])/2).vectors'v[:,1:2]) ≈ Matrix(I, 2, 2) - eig(Hermitian(aherm), d[1] - 1, (d[2] + d[3])/2) # same result, but checks that method works @test eigvals(Hermitian(aherm), 1:2) ≈ d[1:2] @test eigvals(Hermitian(aherm), d[1] - 1, (d[2] + d[3])/2) ≈ d[1:2] @test Matrix(eigen(aherm)) ≈ aherm @@ -365,7 +361,7 @@ end end @testset "Issues #8057 and #8058. f=$f, A=$A" for f in - (eigen, eigvals, eig), + (eigen, eigvals), A in (Symmetric([0 1; 1 0]), Hermitian([0 im; -im 0])) @test_throws ArgumentError f(A, 3, 2) @test_throws ArgumentError f(A, 1:4) diff --git a/stdlib/LinearAlgebra/test/triangular.jl b/stdlib/LinearAlgebra/test/triangular.jl index 0043176673605..89ad49d70329d 100644 --- a/stdlib/LinearAlgebra/test/triangular.jl +++ b/stdlib/LinearAlgebra/test/triangular.jl @@ -249,7 +249,7 @@ for elty1 in (Float32, Float64, BigFloat, ComplexF32, ComplexF64, Complex{BigFlo # eigenproblems if !(elty1 in (BigFloat, Complex{BigFloat})) # Not handled yet - vals, vecs = eig(A1) + vals, vecs = eigen(A1) if (t1 == UpperTriangular || t1 == LowerTriangular) && elty1 != Int # Cannot really handle degenerate eigen space and Int matrices will probably have repeated eigenvalues. @test vecs*diagm(0 => vals)/vecs ≈ A1 atol=sqrt(eps(float(real(one(vals[1])))))*(norm(A1,Inf)*n)^2 end diff --git a/stdlib/LinearAlgebra/test/tridiag.jl b/stdlib/LinearAlgebra/test/tridiag.jl index 903d09a02d27f..0573db496d2de 100644 --- a/stdlib/LinearAlgebra/test/tridiag.jl +++ b/stdlib/LinearAlgebra/test/tridiag.jl @@ -243,7 +243,7 @@ end w, iblock, isplit = LAPACK.stebz!('V', 'B', -infinity, infinity, 0, 0, zero, b, a) evecs = LAPACK.stein!(b, a, w) - (e, v) = eig(SymTridiagonal(b, a)) + (e, v) = eigen(SymTridiagonal(b, a)) @test e ≈ w test_approx_eq_vecs(v, evecs) end @@ -266,10 +266,10 @@ end end @testset "eigenvalues/eigenvectors of symmetric tridiagonal" begin if elty === Float32 || elty === Float64 - DT, VT = @inferred eig(A) - @inferred eig(A, 2:4) - @inferred eig(A, 1.0, 2.0) - D, Vecs = eig(fA) + DT, VT = @inferred eigen(A) + @inferred eigen(A, 2:4) + @inferred eigen(A, 1.0, 2.0) + D, Vecs = eigen(fA) @test DT ≈ D @test abs.(VT'Vecs) ≈ Matrix(elty(1)I, n, n) test_approx_eq_modphase(eigvecs(A), eigvecs(fA)) diff --git a/stdlib/SparseArrays/src/linalg.jl b/stdlib/SparseArrays/src/linalg.jl index 36dba2f9c8061..170232f7a463c 100644 --- a/stdlib/SparseArrays/src/linalg.jl +++ b/stdlib/SparseArrays/src/linalg.jl @@ -1009,7 +1009,7 @@ function factorize(A::LinearAlgebra.RealHermSymComplexHerm{Float64,<:SparseMatri end chol(A::SparseMatrixCSC) = error("Use cholesky() instead of chol() for sparse matrices.") -eig(A::SparseMatrixCSC) = error("Use IterativeEigensolvers.eigs() instead of eig() for sparse matrices.") +eigen(A::SparseMatrixCSC) = error("Use IterativeEigensolvers.eigs() instead of eigen() for sparse matrices.") function Base.cov(X::SparseMatrixCSC; dims::Int=1, corrected::Bool=true) vardim = dims diff --git a/stdlib/SparseArrays/test/sparse.jl b/stdlib/SparseArrays/test/sparse.jl index f55f90497fba4..fcface7889ab4 100644 --- a/stdlib/SparseArrays/test/sparse.jl +++ b/stdlib/SparseArrays/test/sparse.jl @@ -1780,7 +1780,7 @@ end C, b = A[:, 1:4], fill(1., size(A, 1)) @test !Base.USE_GPL_LIBS || factorize(C)\b ≈ Array(C)\b @test_throws ErrorException chol(A) - @test_throws ErrorException eig(A) + @test_throws ErrorException eigen(A) @test_throws ErrorException inv(A) end