Skip to content
This repository was archived by the owner on Apr 26, 2021. It is now read-only.

Commit 43190f0

Browse files
committed
Update for 0.5, clean up some docs
1 parent d89e7ea commit 43190f0

File tree

6 files changed

+61
-36
lines changed

6 files changed

+61
-36
lines changed

.travis.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ os:
44
- linux
55
- osx
66
julia:
7-
- release
8-
- nightly
7+
- 0.4
8+
- 0.5
9+
# - nightly
910
notifications:
1011
email: false
1112
# uncomment the following lines to override the default test script

REQUIRE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
julia 0.4
2+
Compat

appveyor.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ environment:
22
matrix:
33
- JULIAVERSION: "julialang/bin/winnt/x86/0.4/julia-0.4-latest-win32.exe"
44
- JULIAVERSION: "julialang/bin/winnt/x64/0.4/julia-0.4-latest-win64.exe"
5-
- JULIAVERSION: "julianightlies/bin/winnt/x86/julia-latest-win32.exe"
6-
- JULIAVERSION: "julianightlies/bin/winnt/x64/julia-latest-win64.exe"
5+
- JULIAVERSION: "julialang/bin/winnt/x86/0.4/julia-0.5-latest-win32.exe"
6+
- JULIAVERSION: "julialang/bin/winnt/x64/0.4/julia-0.5-latest-win64.exe"
7+
# - JULIAVERSION: "julianightlies/bin/winnt/x86/julia-latest-win32.exe"
8+
# - JULIAVERSION: "julianightlies/bin/winnt/x64/julia-latest-win64.exe"
79

810
branches:
911
only:

src/GenericSVD.jl

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
__precompile__(true)
12
module GenericSVD
23

4+
import Compat: view
35
import Base: SVD
46

57
include("utils.jl")
@@ -53,12 +55,15 @@ end
5355

5456

5557
"""
56-
Tests if the B[i-1,i] element is approximately zero, using the criteria
58+
is_offdiag_approx_zero!(B::Bidiagonal,i,ɛ)
59+
60+
Tests if the element `B[i-1,i]` is approximately zero, using the criteria
5761
```math
5862
|B_{i-1,i}| ≤ ɛ*(|B_{i-1,i-1}| + |B_{i,i}|)
5963
```
64+
If true, sets the element to exact zero.
6065
"""
61-
function offdiag_approx_zero(B::Bidiagonal,i,ɛ)
66+
function is_offdiag_approx_zero!(B::Bidiagonal,i,ɛ)
6267
iszero = abs(B.ev[i-1]) ɛ*(abs(B.dv[i-1]) + abs(B.dv[i]))
6368
if iszero
6469
B.ev[i-1] = 0
@@ -68,9 +73,19 @@ end
6873

6974

7075
"""
71-
Generic SVD algorithm:
76+
svd!(B::Bidiagonal [, U, Vt [, ϵ]])
77+
78+
Compute the SVD of a bidiagonal matrix `B`, via an implicit QR algorithm with shift (known as a Golub-Kahan iterations).
79+
80+
Optional arguments:
81+
82+
* `U` and `Vt`: orthogonal matrices which pre- and post-multiply `B`, for computing the SVD of a full matrix `X = U*B*Vt` from its bidiagonalized form.
7283
73-
This finds the lowest strictly-bidiagonal submatrix, i.e. n₁, n₂ such that
84+
* `ϵ`: the tolerance for testing zeros of the offdiagonal elements of `B` (see below).
85+
86+
Algorithm:
87+
88+
This proceeds by iteratively finding the lowest strictly-bidiagonal submatrix, i.e. n₁, n₂ such that
7489
```
7590
[ d ? ]
7691
[ d 0 ]
@@ -79,7 +94,7 @@ This finds the lowest strictly-bidiagonal submatrix, i.e. n₁, n₂ such that
7994
n₂ [ d 0 ]
8095
[ d 0 ]
8196
```
82-
Then applies a Golub-Kahan iteration.
97+
then applying a Golub-Kahan QR iteration.
8398
"""
8499
function svd!{T<:Real}(B::Bidiagonal{T}, U=nothing, Vt=nothing, ɛ::T = eps(T))
85100
n = size(B, 1)
@@ -91,28 +106,25 @@ function svd!{T<:Real}(B::Bidiagonal{T}, U=nothing, Vt=nothing, ɛ::T = eps(T))
91106
while true
92107
@label mainloop
93108

94-
while offdiag_approx_zero(B,n₂,ɛ)
109+
while is_offdiag_approx_zero!(B,n₂,ɛ)
95110
n₂ -= 1
96111
if n₂ == 1
97112
@goto done
98113
end
99114
end
100115

101-
102-
103-
n₁ = n₂ - 1
104-
# check for diagonal zeros
105-
if abs(B.dv[n₁]) ɛ*maxB
106-
svd_zerodiag_row!(U,B,n₁,n₂)
107-
@goto mainloop
108-
end
109-
while n₁ > 1 && !offdiag_approx_zero(B,n₁,ɛ)
116+
n₁ = n₂
117+
while true
110118
n₁ -= 1
119+
111120
# check for diagonal zeros
112121
if abs(B.dv[n₁]) ɛ*maxB
113122
svd_zerodiag_row!(U,B,n₁,n₂)
114123
@goto mainloop
115124
end
125+
if n₁ == 1 || is_offdiag_approx_zero!(B,n₁,ɛ)
126+
break
127+
end
116128
end
117129

118130
if abs(B.dv[n₂]) ɛ*maxB
@@ -140,7 +152,9 @@ end
140152

141153

142154
"""
143-
Sets B[n₁,n₁] to zero, then zeros out row n₁ by applying sequential row (left) Givens rotations up to n₂.
155+
svd_zerodiag_row!(U,B,n₁,n₂)
156+
157+
Sets `B[n₁,n₁]` to zero, then zeros out row `n₁` by applying sequential row (left) Givens rotations up to `n₂`, and the corresponding inverse rotations to `U` (preserveing `U*B`.
144158
"""
145159
function svd_zerodiag_row!(U,B,n₁,n₂)
146160
e = B.ev[n₁]
@@ -167,7 +181,9 @@ end
167181

168182

169183
"""
170-
Sets B[n₂,n₂] to zero, then zeros out column n₂ by applying sequential column (right) Givens rotations up to n₁.
184+
svd_zerodiag_col!(B::Bidiagonal,Vt,n₁,n₂)
185+
186+
Sets `B[n₂,n₂]` to zero, then zeros out column `n₂` by applying sequential column (right) Givens rotations up to `n₁`, and the corresponding inverse rotations to `Vt` (preserving `B*Vt`).
171187
"""
172188
function svd_zerodiag_col!(B,Vt,n₁,n₂)
173189
e = B.ev[n₂-1]
@@ -187,7 +203,7 @@ function svd_zerodiag_col!(B,Vt,n₁,n₂)
187203

188204
if n₁ < i
189205
eᵢ = B.ev[i-1]
190-
e = -G.s*eᵢ
206+
e = -G.s*eᵢ
191207
B.ev[i-1] = G.c*eᵢ
192208
end
193209
end
@@ -196,7 +212,9 @@ end
196212

197213

198214
"""
199-
Applies a Golub-Kahan SVD step.
215+
svd_gk!{T<:Real}(B::Bidiagonal{T},U,Vt,n₁,n₂,shift)
216+
217+
Applies a Golub-Kahan SVD step (an implicit QR with shift) to the submatrix `B[n₁:n₂,n₁:n₂]`, applying the inverse transformations to `U` and `Vt` (preserving `U*B*Vt`).
200218
201219
A Givens rotation is applied to the top 2x2 matrix, and the resulting "bulge" is "chased" down the diagonal to the bottom of the matrix.
202220
"""
@@ -275,6 +293,8 @@ end
275293

276294

277295
"""
296+
svdvals2x2(f, h, g)
297+
278298
The singular values of the matrix
279299
```
280300
B = [ f g ;
@@ -289,8 +309,7 @@ function svdvals2x2(f, h, g)
289309
ga = abs(g)
290310
ha = abs(h)
291311

292-
fhmin = min(fa,ha)
293-
fhmax = max(fa,ha)
312+
fhmin, fhmax = minmax(fa,ha)
294313

295314
if fhmin == 0
296315
ssmin = zero(f)

src/bidiagonalize.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,20 @@ function bidiagonalize_tall!{T}(A::Matrix{T},B::Bidiagonal)
1515
# upper bidiagonal
1616

1717
for i = 1:n
18-
x = slice(A, i:m, i)
18+
x = view(A, i:m, i)
1919
τi = LinAlg.reflector!(x)
2020
B.dv[i] = real(A[i,i])
21-
LinAlg.reflectorApply!(x, τi, slice(A, i:m, i+1:n))
21+
LinAlg.reflectorApply!(x, τi, view(A, i:m, i+1:n))
2222
A[i,i] = τi # store reflector in diagonal coefficient
2323

2424
# for Real, this only needs to be n-2
2525
# needed for Complex to ensure superdiagonal is Real
2626
if i <= n-1
27-
x = slice(A, i, i+1:n)
27+
x = view(A, i, i+1:n)
2828
conj!(x)
2929
τi = LinAlg.reflector!(x)
3030
B.ev[i] = real(A[i,i+1])
31-
LinAlg.reflectorApply!(slice(A, i+1:m, i+1:n), x, τi)
31+
LinAlg.reflectorApply!(view(A, i+1:m, i+1:n), x, τi)
3232
A[i,i+1] = τi
3333
end
3434
end
@@ -53,16 +53,16 @@ function Base.full{T}(P::PackedUVt{T};thin=true)
5353
U = eye(T,m,w)
5454
for i = n:-1:1
5555
τi = A[i,i]
56-
x = slice(A, i:m, i)
57-
LinAlg.reflectorApply!(x, τi', slice(U, i:m, i:w))
56+
x = view(A, i:m, i)
57+
LinAlg.reflectorApply!(x, τi', view(U, i:m, i:w))
5858
end
5959

6060
# Vt = P_{n_2} ... P_1
6161
Vt = eye(T,n,n)
6262
for i = n-1:-1:1
6363
τi = A[i,i+1]
64-
x = slice(A, i, i+1:n)
65-
LinAlg.reflectorApply!(slice(Vt, i:n, i+1:n), x, τi')
64+
x = view(A, i, i+1:n)
65+
LinAlg.reflectorApply!(view(Vt, i:n, i+1:n), x, τi')
6666
end
6767
U,Vt
6868
end

src/utils.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ import Base: A_mul_B!, A_mul_Bc!, A_ldiv_B!
2626
A_mul_B!(G::LinAlg.Givens, ::Void) = nothing
2727
A_mul_Bc!(::Void, G::LinAlg.Givens) = nothing
2828

29-
function A_ldiv_B!{Ta,Tb}(A::SVD{Ta}, B::StridedVecOrMat{Tb})
30-
k = searchsortedlast(A.S, eps(real(Ta))*A.S[1], rev=true)
31-
sub(A.Vt,1:k,:)' * (sub(A.S,1:k) .\ (sub(A.U,:,1:k)' * B))
29+
if VERSION < v"0.5.0-"
30+
function A_ldiv_B!{Ta,Tb}(A::SVD{Ta}, B::StridedVecOrMat{Tb})
31+
k = searchsortedlast(A.S, eps(real(Ta))*A.S[1], rev=true)
32+
view(A.Vt,1:k,:)' * (view(A.S,1:k) .\ (view(A.U,:,1:k)' * B))
33+
end
3234
end
3335

3436

0 commit comments

Comments
 (0)