1
1
using StaticArrays, Test, LinearAlgebra, Random
2
2
3
+ macro test_noalloc (ex)
4
+ esc (quote
5
+ $ ex
6
+ @test (@allocated ($ ex) == 0 )
7
+ end )
8
+ end
9
+
3
10
broadenrandn (:: Type{BigFloat} ) = BigFloat (randn (Float64))
4
11
broadenrandn (:: Type{Int} ) = rand (- 9 : 9 )
5
12
broadenrandn (:: Type{Complex{T}} ) where T = Complex {T} (broadenrandn (T), broadenrandn (T))
6
13
broadenrandn (:: Type{T} ) where T = randn (T)
7
14
8
15
Random. seed! (42 )
9
- @testset " QR decomposition" begin
16
+ false && @testset " QR decomposition" begin
10
17
function test_qr (arr)
11
18
12
19
T = eltype (arr)
@@ -69,10 +76,147 @@ Random.seed!(42)
69
76
end
70
77
end
71
78
79
+
72
80
@testset " QR method ambiguity" begin
73
81
# Issue #931; just test that methods do not throw an ambiguity error when called
74
82
A = @SMatrix [1.0 2.0 3.0 ; 4.0 5.0 6.0 ]
75
83
@test isa (qr (A), StaticArrays. QR)
76
84
@test isa (qr (A, Val (true )), StaticArrays. QR)
77
85
@test isa (qr (A, Val (false )), StaticArrays. QR)
78
- end
86
+ end
87
+
88
+ @testset " invperm" begin
89
+ p = @SVector [9 ,8 ,7 ,6 ,5 ,4 ,2 ,1 ,3 ]
90
+ v = @SVector [15 ,14 ,13 ,12 ,11 ,10 ,15 ,3 ,7 ]
91
+ @test StaticArrays. is_identity_perm (p[invperm (p)])
92
+ @test v == v[p][invperm (p)]
93
+ @test_throws ArgumentError invperm (v)
94
+ expect0 = Base. JLOptions (). check_bounds != 1
95
+ # expect0 && @test_noalloc @inbounds invperm(p)
96
+
97
+ @test StaticArrays. invpivot (v, p) == v[invperm (p)]
98
+ @test_noalloc StaticArrays. invpivot (v, p)
99
+ end
100
+
101
+ @testset " #1192 QR inv, size, and \\ " begin
102
+ function test_pivot (pivot, MatrixType)
103
+ Random. seed! (42 )
104
+ A = rand (MatrixType)
105
+ n, m = size (A)
106
+ y = @SVector rand (size (A, 1 ))
107
+ Y = @SMatrix rand (n, 2 )
108
+ F = @inferred QR qr (A, pivot)
109
+ F_gold = @inferred LinearAlgebra. QRCompactWY qr (Matrix (A), pivot)
110
+
111
+ expect0 = pivot isa NoPivot || Base. JLOptions (). check_bounds != 1
112
+
113
+ @test StaticArrays. is_identity_perm (F. p) == (pivot isa NoPivot)
114
+ @test size (F) == size (A)
115
+
116
+ @testset " inv UpperTriangular StaticMatrix" begin
117
+ if m <= n
118
+ invR = @inferred StaticMatrix inv (UpperTriangular (F. R))
119
+ @test invR* F. R ≈ I (m)
120
+
121
+ expect0 && @eval @test_noalloc inv (UpperTriangular ($ F. R))
122
+ else
123
+ @test_throws DimensionMismatch inv (UpperTriangular (F. R))
124
+ end
125
+ end
126
+
127
+ @testset " qr inversion" begin
128
+ if m <= n
129
+ inv_F_gold = inv (qr (Matrix (A)))
130
+ inv_F = @inferred StaticMatrix inv (F)
131
+ @test size (inv_F) == size (inv_F_gold)
132
+ @test inv_F[1 : m,:] ≈ inv_F_gold[1 : m,:] # equal except for the nullspace
133
+ @test inv_F * A ≈ I (n)[:,1 : m]
134
+
135
+ expect0 && @eval @test_noalloc inv ($ F)
136
+ else
137
+ @test_throws DimensionMismatch inv (F)
138
+ @test_throws DimensionMismatch inv (qr (Matrix (A)))
139
+ end
140
+ end
141
+
142
+ @testset " QR \\ StaticVector" begin
143
+ if m <= n
144
+ x_gold = Matrix (A) \ Vector (y)
145
+ x = @inferred StaticVector F \ y
146
+ @test x_gold ≈ x
147
+
148
+ expect0 && @eval @test_noalloc $ F \ $ y
149
+ else
150
+ @test_throws DimensionMismatch F \ y
151
+
152
+ if pivot isa Val{false }
153
+ @test_throws DimensionMismatch F_gold \ Vector (y)
154
+ end
155
+ end
156
+ end
157
+
158
+ @testset " QR \\ StaticMatrix" begin
159
+ if m <= n
160
+ @test F \ Y ≈ A \ Y
161
+
162
+ expect0 && @eval @test_noalloc $ F \ $ Y
163
+ else
164
+ @test_throws DimensionMismatch F \ Y
165
+ end
166
+ end
167
+
168
+ @testset " ldiv!" begin
169
+ x = @MVector zeros (m)
170
+ X = @MMatrix zeros (m, size (Y, 2 ))
171
+
172
+ if m <= n
173
+ ldiv! (x, F, y)
174
+ @test x ≈ A \ y
175
+
176
+ ldiv! (X, F, Y)
177
+ @test X ≈ A \ Y
178
+
179
+ expect0 && @test_noalloc ldiv! (x, F, y)
180
+ expect0 && @test_noalloc ldiv! (X, F, Y)
181
+ else
182
+ @test_throws DimensionMismatch ldiv! (x, F, y)
183
+ @test_throws DimensionMismatch ldiv! (X, F, Y)
184
+
185
+ if pivot isa Val{false }
186
+ @test_throws DimensionMismatch ldiv! (zeros (size (x)), F_gold, Array (y))
187
+ @test_throws DimensionMismatch ldiv! (zeros (size (X)), F_gold, Array (Y))
188
+ end
189
+ end
190
+ end
191
+ end
192
+
193
+ @testset " pivot=$pivot " for pivot in [NoPivot (), ColumnNorm ()]
194
+ @testset " $label ($n ,$m )" for (label,n,m) in [
195
+ (:square ,3 ,3 ),
196
+ (:overdetermined ,6 ,3 ),
197
+ (:underdetermined ,3 ,4 )
198
+ ]
199
+ test_pivot (pivot, SMatrix{n,m,Float64})
200
+ end
201
+
202
+ @testset " performance" begin
203
+ function speed_test (n, iter)
204
+ y2 = @SVector rand (n)
205
+ A2 = @SMatrix rand (n,5 )
206
+ F2 = qr (A2, pivot)
207
+ iA = pinv (A2)
208
+
209
+ min_time_to_solve = minimum (@elapsed (A2 \ y2) for _ in 1 : iter)
210
+ min_time_to_solve_qr = minimum (@elapsed (F2 \ y2) for _ in 1 : iter)
211
+ min_time_to_solve_inv = minimum (@elapsed (iA * y2) for _ in 1 : iter)
212
+
213
+ if 1 != Base. JLOptions (). check_bounds
214
+ @test 10 min_time_to_solve_qr < min_time_to_solve
215
+ @test 2 min_time_to_solve_inv < min_time_to_solve_qr
216
+ end
217
+ end
218
+ speed_test (100 , 100 )
219
+ @test @elapsed (speed_test (100 , 100 )) < 1
220
+ end
221
+ end
222
+ end
0 commit comments