Skip to content

Commit 5f05098

Browse files
alanedelmanViralBShahandreasnoack
authored andcommitted
Update svd.jl (#30239)
* Update svd.jl * Update svd.jl Make doc more useful to the reader. * Fix grammar and one trailing whitespace * Update svd.jl * Fix doctests * Avoid duplicating documentation between mutating and non-mutating versions of svd functions. * Reorganize generalized svd docstring and doctests * Break some long lines Co-authored-by: Viral B. Shah <viral@juliacomputing.com> Co-authored-by: Andreas Noack <andreas@noack.dk>
1 parent 2d8b708 commit 5f05098

File tree

1 file changed

+38
-151
lines changed
  • stdlib/LinearAlgebra/src

1 file changed

+38
-151
lines changed

stdlib/LinearAlgebra/src/svd.jl

Lines changed: 38 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -87,32 +87,7 @@ default_svd_alg(A) = DivideAndConquer()
8787
svd!(A; full::Bool = false, alg::Algorithm = default_svd_alg(A)) -> SVD
8888
8989
`svd!` is the same as [`svd`](@ref), but saves space by
90-
overwriting the input `A`, instead of creating a copy.
91-
92-
# Examples
93-
```jldoctest
94-
julia> A = [1. 0. 0. 0. 2.; 0. 0. 3. 0. 0.; 0. 0. 0. 0. 0.; 0. 2. 0. 0. 0.]
95-
4×5 Array{Float64,2}:
96-
1.0 0.0 0.0 0.0 2.0
97-
0.0 0.0 3.0 0.0 0.0
98-
0.0 0.0 0.0 0.0 0.0
99-
0.0 2.0 0.0 0.0 0.0
100-
101-
julia> F = svd!(A);
102-
103-
julia> F.U * Diagonal(F.S) * F.Vt
104-
4×5 Array{Float64,2}:
105-
1.0 0.0 0.0 0.0 2.0
106-
0.0 0.0 3.0 0.0 0.0
107-
0.0 0.0 0.0 0.0 0.0
108-
0.0 2.0 0.0 0.0 0.0
109-
110-
julia> A
111-
4×5 Array{Float64,2}:
112-
-2.23607 0.0 0.0 0.0 0.618034
113-
0.0 -3.0 1.0 0.0 0.0
114-
0.0 0.0 0.0 0.0 0.0
115-
0.0 0.0 -2.0 0.0 0.0
90+
overwriting the input `A`, instead of creating a copy. See documentation of [`svd`](@ref) for details.
11691
```
11792
"""
11893
function svd!(A::StridedMatrix{T}; full::Bool = false, alg::Algorithm = default_svd_alg(A)) where T<:BlasFloat
@@ -161,25 +136,21 @@ Another (typically slower but more accurate) option is `alg = QRIteration()`.
161136
162137
# Examples
163138
```jldoctest
164-
julia> A = [1. 0. 0. 0. 2.; 0. 0. 3. 0. 0.; 0. 0. 0. 0. 0.; 0. 2. 0. 0. 0.]
165-
4×5 Array{Float64,2}:
166-
1.0 0.0 0.0 0.0 2.0
167-
0.0 0.0 3.0 0.0 0.0
168-
0.0 0.0 0.0 0.0 0.0
169-
0.0 2.0 0.0 0.0 0.0
139+
julia> A = rand(4,3);
170140
171-
julia> F = svd(A);
141+
julia> F = svd(A); # Store the Factorization Object
172142
173-
julia> F.U * Diagonal(F.S) * F.Vt
174-
4×5 Array{Float64,2}:
175-
1.0 0.0 0.0 0.0 2.0
176-
0.0 0.0 3.0 0.0 0.0
177-
0.0 0.0 0.0 0.0 0.0
178-
0.0 2.0 0.0 0.0 0.0
143+
julia> A ≈ F.U * Diagonal(F.S) * F.Vt
144+
true
179145
180-
julia> u, s, v = F; # destructuring via iteration
146+
julia> U, S, V = F; # destructuring via iteration
181147
182-
julia> u == F.U && s == F.S && v == F.V
148+
julia> A ≈ U * Diagonal(S) * V'
149+
true
150+
151+
julia> Uonly, = svd(A); # Store U only
152+
153+
julia> Uonly == U
183154
true
184155
```
185156
"""
@@ -217,29 +188,6 @@ Base.propertynames(F::SVD, private::Bool=false) =
217188
218189
Return the singular values of `A`, saving space by overwriting the input.
219190
See also [`svdvals`](@ref) and [`svd`](@ref).
220-
221-
# Examples
222-
```jldoctest
223-
julia> A = [1. 0. 0. 0. 2.; 0. 0. 3. 0. 0.; 0. 0. 0. 0. 0.; 0. 2. 0. 0. 0.]
224-
4×5 Array{Float64,2}:
225-
1.0 0.0 0.0 0.0 2.0
226-
0.0 0.0 3.0 0.0 0.0
227-
0.0 0.0 0.0 0.0 0.0
228-
0.0 2.0 0.0 0.0 0.0
229-
230-
julia> svdvals!(A)
231-
4-element Array{Float64,1}:
232-
3.0
233-
2.23606797749979
234-
2.0
235-
0.0
236-
237-
julia> A
238-
4×5 Array{Float64,2}:
239-
-2.23607 0.0 0.0 0.0 0.618034
240-
0.0 -3.0 1.0 0.0 0.0
241-
0.0 0.0 0.0 0.0 0.0
242-
0.0 0.0 -2.0 0.0 0.0
243191
```
244192
"""
245193
svdvals!(A::StridedMatrix{T}) where {T<:BlasFloat} = isempty(A) ? zeros(real(T), 0) : LAPACK.gesdd!('N', A)[2]
@@ -409,41 +357,7 @@ Base.iterate(S::GeneralizedSVD, ::Val{:done}) = nothing
409357
svd!(A, B) -> GeneralizedSVD
410358
411359
`svd!` is the same as [`svd`](@ref), but modifies the arguments
412-
`A` and `B` in-place, instead of making copies.
413-
414-
# Examples
415-
```jldoctest
416-
julia> A = [1. 0.; 0. -1.]
417-
2×2 Array{Float64,2}:
418-
1.0 0.0
419-
0.0 -1.0
420-
421-
julia> B = [0. 1.; 1. 0.]
422-
2×2 Array{Float64,2}:
423-
0.0 1.0
424-
1.0 0.0
425-
426-
julia> F = svd!(A, B);
427-
428-
julia> F.U*F.D1*F.R0*F.Q'
429-
2×2 Array{Float64,2}:
430-
1.0 0.0
431-
0.0 -1.0
432-
433-
julia> F.V*F.D2*F.R0*F.Q'
434-
2×2 Array{Float64,2}:
435-
0.0 1.0
436-
1.0 0.0
437-
438-
julia> A
439-
2×2 Array{Float64,2}:
440-
1.41421 0.0
441-
0.0 -1.41421
442-
443-
julia> B
444-
2×2 Array{Float64,2}:
445-
1.0 -0.0
446-
0.0 -1.0
360+
`A` and `B` in-place, instead of making copies. See documentation of [`svd`](@ref) for details.
447361
```
448362
"""
449363
function svd!(A::StridedMatrix{T}, B::StridedMatrix{T}) where T<:BlasFloat
@@ -458,12 +372,11 @@ end
458372
svd(A::StridedMatrix{T}, B::StridedMatrix{T}) where {T<:BlasFloat} = svd!(copy(A),copy(B))
459373

460374
"""
375+
461376
svd(A, B) -> GeneralizedSVD
462377
463378
Compute the generalized SVD of `A` and `B`, returning a `GeneralizedSVD` factorization
464-
object `F`, such that `A = F.U*F.D1*F.R0*F.Q'` and `B = F.V*F.D2*F.R0*F.Q'`.
465-
466-
For an M-by-N matrix `A` and P-by-N matrix `B`,
379+
object `F` such that `[A;B] = [F.U * F.D1; F.V * F.D2] * F.R0 * F.Q'`
467380
468381
- `U` is a M-by-M orthogonal matrix,
469382
- `V` is a P-by-P orthogonal matrix,
@@ -477,35 +390,36 @@ For an M-by-N matrix `A` and P-by-N matrix `B`,
477390
478391
Iterating the decomposition produces the components `U`, `V`, `Q`, `D1`, `D2`, and `R0`.
479392
480-
The entries of `F.D1` and `F.D2` are related, as explained in the LAPACK
481-
documentation for the
482-
[generalized SVD](http://www.netlib.org/lapack/lug/node36.html) and the
483-
[xGGSVD3](http://www.netlib.org/lapack/explore-html/d6/db3/dggsvd3_8f.html)
484-
routine which is called underneath (in LAPACK 3.6.0 and newer).
393+
The generalized SVD is used in applications such as when one wants to compare how much belongs
394+
to `A` vs. how much belongs to `B`, as in human vs yeast genome, or signal vs noise, or between
395+
clusters vs within clusters. (See Edelman and Wang for discussion: https://arxiv.org/abs/1901.00485)
396+
397+
It decomposes `[A; B]` into `[UC; VS]H`, where `[UC; VS]` is a natural orthogonal basis for the
398+
column space of `[A; B]`, and `H = RQ'` is a natural non-orthogonal basis for the rowspace of `[A;B]`,
399+
where the top rows are most closely attributed to the `A` matrix, and the bottom to the `B` matrix.
400+
The multi-cosine/sine matrices `C` and `S` provide a multi-measure of how much `A` vs how much `B`,
401+
and `U` and `V` provide directions in which these are measured.
485402
486403
# Examples
487404
```jldoctest
488-
julia> A = [1. 0.; 0. -1.]
489-
2×2 Array{Float64,2}:
490-
1.0 0.0
491-
0.0 -1.0
492-
493-
julia> B = [0. 1.; 1. 0.]
494-
2×2 Array{Float64,2}:
495-
0.0 1.0
496-
1.0 0.0
405+
julia> A = randn(3,2); B=randn(4,2);
497406
498407
julia> F = svd(A, B);
499408
500-
julia> F.U*F.D1*F.R0*F.Q'
501-
2×2 Array{Float64,2}:
502-
1.0 0.0
503-
0.0 -1.0
409+
julia> U,V,Q,C,S,R = F;
504410
505-
julia> F.V*F.D2*F.R0*F.Q'
506-
2×2 Array{Float64,2}:
507-
0.0 1.0
508-
1.0 0.0
411+
julia> H = R*Q';
412+
413+
julia> [A; B] ≈ [U*C; V*S]*H
414+
true
415+
416+
julia> [A; B] ≈ [F.U*F.D1; F.V*F.D2]*F.R0*F.Q'
417+
true
418+
419+
julia> Uonly, = svd(A,B);
420+
421+
julia> U == Uonly
422+
true
509423
```
510424
"""
511425
function svd(A::StridedMatrix{TA}, B::StridedMatrix{TB}) where {TA,TB}
@@ -582,33 +496,6 @@ end
582496
Return the generalized singular values from the generalized singular value
583497
decomposition of `A` and `B`, saving space by overwriting `A` and `B`.
584498
See also [`svd`](@ref) and [`svdvals`](@ref).
585-
586-
# Examples
587-
```jldoctest
588-
julia> A = [1. 0.; 0. -1.]
589-
2×2 Array{Float64,2}:
590-
1.0 0.0
591-
0.0 -1.0
592-
593-
julia> B = [0. 1.; 1. 0.]
594-
2×2 Array{Float64,2}:
595-
0.0 1.0
596-
1.0 0.0
597-
598-
julia> svdvals!(A, B)
599-
2-element Array{Float64,1}:
600-
1.0
601-
1.0
602-
603-
julia> A
604-
2×2 Array{Float64,2}:
605-
1.41421 0.0
606-
0.0 -1.41421
607-
608-
julia> B
609-
2×2 Array{Float64,2}:
610-
1.0 -0.0
611-
0.0 -1.0
612499
```
613500
"""
614501
function svdvals!(A::StridedMatrix{T}, B::StridedMatrix{T}) where T<:BlasFloat

0 commit comments

Comments
 (0)