3
3
# ### Specialized matrix types ####
4
4
5
5
# # (complex) symmetric tridiagonal matrices
6
- struct SymTridiagonal{T,V<: AbstractVector{T} } <: AbstractMatrix{T}
6
+ struct SymTridiagonal{T, V<: AbstractVector{T} } <: AbstractMatrix{T}
7
7
dv:: V # diagonal
8
- ev:: V # subdiagonal
9
- function SymTridiagonal {T,V} (dv, ev) where {T,V<: AbstractVector{T} }
8
+ ev:: V # superdiagonal
9
+ function SymTridiagonal {T, V} (dv, ev) where {T, V<: AbstractVector{T} }
10
10
require_one_based_indexing (dv, ev)
11
11
if ! (length (dv) - 1 <= length (ev) <= length (dv))
12
12
throw (DimensionMismatch (" subdiagonal has wrong length. Has length $(length (ev)) , but should be either $(length (dv) - 1 ) or $(length (dv)) ." ))
13
13
end
14
- new {T,V} (dv,ev)
14
+ new {T, V} (dv, ev)
15
15
end
16
16
end
17
17
@@ -23,6 +23,10 @@ sub/super-diagonal (`ev`), respectively. The result is of type `SymTridiagonal`
23
23
and provides efficient specialized eigensolvers, but may be converted into a
24
24
regular matrix with [`convert(Array, _)`](@ref) (or `Array(_)` for short).
25
25
26
+ For `SymTridiagonal` block matrices, the elements of `dv` are symmetrized.
27
+ The argument `ev` is interpreted as the superdiagonal. Blocks from the
28
+ subdiagonal are (materialized) transpose of the corresponding superdiagonal blocks.
29
+
26
30
# Examples
27
31
```jldoctest
28
32
julia> dv = [1, 2, 3, 4]
@@ -44,6 +48,23 @@ julia> SymTridiagonal(dv, ev)
44
48
7 2 8 ⋅
45
49
⋅ 8 3 9
46
50
⋅ ⋅ 9 4
51
+
52
+ julia> A = SymTridiagonal(fill([1 2; 3 4], 3), fill([1 2; 3 4], 2));
53
+
54
+ julia> A[1,1]
55
+ 2×2 Symmetric{Int64,Array{Int64,2}}:
56
+ 1 2
57
+ 2 4
58
+
59
+ julia> A[1,2]
60
+ 2×2 Array{Int64,2}:
61
+ 1 2
62
+ 3 4
63
+
64
+ julia> A[2,1]
65
+ 2×2 Array{Int64,2}:
66
+ 1 3
67
+ 2 4
47
68
```
48
69
"""
49
70
SymTridiagonal (dv:: V , ev:: V ) where {T,V<: AbstractVector{T} } = SymTridiagonal {T} (dv, ev)
56
77
"""
57
78
SymTridiagonal(A::AbstractMatrix)
58
79
59
- Construct a symmetric tridiagonal matrix from the diagonal and
60
- first sub/super-diagonal, of the symmetric matrix `A`.
80
+ Construct a symmetric tridiagonal matrix from the diagonal and first superdiagonal
81
+ of the symmetric matrix `A`.
61
82
62
83
# Examples
63
84
```jldoctest
@@ -72,11 +93,18 @@ julia> SymTridiagonal(A)
72
93
1 2 ⋅
73
94
2 4 5
74
95
⋅ 5 6
96
+
97
+ julia> B = reshape([[1 2; 2 3], [1 2; 3 4], [1 3; 2 4], [1 2; 2 3]], 2, 2);
98
+
99
+ julia> SymTridiagonal(B)
100
+ 2×2 SymTridiagonal{Array{Int64,2},Array{Array{Int64,2},1}}:
101
+ [1 2; 2 3] [1 3; 2 4]
102
+ [1 2; 3 4] [1 2; 2 3]
75
103
```
76
104
"""
77
105
function SymTridiagonal (A:: AbstractMatrix )
78
- if diag (A,1 ) == diag (A,- 1 )
79
- SymTridiagonal (diag (A,0 ), diag (A,1 ))
106
+ if ( diag (A, 1 ) == transpose .( diag (A, - 1 ))) && all ( issymmetric .( diag (A, 0 )) )
107
+ SymTridiagonal (diag (A, 0 ), diag (A, 1 ))
80
108
else
81
109
throw (ArgumentError (" matrix is not symmetric; cannot convert to SymTridiagonal" ))
82
110
end
@@ -139,13 +167,13 @@ adjoint(S::SymTridiagonal) = Adjoint(S)
139
167
Base. copy (S:: Adjoint{<:Any,<:SymTridiagonal} ) = SymTridiagonal (map (x -> copy .(adjoint .(x)), (S. parent. dv, S. parent. ev))... )
140
168
Base. copy (S:: Transpose{<:Any,<:SymTridiagonal} ) = SymTridiagonal (map (x -> copy .(transpose .(x)), (S. parent. dv, S. parent. ev))... )
141
169
142
- function diag (M:: SymTridiagonal , n:: Integer = 0 )
170
+ function diag (M:: SymTridiagonal{<:Number} , n:: Integer = 0 )
143
171
# every branch call similar(..., ::Int) to make sure the
144
172
# same vector type is returned independent of n
145
173
absn = abs (n)
146
174
if absn == 0
147
175
return copyto! (similar (M. dv, length (M. dv)), M. dv)
148
- elseif absn== 1
176
+ elseif absn == 1
149
177
return copyto! (similar (M. ev, length (M. ev)), M. ev)
150
178
elseif absn <= size (M,1 )
151
179
return fill! (similar (M. dv, size (M,1 )- absn), 0 )
@@ -154,6 +182,22 @@ function diag(M::SymTridiagonal, n::Integer=0)
154
182
" and at most $(size (M, 2 )) for an $(size (M, 1 )) -by-$(size (M, 2 )) matrix" )))
155
183
end
156
184
end
185
+ function diag (M:: SymTridiagonal , n:: Integer = 0 )
186
+ # every branch call similar(..., ::Int) to make sure the
187
+ # same vector type is returned independent of n
188
+ if n == 0
189
+ return copyto! (similar (M. dv, length (M. dv)), symmetric .(M. dv, :U ))
190
+ elseif n == 1
191
+ return copyto! (similar (M. ev, length (M. ev)), M. ev)
192
+ elseif n == - 1
193
+ return copyto! (similar (M. ev, length (M. ev)), transpose .(M. ev))
194
+ elseif n <= size (M,1 )
195
+ throw (ArgumentError (" requested diagonal contains undefined zeros of an array type" ))
196
+ else
197
+ throw (ArgumentError (string (" requested diagonal, $n , must be at least $(- size (M, 1 )) " ,
198
+ " and at most $(size (M, 2 )) for an $(size (M, 1 )) -by-$(size (M, 2 )) matrix" )))
199
+ end
200
+ end
157
201
158
202
+ (A:: SymTridiagonal , B:: SymTridiagonal ) = SymTridiagonal (A. dv+ B. dv, A. ev+ B. ev)
159
203
- (A:: SymTridiagonal , B:: SymTridiagonal ) = SymTridiagonal (A. dv- B. dv, A. ev- B. ev)
@@ -390,9 +434,9 @@ function getindex(A::SymTridiagonal{T}, i::Integer, j::Integer) where T
390
434
throw (BoundsError (A, (i,j)))
391
435
end
392
436
if i == j
393
- return A. dv[i]
437
+ return symmetric ( A. dv[i], :U ) :: symmetric_type ( eltype (A . dv))
394
438
elseif i == j + 1
395
- return A. ev[j]
439
+ return copy ( transpose ( A. ev[j])) # materialized for type stability
396
440
elseif i + 1 == j
397
441
return A. ev[i]
398
442
else
0 commit comments