@@ -3,17 +3,87 @@ struct BlockMap{T,As<:Tuple{Vararg{LinearMap}},Rs<:Tuple{Vararg{Int}},Rranges<:T
3
3
rows:: Rs
4
4
rowranges:: Rranges
5
5
colranges:: Cranges
6
+ # Store BlockMap size explicitly, to allow south-east corner to be
7
+ # empty.
8
+ M:: Int
9
+ N:: Int
10
+
6
11
function BlockMap {T,R,S} (maps:: R , rows:: S ) where {T, R<: Tuple{Vararg{LinearMap}} , S<: Tuple{Vararg{Int}} }
7
12
for A in maps
8
13
promote_type (T, eltype (A)) == T || throw (InexactError ())
9
14
end
10
15
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)
12
18
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)
13
23
end
14
24
15
25
BlockMap {T} (maps:: As , rows:: S ) where {T,As<: Tuple{Vararg{LinearMap}} ,S} = BlockMap {T,As,S} (maps, rows)
16
26
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
+
17
87
MulStyle (A:: BlockMap ) = MulStyle (A. maps... )
18
88
19
89
function check_dim (A:: LinearMap , dim, n)
@@ -49,7 +119,7 @@ function rowcolranges(maps, rows)
49
119
return rowranges:: NTuple{length(rows), UnitRange{Int}} , colranges:: NTuple{length(maps), UnitRange{Int}}
50
120
end
51
121
52
- Base. size (A:: BlockMap ) = (last ( last (A . rowranges)), last ( last (A . colranges)) )
122
+ Base. size (A:: BlockMap ) = (A . M, A . N )
53
123
54
124
# ###########
55
125
# concatenation
@@ -306,6 +376,7 @@ LinearAlgebra.adjoint(A::BlockMap) = AdjointMap(A)
306
376
maps, rows, yinds, xinds = A. maps, A. rows, A. rowranges, A. colranges
307
377
mapind = 0
308
378
@views @inbounds for (row, yi) in zip (rows, yinds)
379
+ iszero (row) && continue
309
380
yrow = selectdim (y, 1 , yi)
310
381
mapind += 1
311
382
mul! (yrow, maps[mapind], selectdim (x, 1 , xinds[mapind]), α, β)
@@ -377,6 +448,29 @@ for Atype in (AbstractVector, AbstractMatrix)
377
448
end
378
449
end
379
450
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
+
380
474
# ###########
381
475
# show methods
382
476
# ###########
0 commit comments