1
1
using BlockArrays: Block, BlockedMatrix, BlockedVector, blocks, mortar
2
2
using BlockSparseArrays:
3
- BlockSparseArray, BlockDiagonal, blockstoredlength, eachblockstoredindex
3
+ BlockSparseArrays,
4
+ BlockDiagonal,
5
+ BlockSparseArray,
6
+ BlockSparseMatrix,
7
+ blockstoredlength,
8
+ eachblockstoredindex
9
+ using LinearAlgebra: LinearAlgebra, Diagonal, hermitianpart, pinv
4
10
using MatrixAlgebraKit:
5
11
diagview,
6
12
eig_full,
@@ -22,10 +28,87 @@ using MatrixAlgebraKit:
22
28
svd_trunc,
23
29
truncrank,
24
30
trunctol
25
- using LinearAlgebra: LinearAlgebra, Diagonal, hermitianpart
26
31
using Random: Random
27
32
using StableRNGs: StableRNG
28
- using Test: @inferred , @testset , @test
33
+ using Test: @inferred , @test , @test_broken , @test_throws , @testset
34
+
35
+ @testset " Matrix functions (T=$elt )" for elt in (Float32, Float64, ComplexF64)
36
+ rng = StableRNG (123 )
37
+ a = BlockSparseMatrix {elt} (undef, [2 , 3 ], [2 , 3 ])
38
+ a[Block (1 , 1 )] = randn (rng, elt, 2 , 2 )
39
+ a[Block (2 , 2 )] = randn (rng, elt, 3 , 3 )
40
+ MATRIX_FUNCTIONS = BlockSparseArrays. MATRIX_FUNCTIONS
41
+ MATRIX_FUNCTIONS = [MATRIX_FUNCTIONS; [:inv , :pinv ]]
42
+ # Only works when real, also isn't defined in Julia 1.10.
43
+ MATRIX_FUNCTIONS = setdiff (MATRIX_FUNCTIONS, [:cbrt ])
44
+ MATRIX_FUNCTIONS_LOW_ACCURACY = [:acoth ]
45
+ for f in setdiff (MATRIX_FUNCTIONS, MATRIX_FUNCTIONS_LOW_ACCURACY)
46
+ @eval begin
47
+ fa = $ f ($ a)
48
+ @test Matrix (fa) ≈ $ f (Matrix ($ a)) rtol = √ (eps (real ($ elt)))
49
+ @test fa isa BlockSparseMatrix
50
+ @test issetequal (eachblockstoredindex (fa), [Block (1 , 1 ), Block (2 , 2 )])
51
+ end
52
+ end
53
+ for f in MATRIX_FUNCTIONS_LOW_ACCURACY
54
+ @eval begin
55
+ fa = $ f ($ a)
56
+ if ! Sys. isapple () && ($ elt <: Real )
57
+ # `acoth` appears to be broken on this matrix on Windows and Ubuntu
58
+ # for real matrices.
59
+ @test_broken Matrix (fa) ≈ $ f (Matrix ($ a)) rtol = √ eps (real ($ elt))
60
+ else
61
+ @test Matrix (fa) ≈ $ f (Matrix ($ a)) rtol = √ eps (real ($ elt))
62
+ end
63
+ @test fa isa BlockSparseMatrix
64
+ @test issetequal (eachblockstoredindex (fa), [Block (1 , 1 ), Block (2 , 2 )])
65
+ end
66
+ end
67
+
68
+ # Catch case of off-diagonal blocks.
69
+ rng = StableRNG (123 )
70
+ a = BlockSparseMatrix {elt} (undef, [2 , 3 ], [2 , 3 ])
71
+ a[Block (1 , 1 )] = randn (rng, elt, 2 , 2 )
72
+ a[Block (1 , 2 )] = randn (rng, elt, 2 , 3 )
73
+ for f in MATRIX_FUNCTIONS
74
+ @eval begin
75
+ @test_throws ArgumentError $ f ($ a)
76
+ end
77
+ end
78
+
79
+ # Missing diagonal blocks.
80
+ rng = StableRNG (123 )
81
+ a = BlockSparseMatrix {elt} (undef, [2 , 3 ], [2 , 3 ])
82
+ a[Block (2 , 2 )] = randn (rng, elt, 3 , 3 )
83
+ MATRIX_FUNCTIONS = BlockSparseArrays. MATRIX_FUNCTIONS
84
+ # These functions involve inverses so they break when there are zeros on the diagonal.
85
+ MATRIX_FUNCTIONS_SINGULAR = [
86
+ :log , :acsc , :asec , :acot , :acsch , :asech , :acoth , :csc , :cot , :csch , :coth
87
+ ]
88
+ MATRIX_FUNCTIONS = setdiff (MATRIX_FUNCTIONS, MATRIX_FUNCTIONS_SINGULAR)
89
+ # Dense version is broken for some reason, investigate.
90
+ MATRIX_FUNCTIONS = setdiff (MATRIX_FUNCTIONS, [:cbrt ])
91
+ for f in MATRIX_FUNCTIONS
92
+ @eval begin
93
+ fa = $ f ($ a)
94
+ @test Matrix (fa) ≈ $ f (Matrix ($ a)) rtol = √ (eps (real ($ elt)))
95
+ @test fa isa BlockSparseMatrix
96
+ @test issetequal (eachblockstoredindex (fa), [Block (1 , 1 ), Block (2 , 2 )])
97
+ end
98
+ end
99
+
100
+ SINGULAR_EXCEPTION = if VERSION < v " 1.11-"
101
+ # A different exception is thrown in older versions of Julia.
102
+ LinearAlgebra. LAPACKException
103
+ else
104
+ LinearAlgebra. SingularException
105
+ end
106
+ for f in setdiff (MATRIX_FUNCTIONS_SINGULAR, [:log ])
107
+ @eval begin
108
+ @test_throws $ SINGULAR_EXCEPTION $ f ($ a)
109
+ end
110
+ end
111
+ end
29
112
30
113
function test_svd (a, (U, S, Vᴴ); full= false )
31
114
# Check that the SVD is correct
0 commit comments