Skip to content

Commit 084e215

Browse files
authored
Fix precision of 2x2 eigenvectors (JuliaArrays#1191)
* Fix precision of 2x2 eigenvectors * Use same code for upper and lower diag (2x2 eigen) * Add tests and fix some issues * Fix test on julia 1.10 * Remove todo comments * Bump patch version
1 parent 6bd6f52 commit 084e215

File tree

4 files changed

+45
-44
lines changed

4 files changed

+45
-44
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "StaticArrays"
22
uuid = "90137ffa-7385-5640-81b9-e52037218182"
3-
version = "1.6.2"
3+
version = "1.6.3"
44

55
[deps]
66
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

src/eigen.jl

Lines changed: 20 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -159,48 +159,26 @@ end
159159
@inline function _eig(::Size{(2,2)}, A::LinearAlgebra.RealHermSymComplexHerm{T}, permute, scale) where {T <: Real}
160160
a = A.data
161161
TA = eltype(A)
162-
@inbounds if A.uplo == 'U'
163-
if !iszero(a[3]) # A is not diagonal
164-
t_half = real(a[1] + a[4]) / 2
165-
tmp = norm(SVector((a[1] - a[4])/2, a[3]'))
166-
vals = SVector(t_half - tmp, t_half + tmp)
167-
168-
v11 = vals[1] - a[4]
169-
n1 = sqrt(v11' * v11 + a[3]' * a[3])
170-
v11 = v11 / n1
171-
v12 = a[3]' / n1
172-
173-
v21 = vals[2] - a[4]
174-
n2 = sqrt(v21' * v21 + a[3]' * a[3])
175-
v21 = v21 / n2
176-
v22 = a[3]' / n2
177-
178-
vecs = @SMatrix [ v11 v21 ;
179-
v12 v22 ]
180-
181-
return Eigen(vals, vecs)
182-
end
183-
else # A.uplo == 'L'
184-
if !iszero(a[2]) # A is not diagonal
185-
t_half = real(a[1] + a[4]) / 2
186-
tmp = norm(SVector((a[1] - a[4])/2, a[2]))
187-
vals = SVector(t_half - tmp, t_half + tmp)
188-
189-
v11 = vals[1] - a[4]
190-
n1 = sqrt(v11' * v11 + a[2]' * a[2])
191-
v11 = v11 / n1
192-
v12 = a[2] / n1
193-
194-
v21 = vals[2] - a[4]
195-
n2 = sqrt(v21' * v21 + a[2]' * a[2])
196-
v21 = v21 / n2
197-
v22 = a[2] / n2
198-
199-
vecs = @SMatrix [ v11 v21 ;
200-
v12 v22 ]
201-
202-
return Eigen(vals,vecs)
203-
end
162+
@inbounds a21 = A.uplo == 'U' ? a[3]' : a[2]
163+
@inbounds if !iszero(a21) # A is not diagonal
164+
t_half = real(a[1] + a[4]) / 2
165+
diag_avg_diff = (a[1] - a[4])/2
166+
tmp = norm(SVector(diag_avg_diff, a21))
167+
vals = SVector(t_half - tmp, t_half + tmp)
168+
v11 = -tmp + diag_avg_diff
169+
n1 = sqrt(v11' * v11 + a21 * a21')
170+
v11 = v11 / n1
171+
v12 = a21 / n1
172+
173+
v21 = tmp + diag_avg_diff
174+
n2 = sqrt(v21' * v21 + a21 * a21')
175+
v21 = v21 / n2
176+
v22 = a21 / n2
177+
178+
vecs = @SMatrix [ v11 v21 ;
179+
v12 v22 ]
180+
181+
return Eigen(vals, vecs)
204182
end
205183

206184
# A must be diagonal if we reached this point; treatment of uplo 'L' and 'U' is then identical

test/eigen.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,25 @@ using StaticArrays, Test, LinearAlgebra
8383
@test eigvecs(E) * SDiagonal(eigvals(E)) * eigvecs(E)' A
8484
end
8585

86+
# issue #956
87+
v1, v2 = let A = SMatrix{2,2}((1.0, 1e-100, 1e-100, 1.0))
88+
vecs = eigvecs(eigen(Hermitian(A)))
89+
vecs[:,1], vecs[:,2]
90+
end
91+
@test norm(v1) 1
92+
@test norm(v2) 1
93+
@test acos(v1 v2)*2 π
94+
95+
# Test that correct value is taken for upper or lower sym
96+
for T in (Float64, Complex{Float64})
97+
af = SMatrix{2,2}(rand(T, 4))
98+
a = af + af' # Make hermitian
99+
au = Hermitian(SMatrix{2,2}((a[1,1], zero(T), a[1,2], a[2,2])), 'U')
100+
al = Hermitian(SMatrix{2,2}((a[1,1], a[2,1], zero(T), a[2,2])), 'L')
101+
@test eigvals(eigen(a)) eigvals(eigen(au)) eigvals(eigen(al))
102+
@test eigvals(eigen(a)) eigvals(eigen(au)) eigvals(eigen(al))
103+
end
104+
86105
m1_a = randn(2,2)
87106
m1_a = m1_a*m1_a'
88107
m1 = SMatrix{2,2}(m1_a)

test/initializers.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ if VERSION >= v"1.7.0"
5050
@test SA[1 2;1 2 ;;; 1 2;1 2] === SArray{Tuple{2,2,2}}(Tuple([1 2;1 2 ;;; 1 2;1 2]))
5151
@test_inlined SA_test_hvncat1(3)
5252
@test_inlined SA_test_hvncat2(2)
53-
@test_throws ArgumentError SA[1;2;;3]
53+
if VERSION < v"1.10-DEV"
54+
@test_throws ArgumentError SA[1;2;;3]
55+
else
56+
@test_throws DimensionMismatch SA[1;2;;3]
57+
end
5458
end
5559

5660
# https://github.com/JuliaArrays/StaticArrays.jl/pull/685

0 commit comments

Comments
 (0)