Skip to content

Commit 48b6696

Browse files
committed
feat(matrices): add rosser
1 parent 6d965e4 commit 48b6696

File tree

2 files changed

+126
-0
lines changed

2 files changed

+126
-0
lines changed

Diff for: src/matrices/index.jl

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export
3939
Rando,
4040
RandSVD,
4141
Rohess,
42+
Rosser,
4243
Toeplitz,
4344
Triw
4445

@@ -79,6 +80,7 @@ include("randcorr.jl")
7980
include("rando.jl")
8081
include("randsvd.jl")
8182
include("rohess.jl")
83+
include("rosser.jl")
8284
include("toeplitz.jl")
8385
include("triw.jl")
8486

@@ -124,6 +126,7 @@ MATRIX_GROUPS[GROUP_BUILTIN] = Set([
124126
Rando,
125127
RandSVD,
126128
Rohess,
129+
Rosser,
127130
Toeplitz,
128131
Triw,
129132
])

Diff for: src/matrices/rosser.jl

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
"""
2+
Sylvester's orthogonal matrix
3+
See Rosser matrix References 2.
4+
5+
for a = d = 2, b = c = 1, P_block' * P_block = 10 * Identity
6+
"""
7+
P_block(::Type{T}, a, b, c, d) where {T} =
8+
reshape(T[a, b, c, d, b, -a, -d, c, c, d, -a, -b, d, -c, b, -a], 4, 4)
9+
10+
"""
11+
Rosser Matrix
12+
=============
13+
The Rosser matrix’s eigenvalues are very close together
14+
so it is a challenging matrix for many eigenvalue algorithms.
15+
16+
*Input options:*
17+
18+
+ dim, a, b: `dim` is the dimension of the matrix.
19+
`dim` must be a power of 2.
20+
`a` and `b` are scalars. For `dim = 8, a = 2` and `b = 1`, the generated
21+
matrix is the test matrix used by Rosser.
22+
23+
+ dim: `a = rand(1:5), b = rand(1:5)`.
24+
25+
*References:*
26+
27+
**J. B. Rosser, C. Lanczos, M. R. Hestenes, W. Karush**,
28+
Separation of close eigenvalues of a real symmetric matrix,
29+
Journal of Research of the National Bureau of Standards, v(47)
30+
(1951)
31+
"""
32+
struct Rosser{T<:Number} <: AbstractMatrix{T}
33+
n::Integer
34+
a::T
35+
b::T
36+
M::AbstractMatrix{T}
37+
38+
function Rosser{T}(n::Integer, a::T, b::T) where {T<:Number}
39+
n >= 0 || throw(ArgumentError("$n < 0"))
40+
41+
if n < 1
42+
lgn = 0
43+
else
44+
lgn = round(Integer, log2(n))
45+
end
46+
2^lgn != n && throw(ArgumentError("n must be positive integer and a power of 2."))
47+
48+
if n == 1 # handle 1-d case
49+
return 611 * ones(T, 1, 1)
50+
end
51+
52+
if n == 2
53+
#eigenvalues are 500, 510
54+
B = T[101 1; 1 101]
55+
P = T[2 1; 1 -2]
56+
A = P' * B * P
57+
elseif n == 4
58+
# eigenvalues are 0.1, 1019.9, 1020, 1020 for a = 2 and b = 1
59+
B = zeros(T, n, n)
60+
B[1, 1], B[1, 4], B[4, 1], B[4, 4] = 101, 1, 1, 101
61+
B[2, 2], B[2, 3], B[3, 2], B[3, 3] = 1, 10, 10, 101
62+
P = P_block(T, a, b, b, a)
63+
A = P' * B * P
64+
elseif n == 8
65+
# eigenvalues are 1020, 1020, 1000, 1000, 0.098, 0, -1020
66+
B = zeros(T, n, n)
67+
B[1, 1], B[6, 1], B[2, 2], B[8, 2] = 102, 1, 101, 1
68+
B[3, 3], B[7, 3] = 98, 14
69+
B[4, 4], B[5, 4], B[4, 5], B[5, 5] = 1, 10, 10, 101
70+
B[1, 6], B[6, 6], B[3, 7], B[7, 7], B[2, 8], B[8, 8] = 1, -102, 14, 2, 1, 101
71+
P = [P_block(T, a, b, b, a)' zeros(T, 4, 4); zeros(T, 4, 4) P_block(T, b, -b, -a, a)]
72+
A = P' * B * P
73+
else
74+
lgn = lgn - 2
75+
halfn = round(Integer, n / 2)
76+
# using Sylvester's method
77+
P = P_block(T, a, b, b, a)
78+
m = 4
79+
for i in 1:lgn
80+
P = [P zeros(T, m, m); zeros(T, m, m) P]
81+
m = m * 2
82+
end
83+
# mix 4 2-by-2 matrices (with close eigenvalues) into a large nxn matrix.
84+
B_list = T[102, 1, 1, -102, 101, 1, 1, 101, 1, 10, 10, 101, 98, 14, 14, 2]
85+
B = zeros(T, n, n)
86+
j, k = 1, 5
87+
for i in 1:(halfn+1)
88+
indexend = halfn - 1 + i
89+
list_start = k
90+
list_end = k + 3
91+
92+
if list_start > 16 || list_end > 16
93+
k = 1
94+
list_start = 1
95+
list_end = 4
96+
end
97+
B[j, j], B[j, indexend], B[indexend, j], B[indexend, indexend] = B_list[list_start:list_end]
98+
j = j + 1
99+
k = k + 4
100+
end
101+
A = P' * B * P
102+
end
103+
104+
return new{T}(n, a, b, A)
105+
end
106+
end
107+
108+
# constructors
109+
Rosser(n::Integer) = Rosser(n, rand(1:5), rand(1:5))
110+
Rosser(n::Integer, a::T, b::T) where {T<:Number} = Rosser{T}(n, a, b)
111+
Rosser{T}(n::Integer) where {T<:Number} = Rosser{T}(n, T(rand(1:5)), T(rand(1:5)))
112+
113+
# metadata
114+
@properties Rosser [:illcond, :eigen, :random]
115+
116+
# properties
117+
size(A::Rosser) = (A.n, A.n)
118+
119+
# functions
120+
@inline Base.@propagate_inbounds function getindex(A::Rosser{T}, i::Integer, j::Integer) where {T}
121+
@boundscheck checkbounds(A, i, j)
122+
return A.M[i, j]
123+
end

0 commit comments

Comments
 (0)