11using StaticArrays, Test, LinearAlgebra, Random
22
3+ macro test_noalloc (ex)
4+ esc (quote
5+ $ ex
6+ @test (@allocated ($ ex) == 0 )
7+ end )
8+ end
9+
310broadenrandn (:: Type{BigFloat} ) = BigFloat (randn (Float64))
411broadenrandn (:: Type{Int} ) = rand (- 9 : 9 )
512broadenrandn (:: Type{Complex{T}} ) where T = Complex {T} (broadenrandn (T), broadenrandn (T))
613broadenrandn (:: Type{T} ) where T = randn (T)
714
815Random. seed! (42 )
9- @testset " QR decomposition" begin
16+ false && @testset " QR decomposition" begin
1017 function test_qr (arr)
1118
1219 T = eltype (arr)
@@ -69,10 +76,147 @@ Random.seed!(42)
6976 end
7077end
7178
79+
7280@testset " QR method ambiguity" begin
7381 # Issue #931; just test that methods do not throw an ambiguity error when called
7482 A = @SMatrix [1.0 2.0 3.0 ; 4.0 5.0 6.0 ]
7583 @test isa (qr (A), StaticArrays. QR)
7684 @test isa (qr (A, Val (true )), StaticArrays. QR)
7785 @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