Skip to content

Commit

Permalink
Deprecate svd(...) in favor of svdfact(...) and factorization destruc…
Browse files Browse the repository at this point in the history
…turing.
  • Loading branch information
Sacha0 committed May 15, 2018
1 parent 3c94a27 commit 8fedd69
Show file tree
Hide file tree
Showing 17 changed files with 176 additions and 132 deletions.
40 changes: 40 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1040,6 +1040,46 @@ Deprecated or removed
(`S, T, Q, Z, α, β = schurfact(A, B)`) or as a `GeneralizedSchur` object
(`schurf = schurfact(A, B)`) ([#26997]).

* `svd(A::Abstractarray; thin=true)` has been deprecated in favor of
`svdfact(A; full=false)`. Note that the `thin` keyword and its replacement
`full` have opposite meanings. Additionally, whereas `svd` returns a
tuple of arrays `(U, S, V)` such that `A ≈ U*Diagonal(S)*V'`, `svdfact` returns
an `SVD` object that nominally provides `U, S, Vt` such that `A ≈ U*Diagonal(S)*Vt`.
So for a direct replacement,
use `(U, S, Vt = svdfact(A[; full=...]); (U, S, copy(Vt')))`. But going forward,
consider using the direct result of `svdfact(A[; full=...])` instead,
either destructured into its components (`U, S, Vt = svdfact(A[; full=...])`)
or as an `SVD` object (`svdf = svdfact(A[; full=...])`) ([#26997]).

* `svd(x::Number; thin=true)` has been deprecated in favor of
`svdfact(x; full=false)`. Note that the `thin` keyword and its replacement
`full` have opposite meanings. Additionally, whereas `svd(x::Number[; thin=...])`
returns a tuple of numbers `(u, s, v)` such that `x ≈ u*s*conj(v)`,
`svdfact(x::Number[; full=...])` returns
an `SVD` object that nominally provides `u, s, vt` such that `x ≈ u*Diagonal(s)*conj(vt)`.
So for a direct replacement,
use `(u, s, vt = first.((svdfact(x[; full=...]...,)); (u, s, conj(vt)))`.
But going forward,
consider using the direct result of `svdfact(x[; full=...])` instead,
either destructured into its components (`U, S, Vt = svdfact(A[; full=...])`)
or as an `SVD` object (`svdf = svdfact(x[; full=...])`) ([#26997]).

* `svd(A::Abstractarray, B::AbstractArray)` has been deprecated in favor of
`svdfact(A, B)`. Whereas the former returns a tuple of arrays,
the latter returns a `GeneralizedSVD` object. So for a direct replacement,
use `(svdfact(A, B)...,)`. But going forward,
consider using the direct result of `svdfact(A, B)` instead,
either destructured into its components (`U, V, Q, D1, D2, R0 = svdfact(A, B)`)
or as a `GeneralizedSVD` object (`gsvdf = svdfact(A, B)`) ([#26997]).

* `svd(x::Number, y::Number)` has been deprecated in favor of
`svdfact(x, y)`. Whereas the former returns a tuple of numbers,
the latter returns a `GeneralizedSVD` object. So for a direct replacement,
use `first.((svdfact(x, y)...,))`. But going forward,
consider using the direct result of `svdfact(x, ys)` instead,
either destructured into its components (`U, V, Q, D1, D2, R0 = svdfact(x, y)`)
or as a `GeneralizedSVD` object (`gsvdf = svdfact(x, y)`) ([#26997]).

* The timing functions `tic`, `toc`, and `toq` are deprecated in favor of `@time` and `@elapsed`
([#17046]).

Expand Down
2 changes: 1 addition & 1 deletion doc/src/manual/noteworthy-differences.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ may trip up Julia users accustomed to MATLAB:
parentheses may be required (e.g., to select elements of `A` equal to 1 or 2 use `(A .== 1) .| (A .== 2)`).
* In Julia, the elements of a collection can be passed as arguments to a function using the splat
operator `...`, as in `xs=[1,2]; f(xs...)`.
* Julia's [`svd`](@ref) returns singular values as a vector instead of as a dense diagonal matrix.
* Julia's [`svdfact`](@ref) returns singular values as a vector instead of as a dense diagonal matrix.
* In Julia, `...` is not used to continue lines of code. Instead, incomplete expressions automatically
continue onto the next line.
* In both Julia and MATLAB, the variable `ans` is set to the value of the last expression issued
Expand Down
4 changes: 2 additions & 2 deletions doc/src/manual/parallel-computing.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ we could compute the singular values of several large random matrices in paralle
```julia-repl
julia> M = Matrix{Float64}[rand(1000,1000) for i = 1:10];
julia> pmap(svd, M);
julia> pmap(svdvals, M);
```

Julia's [`pmap`](@ref) is designed for the case where each function call does a large amount
Expand Down Expand Up @@ -486,7 +486,7 @@ As an example, consider computing the singular values of matrices of different s
```julia-repl
julia> M = Matrix{Float64}[rand(800,800), rand(600,600), rand(800,800), rand(600,600)];
julia> pmap(svd, M);
julia> pmap(svdvals, M);
```

If one process handles both 800×800 matrices and another handles both 600×600 matrices, we will
Expand Down
4 changes: 2 additions & 2 deletions doc/src/manual/performance-tips.md
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ function norm(A)
if isa(A, Vector)
return sqrt(real(dot(A,A)))
elseif isa(A, Matrix)
return maximum(svd(A)[2])
return maximum(svdvals(A))
else
error("norm: invalid argument")
end
Expand All @@ -555,7 +555,7 @@ This can be written more concisely and efficiently as:

```julia
norm(x::Vector) = sqrt(real(dot(x,x)))
norm(A::Matrix) = maximum(svd(A)[2])
norm(A::Matrix) = maximum(svdvals(A))
```

## Write "type-stable" functions
Expand Down
4 changes: 2 additions & 2 deletions stdlib/IterativeEigensolvers/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ end
@testset "real svds" begin
A = sparse([1, 1, 2, 3, 4], [2, 1, 1, 3, 1], [2.0, -1.0, 6.1, 7.0, 1.5])
S1 = svds(A, nsv = 2)
S2 = svd(Array(A))
S2 = (F = svdfact(Array(A)); (F.U, F.S, F.V))

## singular values match:
@test S1[1].S S2[2][1:2]
Expand Down Expand Up @@ -248,7 +248,7 @@ end
@testset "complex svds" begin
A = sparse([1, 1, 2, 3, 4], [2, 1, 1, 3, 1], exp.(im*[2.0:2:10;]), 5, 4)
S1 = svds(A, nsv = 2)
S2 = svd(Array(A))
S2 = (F = svdfact(Array(A)); (F.U, F.S, F.V))

## singular values match:
@test S1[1].S S2[2][1:2]
Expand Down
21 changes: 10 additions & 11 deletions stdlib/LinearAlgebra/docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,16 +198,16 @@ Legend:

### Matrix factorizations

| Matrix type | LAPACK | [`eigfact`](@ref) | [`eigvals`](@ref) | [`eigvecs`](@ref) | [`svd`](@ref) | [`svdvals`](@ref) |
|:------------------------- |:------ |:----------------- |:----------------- |:----------------- |:------------- |:----------------- |
| [`Symmetric`](@ref) | SY | | ARI | | | |
| [`Hermitian`](@ref) | HE | | ARI | | | |
| [`UpperTriangular`](@ref) | TR | A | A | A | | |
| [`LowerTriangular`](@ref) | TR | A | A | A | | |
| [`SymTridiagonal`](@ref) | ST | A | ARI | AV | | |
| [`Tridiagonal`](@ref) | GT | | | | | |
| [`Bidiagonal`](@ref) | BD | | | | A | A |
| [`Diagonal`](@ref) | DI | | A | | | |
| Matrix type | LAPACK | [`eigfact`](@ref) | [`eigvals`](@ref) | [`eigvecs`](@ref) | [`svdfact`](@ref) | [`svdvals`](@ref) |
|:------------------------- |:------ |:----------------- |:----------------- |:----------------- |:----------------- |:----------------- |
| [`Symmetric`](@ref) | SY | | ARI | | | |
| [`Hermitian`](@ref) | HE | | ARI | | | |
| [`UpperTriangular`](@ref) | TR | A | A | A | | |
| [`LowerTriangular`](@ref) | TR | A | A | A | | |
| [`SymTridiagonal`](@ref) | ST | A | ARI | AV | | |
| [`Tridiagonal`](@ref) | GT | | | | | |
| [`Bidiagonal`](@ref) | BD | | | | A | A |
| [`Diagonal`](@ref) | DI | | A | | | |

Legend:

Expand Down Expand Up @@ -349,7 +349,6 @@ LinearAlgebra.ordschur
LinearAlgebra.ordschur!
LinearAlgebra.svdfact
LinearAlgebra.svdfact!
LinearAlgebra.svd
LinearAlgebra.svdvals
LinearAlgebra.svdvals!
LinearAlgebra.Givens
Expand Down
1 change: 0 additions & 1 deletion stdlib/LinearAlgebra/src/LinearAlgebra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ export
rdiv!,
schurfact!,
schurfact,
svd,
svdfact!,
svdfact,
svdvals!,
Expand Down
2 changes: 1 addition & 1 deletion stdlib/LinearAlgebra/src/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ end

## norm and rank

svd(A::BitMatrix) = svd(float(A))
svdfact(A::BitMatrix) = svdfact(float(A))
qr(A::BitMatrix) = qr(float(A))

## kron
Expand Down
73 changes: 73 additions & 0 deletions stdlib/LinearAlgebra/src/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1345,3 +1345,76 @@ function schur(A::StridedMatrix, B::StridedMatrix)
" or as a `GeneralizedSchur` object (`schurf = schurfact(A, B)`)."), :schur)
return (schurfact(A, B)...,)
end

# deprecate svd(...) in favor of svdfact(...) and factorization destructuring
export svd
function svd(A::AbstractArray; full::Bool = false, thin::Union{Bool,Nothing} = nothing)
depwarn(string("`svd(A::Abstractarray; thin=true)` has been deprecated ",
"in favor of `svdfact(A; full=false)`. Note that the `thin` keyword ",
"and its replacement `full` have opposite meanings. Additionally, whereas ",
"`svd` returns a tuple of arrays `(U, S, V)` such that `A ≈ U*Diagonal(S)*V'`, ",
"`svdfact` returns an `SVD` object that nominally provides `U, S, Vt` ",
"such that `A ≈ U*Diagonal(S)*Vt`. So for a direct replacement, use ",
"`(U, S, Vt = svdfact(A[; full=...]); (U, S, copy(Vt')))`. But going forward, ",
"consider using the direct result of `svdfact(A[; full=...])` instead, ",
"either destructured into its components (`U, S, Vt = svdfact(A[; full=...])`) ",
"or as an `SVD` object (`svdf = svdfact(A[; full=...])`)."), :svd)
F = svdfact(A, full = (thin != nothing ? !thin : full))
return F.U, F.S, copy(F.Vt')
end
function svd(x::Number; full::Bool = false, thin::Union{Bool,Nothing} = nothing)
depwarn(string("`svd(x::Number; thin=true)` has been deprecated ",
"in favor of `svdfact(x; full=false)`. Note that the `thin` keyword ",
"and its replacement `full` have opposite meanings. Additionally, whereas ",
"`svd(x::Number[; thin=...])` returns a tuple of numbers `(u, s, v)` ",
" such that `x ≈ u*s*conj(v)`, `svdfact(x::Number[; full=...])` returns ",
"an `SVD` object that nominally provides `u, s, vt` such that ",
"`x ≈ u*s*vt`. So for a direct replacement, use ",
"`(u, s, vt = first.((svdfact(A[; full=...])...,)); (u, s, conj(vt)))`. ",
"But going forward, ",
"consider using the direct result of `svdfact(A[; full=...])` instead, ",
"either destructured into its components (`u, s, vt = svdfact(A[; full=...])`) ",
"or as an `SVD` object (`svdf = svdfact(A[; full=...])`)."), :svd)
u, s, v = first.((svdfact(x)...,))
return u, s, conj(vt)
end

function svd(A::AbstractMatrix, B::AbstractMatrix)
depwarn(string("`svd(A::Abstractarray, B::AbstractArray)` has been deprecated ",
"in favor of `svdfact(A, B)`. Whereas the former returns a tuple of arrays, ",
"the latter returns a `GeneralizedSVD` object. So for a direct replacement, ",
"use `(svdfact(A, B)...,)`. But going forward, ",
"consider using the direct result of `svdfact(A, B)` instead, ",
"either destructured into its components ",
"(`U, V, Q, D1, D2, R0 = svdfact(A, B)`) ",
"or as a `GeneralizedSVD` object (`gsvdf = svdfact(A, B)`)."), :svd)
return (svdfact(A, B)...,)
end
function svd(x::Number, y::Number)
depwarn(string("`svd(x::Number, y::Number)` has been deprecated ",
"in favor of `svdfact(x, y)`. Whereas the former returns a tuple of numbers, ",
"the latter returns a `GeneralizedSVD` object. So for a direct replacement, ",
"use `first.((svdfact(x, y)...,))`. But going forward, ",
"consider using the direct result of `svdfact(x, y)` instead, ",
"either destructured into its components ",
"(`U, V, Q, D1, D2, R0 = svdfact(x, y)`) ",
"or as a `GeneralizedSVD` object (`gsvdf = svdfact(x, y)`)."), :svd)
return first.((svdfact(x, y)...,))
end

@inline function _simpledepsvd(A)
depwarn(string("`svd(A)` has been deprecated ",
"in favor of `svdfact(A)`. Whereas `svd` ",
"returns a tuple of arrays `(U, S, V)` such that `A ≈ U*Diagonal(S)*V'`, ",
"`svdfact` returns an `SVD` object that nominally provides `U, S, Vt` ",
"such that `A ≈ U*Diagonal(S)*Vt`. So for a direct replacement, use ",
"`(U, S, Vt = svdfact(A); (U, S, copy(Vt')))`. But going forward, ",
"consider using the direct result of `svdfact(A)` instead, ",
"either destructured into its components (`U, S, Vt = svdfact(A)`) ",
"or as an `SVD` object (`svdf = svdfact(A)`)."), :svd)
U, S, Vt = svdfact(A)
return U, S, copy(Vt')
end
svd(A::BitMatrix) = _simpledepsvd(float(A))
svd(D::Diagonal{<:Number}) = _simpledepsvd(D)
svd(A::AbstractTriangular) = _simpledepsvd(copyto!(similar(parent(A)), A))
8 changes: 4 additions & 4 deletions stdlib/LinearAlgebra/src/diagonal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -455,18 +455,18 @@ end
#Singular system
svdvals(D::Diagonal{<:Number}) = sort!(abs.(D.diag), rev = true)
svdvals(D::Diagonal) = [svdvals(v) for v in D.diag]
function svd(D::Diagonal{<:Number})
function svdfact(D::Diagonal{<:Number})
S = abs.(D.diag)
piv = sortperm(S, rev = true)
U = Diagonal(D.diag ./ S)
Up = hcat([U[:,i] for i = 1:length(D.diag)][piv]...)
V = Diagonal(fill!(similar(D.diag), one(eltype(D.diag))))
Vp = hcat([V[:,i] for i = 1:length(D.diag)][piv]...)
return (Up, S[piv], Vp)
return SVD(Up, S[piv], copy(Vp'))
end
function svdfact(D::Diagonal)
U, s, V = svd(D)
SVD(U, s, copy(V'))
U, s, Vt = svdfact(D)
return SVD(U, s, Vt)
end

# dismabiguation methods: * of Diagonal and Adj/Trans AbsVec
Expand Down
Loading

0 comments on commit 8fedd69

Please sign in to comment.