@@ -8,211 +8,140 @@ function MatrixAlgebraKit.default_lq_algorithm(
8
8
end
9
9
end
10
10
11
- function similar_output (
12
- :: typeof (lq_compact!), A, L_axis, alg:: MatrixAlgebraKit.AbstractAlgorithm
13
- )
14
- L = similar (A, axes (A, 1 ), L_axis)
15
- Q = similar (A, L_axis, axes (A, 2 ))
16
- return L, Q
11
+ function output_type (
12
+ f:: Union{typeof(lq_compact!),typeof(lq_full!)} , A:: Type{<:AbstractMatrix{T}}
13
+ ) where {T}
14
+ LQ = Base. promote_op (f, A)
15
+ return isconcretetype (LQ) ? LQ : Tuple{AbstractMatrix{T},AbstractMatrix{T}}
17
16
end
18
17
19
- function similar_output (
20
- :: typeof (lq_full !), A, L_axis, alg :: MatrixAlgebraKit.AbstractAlgorithm
18
+ function MatrixAlgebraKit . initialize_output (
19
+ :: typeof (lq_compact !), :: AbstractBlockSparseMatrix , :: BlockPermutedDiagonalAlgorithm
21
20
)
22
- L = similar (A, axes (A, 1 ), L_axis)
23
- Q = similar (A, L_axis, axes (A, 2 ))
24
- return L, Q
21
+ return nothing
25
22
end
26
-
27
23
function MatrixAlgebraKit. initialize_output (
28
- :: typeof (lq_compact!), A:: AbstractBlockSparseMatrix , alg:: BlockPermutedDiagonalAlgorithm
24
+ :: typeof (lq_compact!), A:: AbstractBlockSparseMatrix , alg:: BlockDiagonalAlgorithm
29
25
)
30
- bm, bn = blocksize (A)
31
- bmn = min (bm, bn)
32
-
33
26
brows = eachblockaxis (axes (A, 1 ))
34
27
bcols = eachblockaxis (axes (A, 2 ))
35
- l_axes = similar (brows, bmn)
36
-
37
- # fill in values for blocks that are present
38
- bIs = collect (eachblockstoredindex (A))
39
- browIs = Int .(first .(Tuple .(bIs)))
40
- bcolIs = Int .(last .(Tuple .(bIs)))
41
- for bI in eachblockstoredindex (A)
42
- row, col = Int .(Tuple (bI))
43
- len = minimum (length, (brows[row], bcols[col]))
44
- l_axes[row] = bcols[col][Base. OneTo (len)]
45
- end
46
-
47
- # fill in values for blocks that aren't present, pairing them in order of occurence
48
- # this is a convention, which at least gives the expected results for blockdiagonal
49
- emptyrows = setdiff (1 : bm, browIs)
50
- emptycols = setdiff (1 : bn, bcolIs)
51
- for (row, col) in zip (emptyrows, emptycols)
52
- len = minimum (length, (brows[row], bcols[col]))
53
- l_axes[row] = bcols[col][Base. OneTo (len)]
54
- end
55
-
28
+ # using the property that zip stops as soon as one of the iterators is exhausted
29
+ l_axes = map (splat (infimum), zip (brows, bcols))
56
30
l_axis = mortar_axis (l_axes)
57
- L, Q = similar_output (lq_compact!, A, l_axis, alg)
58
31
59
- # allocate output
60
- for bI in eachblockstoredindex (A)
61
- brow, bcol = Tuple (bI)
62
- block = @view! (A[bI])
63
- block_alg = block_algorithm (alg, block)
64
- L[brow, brow], Q[brow, bcol] = MatrixAlgebraKit. initialize_output (
65
- lq_compact!, block, block_alg
66
- )
67
- end
68
-
69
- # allocate output for blocks that aren't present -- do we also fill identities here?
70
- for (row, col) in zip (emptyrows, emptycols)
71
- @view! (Q[Block (row, col)])
72
- end
32
+ BL, BQ = fieldtypes (output_type (lq_compact!, blocktype (A)))
33
+ L = similar (A, BlockType (BL), (axes (A, 1 ), l_axis))
34
+ Q = similar (A, BlockType (BQ), (l_axis, axes (A, 2 )))
73
35
74
36
return L, Q
75
37
end
76
38
77
39
function MatrixAlgebraKit. initialize_output (
78
- :: typeof (lq_full!), A :: AbstractBlockSparseMatrix , alg :: BlockPermutedDiagonalAlgorithm
40
+ :: typeof (lq_full!), :: AbstractBlockSparseMatrix , :: BlockPermutedDiagonalAlgorithm
79
41
)
80
- bm, bn = blocksize (A)
81
-
82
- bcols = eachblockaxis (axes (A, 2 ))
83
- l_axes = copy (bcols)
84
-
85
- # fill in values for blocks that are present
86
- bIs = collect (eachblockstoredindex (A))
87
- browIs = Int .(first .(Tuple .(bIs)))
88
- bcolIs = Int .(last .(Tuple .(bIs)))
89
- for bI in eachblockstoredindex (A)
90
- row, col = Int .(Tuple (bI))
91
- l_axes[row] = bcols[col]
92
- end
93
-
94
- # fill in values for blocks that aren't present, pairing them in order of occurence
95
- # this is a convention, which at least gives the expected results for blockdiagonal
96
- emptyrows = setdiff (1 : bm, browIs)
97
- emptycols = setdiff (1 : bn, bcolIs)
98
- for (row, col) in zip (emptyrows, emptycols)
99
- l_axes[row] = bcols[col]
100
- end
101
- for (i, k) in enumerate ((length (emptycols) + 1 ): length (emptyrows))
102
- l_axes[bn + i] = bcols[emptycols[k]]
103
- end
104
-
105
- l_axis = mortar_axis (l_axes)
106
- L, Q = similar_output (lq_full!, A, l_axis, alg)
107
-
108
- # allocate output
109
- for bI in eachblockstoredindex (A)
110
- brow, bcol = Tuple (bI)
111
- block = @view! (A[bI])
112
- block_alg = block_algorithm (alg, block)
113
- L[brow, brow], Q[brow, bcol] = MatrixAlgebraKit. initialize_output (
114
- lq_full!, block, block_alg
115
- )
116
- end
117
-
118
- # allocate output for blocks that aren't present -- do we also fill identities here?
119
- for (row, col) in zip (emptyrows, emptycols)
120
- @view! (Q[Block (row, col)])
121
- end
122
- # also handle extra rows/cols
123
- for (i, k) in enumerate ((length (emptyrows) + 1 ): length (emptycols))
124
- @view! (Q[Block (bm + i, emptycols[k])])
125
- end
126
-
42
+ return nothing
43
+ end
44
+ function MatrixAlgebraKit. initialize_output (
45
+ :: typeof (lq_full!), A:: AbstractBlockSparseMatrix , alg:: BlockDiagonalAlgorithm
46
+ )
47
+ BL, BQ = fieldtypes (output_type (lq_full!, blocktype (A)))
48
+ L = similar (A, BlockType (BL), (axes (A, 1 ), axes (A, 2 )))
49
+ Q = similar (A, BlockType (BQ), (axes (A, 2 ), axes (A, 2 )))
127
50
return L, Q
128
51
end
129
52
130
53
function MatrixAlgebraKit. check_input (
131
- :: typeof (lq_compact!), A:: AbstractBlockSparseMatrix , LQ
54
+ :: typeof (lq_compact!), A:: AbstractBlockSparseMatrix , LQ, :: BlockPermutedDiagonalAlgorithm
55
+ )
56
+ @assert isblockpermuteddiagonal (A)
57
+ return nothing
58
+ end
59
+ function MatrixAlgebraKit. check_input (
60
+ :: typeof (lq_compact!), A:: AbstractBlockSparseMatrix , (L, Q), :: BlockDiagonalAlgorithm
132
61
)
133
- L, Q = LQ
134
62
@assert isa (L, AbstractBlockSparseMatrix) && isa (Q, AbstractBlockSparseMatrix)
135
63
@assert eltype (A) == eltype (L) == eltype (Q)
136
64
@assert axes (A, 1 ) == axes (L, 1 ) && axes (A, 2 ) == axes (Q, 2 )
137
65
@assert axes (L, 2 ) == axes (Q, 1 )
138
-
66
+ @assert isblockdiagonal (A)
139
67
return nothing
140
68
end
141
-
142
- function MatrixAlgebraKit. check_input (:: typeof (lq_full!), A:: AbstractBlockSparseMatrix , LQ)
143
- L, Q = LQ
69
+ function MatrixAlgebraKit. check_input (
70
+ :: typeof (lq_full!), A:: AbstractBlockSparseMatrix , LQ, :: BlockPermutedDiagonalAlgorithm
71
+ )
72
+ @assert isblockpermuteddiagonal (A)
73
+ return nothing
74
+ end
75
+ function MatrixAlgebraKit. check_input (
76
+ :: typeof (lq_full!), A:: AbstractBlockSparseMatrix , (L, Q), :: BlockDiagonalAlgorithm
77
+ )
144
78
@assert isa (L, AbstractBlockSparseMatrix) && isa (Q, AbstractBlockSparseMatrix)
145
79
@assert eltype (A) == eltype (L) == eltype (Q)
146
80
@assert axes (A, 1 ) == axes (L, 1 ) && axes (A, 2 ) == axes (Q, 2 )
147
81
@assert axes (L, 2 ) == axes (Q, 1 )
148
-
82
+ @assert isblockdiagonal (A)
149
83
return nothing
150
84
end
151
85
152
86
function MatrixAlgebraKit. lq_compact! (
153
87
A:: AbstractBlockSparseMatrix , LQ, alg:: BlockPermutedDiagonalAlgorithm
154
88
)
155
- MatrixAlgebraKit. check_input (lq_compact!, A, LQ)
156
- L, Q = LQ
89
+ MatrixAlgebraKit. check_input (lq_compact!, A, LQ, alg)
90
+ Ad, transform_rows, transform_cols = blockdiagonalize (A)
91
+ Ld, Qd = lq_compact! (Ad, BlockDiagonalAlgorithm (alg))
92
+ L = transform_rows (Ld)
93
+ Q = transform_cols (Qd)
94
+ return L, Q
95
+ end
96
+ function MatrixAlgebraKit. lq_compact! (
97
+ A:: AbstractBlockSparseMatrix , (L, Q), alg:: BlockDiagonalAlgorithm
98
+ )
99
+ MatrixAlgebraKit. check_input (lq_compact!, A, (L, Q), alg)
157
100
158
101
# do decomposition on each block
159
- for bI in eachblockstoredindex (A)
160
- brow, bcol = Tuple (bI)
161
- lq = (@view! (L[brow, brow]), @view! (Q[brow, bcol]))
162
- block = @view! (A[bI])
163
- block_alg = block_algorithm (alg, block)
164
- lq′ = lq_compact! (block, lq, block_alg)
165
- @assert lq === lq′ " lq_compact! might not be in-place"
166
- end
167
-
168
- # fill in identities for blocks that aren't present
169
- bIs = collect (eachblockstoredindex (A))
170
- browIs = Int .(first .(Tuple .(bIs)))
171
- bcolIs = Int .(last .(Tuple .(bIs)))
172
- emptyrows = setdiff (1 : blocksize (A, 1 ), browIs)
173
- emptycols = setdiff (1 : blocksize (A, 2 ), bcolIs)
174
- # needs copyto! instead because size(::LinearAlgebra.I) doesn't work
175
- # Q[Block(row, col)] = LinearAlgebra.I
176
- for (row, col) in zip (emptyrows, emptycols)
177
- copyto! (@view! (Q[Block (row, col)]), LinearAlgebra. I)
102
+ for I in 1 : min (blocksize (A)... )
103
+ bI = Block (I, I)
104
+ if isstored (blocks (A), CartesianIndex (I, I)) # TODO : isblockstored
105
+ block = @view! (A[bI])
106
+ block_alg = block_algorithm (alg, block)
107
+ bL, bQ = lq_compact! (block, block_alg)
108
+ L[bI] = bL
109
+ Q[bI] = bQ
110
+ else
111
+ copyto! (@view! (Q[bI]), LinearAlgebra. I)
112
+ end
178
113
end
179
114
180
- return LQ
115
+ return L, Q
181
116
end
182
117
183
118
function MatrixAlgebraKit. lq_full! (
184
119
A:: AbstractBlockSparseMatrix , LQ, alg:: BlockPermutedDiagonalAlgorithm
185
120
)
186
- MatrixAlgebraKit. check_input (lq_full!, A, LQ)
187
- L, Q = LQ
188
-
189
- # do decomposition on each block
190
- for bI in eachblockstoredindex (A)
191
- brow, bcol = Tuple (bI)
192
- lq = (@view! (L[brow, brow]), @view! (Q[brow, bcol]))
193
- block = @view! (A[bI])
194
- block_alg = block_algorithm (alg, block)
195
- lq′ = lq_full! (block, lq, block_alg)
196
- @assert lq === lq′ " lq_full! might not be in-place"
197
- end
198
-
199
- # fill in identities for blocks that aren't present
200
- bIs = collect (eachblockstoredindex (A))
201
- browIs = Int .(first .(Tuple .(bIs)))
202
- bcolIs = Int .(last .(Tuple .(bIs)))
203
- emptyrows = setdiff (1 : blocksize (A, 1 ), browIs)
204
- emptycols = setdiff (1 : blocksize (A, 2 ), bcolIs)
205
- # needs copyto! instead because size(::LinearAlgebra.I) doesn't work
206
- # Q[Block(row, col)] = LinearAlgebra.I
207
- for (row, col) in zip (emptyrows, emptycols)
208
- copyto! (@view! (Q[Block (row, col)]), LinearAlgebra. I)
209
- end
121
+ MatrixAlgebraKit. check_input (lq_full!, A, LQ, alg)
122
+ Ad, transform_rows, transform_cols = blockdiagonalize (A)
123
+ Ld, Qd = lq_full! (Ad, BlockDiagonalAlgorithm (alg))
124
+ L = transform_rows (Ld)
125
+ Q = transform_cols (Qd)
126
+ return L, Q
127
+ end
128
+ function MatrixAlgebraKit. lq_full! (
129
+ A:: AbstractBlockSparseMatrix , (L, Q), alg:: BlockDiagonalAlgorithm
130
+ )
131
+ MatrixAlgebraKit. check_input (lq_full!, A, (L, Q), alg)
210
132
211
- # also handle extra rows/cols
212
- bm = blocksize (A, 1 )
213
- for (i, k) in enumerate ((length (emptyrows) + 1 ): length (emptycols))
214
- copyto! (@view! (Q[Block (bm + i, emptycols[k])]), LinearAlgebra. I)
133
+ for I in 1 : min (blocksize (A)... )
134
+ bI = Block (I, I)
135
+ if isstored (blocks (A), CartesianIndex (I, I)) # TODO : isblockstored
136
+ block = @view! (A[bI])
137
+ block_alg = block_algorithm (alg, block)
138
+ bL, bQ = lq_full! (block, block_alg)
139
+ L[bI] = bL
140
+ Q[bI] = bQ
141
+ else
142
+ copyto! (@view! (Q[bI]), LinearAlgebra. I)
143
+ end
215
144
end
216
145
217
- return LQ
146
+ return L, Q
218
147
end
0 commit comments