|
| 1 | +""" |
| 2 | +Create an almost singular `Matrix{Float64}` of size `N×N`. |
| 3 | +
|
| 4 | +The first `rank` columns are chosen randomly, followed by `N-rank` linear |
| 5 | +combinations with random weights to create an `N×N` singular matrix `S`. |
| 6 | +A noise matrix of norm `ϵ*norm(S)` is added. |
| 7 | +
|
| 8 | +The condition number of this matrix should be approximately ϵ/eps(Float64) |
| 9 | +""" |
| 10 | +function almost_singular_matrix(N, rank, ϵ) |
| 11 | + B = rand(N,rank) |
| 12 | + weights = rand(rank, N-rank) ./ rank |
| 13 | + S = [B B*weights] |
| 14 | + S = S ./ norm(S) |
| 15 | + noise = rand(N,N) |
| 16 | + S + ϵ*norm(S)/norm(noise) * noise |
| 17 | +end |
| 18 | + |
1 | 19 | @testset "Matrix inverse" begin
|
2 | 20 | @test inv(@SMatrix [2])::SMatrix ≈ @SMatrix [0.5]
|
3 | 21 | @test inv(@SMatrix [1 2; 2 1])::SMatrix ≈ [-1/3 2/3; 2/3 -1/3]
|
4 | 22 | @test inv(@SMatrix [1 2 0; 2 1 0; 0 0 1])::SMatrix ≈ [-1/3 2/3 0; 2/3 -1/3 0; 0 0 1]
|
5 |
| - m = randn(Float64, 4,4) + eye(4) # well conditioned |
6 |
| - @test inv(SMatrix{4,4}(m))::StaticMatrix ≈ inv(m) |
7 | 23 |
|
| 24 | + m = randn(Float64, 10,10) + eye(10) # well conditioned |
| 25 | + @test inv(SMatrix{10,10}(m))::StaticMatrix ≈ inv(m) |
| 26 | + |
| 27 | + |
| 28 | + # Unsigned versions |
8 | 29 | @test inv(@SMatrix [0x01 0x02; 0x02 0x01])::SMatrix ≈ [-1/3 2/3; 2/3 -1/3]
|
9 | 30 | @test inv(@SMatrix [0x01 0x02 0x00; 0x02 0x01 0x00; 0x00 0x00 0x01])::SMatrix ≈ [-1/3 2/3 0; 2/3 -1/3 0; 0 0 1]
|
10 |
| - |
| 31 | + |
11 | 32 | m = triu(randn(Float64, 4,4) + eye(4))
|
12 | 33 | @test inv(SMatrix{4,4}(m))::StaticMatrix ≈ inv(m)
|
13 | 34 | m = tril(randn(Float64, 4,4) + eye(4))
|
14 | 35 | @test inv(SMatrix{4,4}(m))::StaticMatrix ≈ inv(m)
|
15 | 36 | end
|
| 37 | + |
| 38 | + |
| 39 | +@testset "Matrix inverse 4x4" begin |
| 40 | + # A random well-conditioned matrix generated with `rand(1:10,4,4)` |
| 41 | + m = Float64[8 4 3 1; |
| 42 | + 9 1 9 8; |
| 43 | + 5 0 2 1; |
| 44 | + 7 5 7 2] |
| 45 | + sm = SMatrix{4,4}(m) |
| 46 | + @test isapprox(inv(sm)::StaticMatrix, inv(m), rtol=2e-15) |
| 47 | + |
| 48 | + # Poorly conditioned matrix; almost_singular_matrix(4, 3, 1e-7) |
| 49 | + m = [ |
| 50 | + 2.83056817904263402e-01 1.26822318692296848e-01 2.59665505365002547e-01 1.24524798964590747e-01 |
| 51 | + 4.29869029098094768e-01 2.29977256378012789e-03 4.63841570354149135e-01 1.51975221831027241e-01 |
| 52 | + 2.33883312850939995e-01 7.69469213907006122e-02 3.16525493661056589e-01 1.06181613512460249e-01 |
| 53 | + 1.63327582123091175e-01 1.70552365412100865e-01 4.55720450934200327e-01 1.23299968650232419e-01 |
| 54 | + ] |
| 55 | + sm = SMatrix{4,4}(m) |
| 56 | + @test norm(Matrix(sm*inv(sm) - eye(4))) < 10*norm(m*inv(m) - eye(4)) |
| 57 | + @test norm(Matrix(inv(sm)*sm - eye(4))) < 10*norm(inv(m)*m - eye(4)) |
| 58 | + |
| 59 | + # Poorly conditioned matrix, generated by fuzz testing with |
| 60 | + # almost_singular_matrix(N, 3, 1e-7) |
| 61 | + # Case where the 4x4 algorithm fares badly compared to Base inv |
| 62 | + m = [1.80589503332920231e-02 2.37595944073211218e-01 3.80770755039433806e-01 5.70474286930408372e-02 |
| 63 | + 2.17494123374967520e-02 2.94069278741667661e-01 2.57334651147732463e-01 4.02348559939922357e-02 |
| 64 | + 3.42945636322714076e-01 3.29329508494837497e-01 2.25635541033857107e-01 6.03912636987153917e-02 |
| 65 | + 4.77828437366344727e-01 4.86406974015710591e-01 1.95415684569693188e-01 6.74775080892497797e-02] |
| 66 | + sm = SMatrix{4,4}(m) |
| 67 | + @test_broken norm(Matrix(inv(sm)*sm - eye(4))) < 10*norm(inv(m)*m - eye(4)) |
| 68 | + @test_broken norm(Matrix(sm*inv(sm) - eye(4))) < 10*norm(m*inv(m) - eye(4)) |
| 69 | +end |
| 70 | + |
| 71 | + |
| 72 | +# Fuzz testing for inv() |
| 73 | +#= |
| 74 | +for i=1:100 |
| 75 | + N = 4 |
| 76 | + A = almost_singular_matrix(N, 3, 1e-7) |
| 77 | + SA = SMatrix{N,N}(A) |
| 78 | + SA_residual = norm(Matrix(SA*inv(SA) - eye(N))) |
| 79 | + A_residual = norm(A*inv(A) - eye(N)) |
| 80 | + if SA_residual/A_residual > 10000 |
| 81 | + @printf("%10e %.4f\n", SA_residual, SA_residual/A_residual) |
| 82 | + println("[") |
| 83 | + for i=1:4 |
| 84 | + for j=1:4 |
| 85 | + @printf("%.17e ", A[i,j]) |
| 86 | + end |
| 87 | + println() |
| 88 | + end |
| 89 | + println("]") |
| 90 | + end |
| 91 | +end |
| 92 | +=# |
0 commit comments