Skip to content

Commit b4eb88a

Browse files
authored
Fix bug in pinv (JuliaLang#45009)
1 parent 3d787a7 commit b4eb88a

File tree

2 files changed

+31
-37
lines changed

2 files changed

+31
-37
lines changed

stdlib/LinearAlgebra/src/dense.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1449,12 +1449,13 @@ function pinv(A::AbstractMatrix{T}; atol::Real = 0.0, rtol::Real = (eps(real(flo
14491449
return similar(A, Tout, (n, m))
14501450
end
14511451
if isdiag(A)
1452-
ind = diagind(A)
1453-
dA = view(A, ind)
1452+
indA = diagind(A)
1453+
dA = view(A, indA)
14541454
maxabsA = maximum(abs, dA)
14551455
tol = max(rtol * maxabsA, atol)
14561456
B = fill!(similar(A, Tout, (n, m)), 0)
1457-
B[ind] .= (x -> abs(x) > tol ? pinv(x) : zero(x)).(dA)
1457+
indB = diagind(B)
1458+
B[indB] .= (x -> abs(x) > tol ? pinv(x) : zero(x)).(dA)
14581459
return B
14591460
end
14601461
SVD = svd(A)

stdlib/LinearAlgebra/test/pinv.jl

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -63,39 +63,23 @@ function tridiag(T::Type, m::Integer, n::Integer)
6363
end
6464
tridiag(m::Integer, n::Integer) = tridiag(Float64, m::Integer, n::Integer)
6565

66-
function randn_float64(m::Integer, n::Integer)
67-
a=randn(m,n)
68-
b = Matrix{Float64}(undef, m, n)
69-
for i=1:n
70-
for j=1:m
71-
b[j,i]=convert(Float64,a[j,i])
72-
end
73-
end
74-
return b
75-
end
76-
77-
function randn_float32(m::Integer, n::Integer)
78-
a=randn(m,n)
79-
b = Matrix{Float32}(undef, m, n)
80-
for i=1:n
81-
for j=1:m
82-
b[j,i]=convert(Float32,a[j,i])
83-
end
84-
end
85-
return b
86-
end
87-
66+
function test_pinv(a,tol1,tol2)
67+
m,n = size(a)
8868

89-
function test_pinv(a,m,n,tol1,tol2,tol3)
9069
apinv = @inferred pinv(a)
91-
70+
@test size(apinv) == (n,m)
9271
@test norm(a*apinv*a-a)/norm(a) 0 atol=tol1
93-
x0 = randn(n); b = a*x0; x = apinv*b
72+
@test norm(apinv*a*apinv-apinv)/norm(apinv) 0 atol=tol1
73+
b = a*randn(n)
74+
x = apinv*b
9475
@test norm(a*x-b)/norm(b) 0 atol=tol1
95-
apinv = pinv(a,sqrt(eps(real(one(eltype(a))))))
9676

77+
apinv = @inferred pinv(a,sqrt(eps(real(one(eltype(a))))))
78+
@test size(apinv) == (n,m)
9779
@test norm(a*apinv*a-a)/norm(a) 0 atol=tol2
98-
x0 = randn(n); b = a*x0; x = apinv*b
80+
@test norm(apinv*a*apinv-apinv)/norm(apinv) 0 atol=tol2
81+
b = a*randn(n)
82+
x = apinv*b
9983
@test norm(a*x-b)/norm(b) 0 atol=tol2
10084
end
10185

@@ -104,28 +88,25 @@ end
10488
default_tol = (real(one(eltya))) * max(m,n) * 10
10589
tol1 = 1e-2
10690
tol2 = 1e-5
107-
tol3 = 1e-5
10891
if real(eltya) == Float32
10992
tol1 = 1e0
11093
tol2 = 1e-2
111-
tol3 = 1e-2
11294
end
11395
@testset "dense/ill-conditioned matrix" begin
114-
### a = randn_float64(m,n) * hilb(eltya,n)
11596
a = hilb(eltya, m, n)
116-
test_pinv(a, m, n, tol1, tol2, tol3)
97+
test_pinv(a, tol1, tol2)
11798
end
11899
@testset "dense/diagonal matrix" begin
119100
a = onediag(eltya, m, n)
120-
test_pinv(a, m, n, default_tol, default_tol, default_tol)
101+
test_pinv(a, default_tol, default_tol)
121102
end
122103
@testset "dense/tri-diagonal matrix" begin
123104
a = tridiag(eltya, m, n)
124-
test_pinv(a, m, n, default_tol, tol2, default_tol)
105+
test_pinv(a, default_tol, tol2)
125106
end
126107
@testset "Diagonal matrix" begin
127108
a = onediag_sparse(eltya, m)
128-
test_pinv(a, m, m, default_tol, default_tol, default_tol)
109+
test_pinv(a, default_tol, default_tol)
129110
end
130111
@testset "Vector" begin
131112
a = rand(eltya, m)
@@ -164,6 +145,18 @@ end
164145
@test C ones(2,2)
165146
end
166147

148+
@testset "non-square diagonal matrices" begin
149+
A = eltya[1 0 ; 0 1 ; 0 0]
150+
B = pinv(A)
151+
@test A*B*A A
152+
@test B*A*B B
153+
154+
A = eltya[1 0 0 ; 0 1 0]
155+
B = pinv(A)
156+
@test A*B*A A
157+
@test B*A*B B
158+
end
159+
167160
if eltya <: LinearAlgebra.BlasReal
168161
@testset "sub-normal numbers/vectors/matrices" begin
169162
a = pinv(floatmin(eltya)/100)

0 commit comments

Comments
 (0)