@@ -3,17 +3,87 @@ struct BlockMap{T,As<:Tuple{Vararg{LinearMap}},Rs<:Tuple{Vararg{Int}},Rranges<:T
33 rows:: Rs
44 rowranges:: Rranges
55 colranges:: Cranges
6+ # Store BlockMap size explicitly, to allow south-east corner to be
7+ # empty.
8+ M:: Int
9+ N:: Int
10+
611 function BlockMap {T,R,S} (maps:: R , rows:: S ) where {T, R<: Tuple{Vararg{LinearMap}} , S<: Tuple{Vararg{Int}} }
712 for A in maps
813 promote_type (T, eltype (A)) == T || throw (InexactError ())
914 end
1015 rowranges, colranges = rowcolranges (maps, rows)
11- return new {T,R,S,typeof(rowranges),typeof(colranges)} (maps, rows, rowranges, colranges)
16+ M,N = last (last (rowranges)), last (last (colranges))
17+ return new {T,R,S,typeof(rowranges),typeof(colranges)} (maps, rows, rowranges, colranges, M, N)
1218 end
19+
20+ BlockMap {T} (maps:: As , rows:: Rs , rowranges:: Rranges , colranges:: Cranges ,
21+ M:: Integer , N:: Integer ) where {T,As,Rs,Rranges,Cranges} =
22+ new {T,As,Rs,Rranges,Cranges} (maps, rows, rowranges, colranges, M, N)
1323end
1424
1525BlockMap {T} (maps:: As , rows:: S ) where {T,As<: Tuple{Vararg{LinearMap}} ,S} = BlockMap {T,As,S} (maps, rows)
1626
27+ """
28+ BlockMap{T}(M, N, (m, n), maps, is, js)
29+
30+ Constructor for a `BlockMap` of `eltype(T)` for the case when all rows
31+ have the same column dimensions; these are specified using the vectors
32+ `m` and `n`. Only those blocks `maps` that are actually occupied need
33+ to be specified, their coordinates are given by the vectors `is` and `js`.
34+ """
35+ function BlockMap {T} (M:: Int , N:: Int , (m,n), maps, is, js) where T
36+ all (m .> 0 ) && all (n .> 0 ) ||
37+ throw (ArgumentError (" Block sizes must be positive integers" ))
38+
39+ sum (m) == M && sum (n) == N ||
40+ throw (DimensionMismatch (" Cumulative block dimensions $(sum (m)) ×$(sum (n)) do not agree with overall size $(M) ×$(N) " ))
41+
42+ allunique (zip (is, js)) ||
43+ throw (ArgumentError (" Not all block indices unique" ))
44+
45+ for (A,i,j) in zip (maps,is,js)
46+ promote_type (T, eltype (A)) == T || throw (InexactError ())
47+ 0 < i ≤ length (m) || throw (ArgumentError (" Invalid block row $(i) ∉ 1:$(length (m)) " ))
48+ 0 < j ≤ length (n) || throw (ArgumentError (" Invalid block column $(j) ∉ 1:$(length (n)) " ))
49+ size (A) == (m[i],n[j]) ||
50+ throw (DimensionMismatch (" Block of size $(size (A)) does not match size at $((i,j)) : $((m[i],n[j])) " ))
51+ end
52+
53+ # It would be nice to do just maps = map(LinearMap, maps)
54+ maps = (map (A -> A isa LinearMap ? A : LinearMap (A), maps)... ,)
55+
56+ rows = zeros (Int, length (m))
57+ colranges = ()
58+ colstarts = 1 .+ vcat (0 ,cumsum (n))
59+ for p = sortperm (collect (zip (is,js)))
60+ A,i,j = maps[p],is[p],js[p]
61+ rows[i] += 1
62+ colranges = (colranges... , colstarts[j]: colstarts[j+ 1 ]- 1 )
63+ end
64+ rows = (rows... ,)
65+
66+ rowranges = ()
67+ i = 1
68+ for (mm,r) in zip (m,rows)
69+ iprev = i
70+ i += mm
71+ rowranges = (rowranges... ,iprev: i- 1 )
72+ end
73+
74+ BlockMap {T} (maps, rows, rowranges, colranges, M, N)
75+ end
76+
77+ function Base. show (io:: IO , B:: BlockMap{T} ) where T
78+ nrows = length (B. rows)
79+ # One block in one row may actually span multiple block columns
80+ # for other rows, but it's nice to get a sense of the structure
81+ # anyway.
82+ ncols = maximum (B. rows)
83+ M,N = size (B)
84+ write (io, " $(nrows) ×$(ncols) -blocked $(M) ×$(N) BlockMap{$T }" )
85+ end
86+
1787MulStyle (A:: BlockMap ) = MulStyle (A. maps... )
1888
1989function check_dim (A:: LinearMap , dim, n)
@@ -49,7 +119,7 @@ function rowcolranges(maps, rows)
49119 return rowranges:: NTuple{length(rows), UnitRange{Int}} , colranges:: NTuple{length(maps), UnitRange{Int}}
50120end
51121
52- Base. size (A:: BlockMap ) = (last ( last (A . rowranges)), last ( last (A . colranges)) )
122+ Base. size (A:: BlockMap ) = (A . M, A . N )
53123
54124# ###########
55125# concatenation
@@ -306,6 +376,7 @@ LinearAlgebra.adjoint(A::BlockMap) = AdjointMap(A)
306376 maps, rows, yinds, xinds = A. maps, A. rows, A. rowranges, A. colranges
307377 mapind = 0
308378 @views @inbounds for (row, yi) in zip (rows, yinds)
379+ iszero (row) && continue
309380 yrow = selectdim (y, 1 , yi)
310381 mapind += 1
311382 mul! (yrow, maps[mapind], selectdim (x, 1 , xinds[mapind]), α, β)
@@ -377,6 +448,29 @@ for Atype in (AbstractVector, AbstractMatrix)
377448 end
378449end
379450
451+ # ###########
452+ # materialization into matrices
453+ # ###########
454+
455+ function materialize! (M:: MT , A:: BlockMap ) where {MT<: AbstractArray }
456+ axes (M) == axes (A) ||
457+ throw (DimensionMismatch (" Cannot materialize BlockMap of size $(size (A)) into matrix of size $(size (M)) " ))
458+
459+ M .= false
460+
461+ maps, rows, yinds, xinds = A. maps, A. rows, A. rowranges, A. colranges
462+ mapind = 0
463+ @views @inbounds for (row, yi) in zip (rows, yinds)
464+ Mrow = selectdim (M, 1 , yi)
465+ for _ in 1 : row
466+ mapind += 1
467+ copyto! (selectdim (Mrow, 2 , xinds[mapind]), convert (Matrix, maps[mapind]))
468+ end
469+ end
470+
471+ M
472+ end
473+
380474# ###########
381475# show methods
382476# ###########
0 commit comments