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