11"""
2- ModalInterlace
2+ ModalTrav(A::AbstractMatrix)
3+
4+ takes coefficients as provided by the Zernike polynomial layout of FastTransforms.jl and
5+ makes them accessible sorted such that in each block the m=0 entries are always in first place,
6+ followed by alternating sin and cos terms of increasing |m|.
7+ """
8+ struct ModalTrav{T, AA<: AbstractMatrix{T} } <: AbstractBlockVector{T}
9+ matrix:: AA
10+ function ModalTrav {T, AA} (matrix:: AA ) where {T,AA<: AbstractMatrix{T} }
11+ m,n = size (matrix)
12+ if isfinite (m)
13+ isfinite (n) && isodd (n) && m == n ÷ 4 + 1 || throw (ArgumentError (" size must match" ))
14+ end
15+ new {T,AA} (matrix)
16+ end
17+ end
18+
19+ ModalTrav {T} (matrix:: AbstractMatrix{T} ) where T = ModalTrav {T,typeof(matrix)} (matrix)
20+ ModalTrav (matrix:: AbstractMatrix{T} ) where T = ModalTrav {T} (matrix)
21+
22+ function ModalTrav {T} (:: UndefInitializer , n:: Int ) where T
23+ N = (isqrt (8 n+ 1 )- 1 ) ÷ 2
24+ @assert sum (1 : N) == n
25+ m = N ÷ 2 + 1
26+ n = 4 (m- 1 ) + 1
27+ ModalTrav (Matrix {T} (undef, m, n))
28+ end
29+
30+ convert (:: Type{ModalTrav{T,M}} , v:: ModalTrav ) where {T,M} = ModalTrav {T,M} (convert (M, v. matrix))
31+
32+ function convert (:: Type{ModalTrav{T,M}} , v_in:: AbstractVector ) where {T,M}
33+ N = (isqrt (8 length (v_in)+ 1 )- 1 ) ÷ 2
34+ v = PseudoBlockVector (v_in, OneTo (N))
35+ m = N ÷ 2 + 1
36+ n = 4 (m- 1 ) + 1
37+ mat = zeros (T, m, n)
38+ for K in blockaxes (v,1 )
39+ K̃ = Int (K)
40+ w = v[K]
41+ if isodd (K̃)
42+ mat[K̃÷ 2 + 1 ,1 ] = w[1 ]
43+ for j = 2 : 2 : K̃- 1
44+ mat[K̃÷ 2 - j÷ 2 + 1 ,2 (j- 1 )+ 2 ] = w[j]
45+ mat[K̃÷ 2 - j÷ 2 + 1 ,2 (j- 1 )+ 3 ] = w[j+ 1 ]
46+ end
47+ else
48+ for j = 1 : 2 : K̃
49+ mat[K̃÷ 2 - j÷ 2 ,2 (j- 1 )+ 2 ] = w[j]
50+ mat[K̃÷ 2 - j÷ 2 ,2 (j- 1 )+ 3 ] = w[j+ 1 ]
51+ end
52+ end
53+ end
54+ ModalTrav {T,M} (mat)
55+ end
56+
57+ ModalTrav {T,M} (v:: AbstractVector ) where {T,M} = convert (ModalTrav{T,M}, v)
58+ ModalTrav {T} (v:: AbstractVector ) where T = ModalTrav {T,Matrix{T}} (v)
59+ ModalTrav (v:: AbstractVector{T} ) where T = ModalTrav {T} (v)
60+
61+ copy (A:: ModalTrav ) = ModalTrav (copy (A. matrix))
62+
63+ _diviffinite (n) = div (n,2 ,RoundUp)
64+ _diviffinite (n:: InfiniteCardinal ) = n
65+
66+ axes (A:: ModalTrav ) = (blockedrange (oneto (_diviffinite (size (A. matrix,2 )))),)
67+
68+ getindex (A:: ModalTrav , K:: Block{1} ) = _modaltravgetindex (A. matrix, K)
69+
70+ _modaltravgetindex (mat, K) = _modaltravgetindex (MemoryLayout (mat), mat, K)
71+ function _modaltravgetindex (_, mat, K:: Block{1} )
72+ k = Int (K)
73+ m = k ÷ 2 + 1
74+ n = 4 (m- 1 ) + 1
75+ _modaltravgetindex (Matrix (mat[1 : m, 1 : n]), K)
76+ end
77+
78+ function _modaltravgetindex (:: AbstractStridedLayout , mat, K:: Block{1} )
79+ k = Int (K)
80+ k == 1 && return mat[1 : 1 ]
81+ k == 2 && return mat[1 ,2 : 3 ]
82+ st = stride (mat,2 )
83+ if isodd (k)
84+ # nonnegative terms
85+ p = mat[range (k÷ 2 + 1 , step= 4 * st- 1 , length= k÷ 2 + 1 )]
86+ # negative terms
87+ n = mat[range (k÷ 2 + 3 * st, step= 4 * st- 1 , length= k÷ 2 )]
88+ interlace (p,n)
89+ else
90+ # negative terms
91+ n = mat[range (st+ k÷ 2 , step= 4 * st- 1 , length= k÷ 2 )]
92+ # positive terms
93+ p = mat[range (2 st+ k÷ 2 , step= 4 * st- 1 , length= k÷ 2 )]
94+ interlace (n,p)
95+ end
96+ end
97+
98+ getindex (A:: ModalTrav , k:: Int ) = A[findblockindex (axes (A,1 ), k)]
99+ function setindex! (A:: ModalTrav , v, k:: Int )
100+ Kk = findblockindex (axes (A,1 ), k)
101+ K,j = block (Kk),blockindex (Kk)
102+ K̃ = Int (K)
103+ mat = A. matrix
104+ if isodd (K̃)
105+ if j == 1
106+ mat[K̃÷ 2 + 1 ,1 ] = v
107+ elseif iseven (j)
108+ mat[K̃÷ 2 - j÷ 2 + 1 ,2 (j- 1 )+ 2 ] = v
109+ else
110+ mat[K̃÷ 2 - (j- 1 )÷ 2 + 1 ,2 (j- 2 )+ 3 ] = v
111+ end
112+ else
113+ if iseven (j)
114+ mat[K̃÷ 2 - (j- 1 )÷ 2 ,2 (j- 2 )+ 3 ] = v
115+ else
116+ mat[K̃÷ 2 - j÷ 2 ,2 (j- 1 )+ 2 ] = v
117+ end
118+ end
119+ A
120+ end
121+
122+ similar (A:: ModalTrav , :: Type{T} ) where T = ModalTrav (similar (A. matrix, T))
123+ function fill! (A:: ModalTrav , x)
124+ fill! (A. matrix, x)
125+ A
126+ end
127+
128+ struct ModalTravStyle <: AbstractBlockStyle{1} end
129+
130+ ModalTravStyle (:: Val{1} ) = ModalTravStyle ()
131+
132+ BroadcastStyle (:: Type{<:ModalTrav} ) = ModalTravStyle ()
133+ BroadcastStyle (a:: ModalTravStyle , b:: DefaultArrayStyle{0} ) = ModalTravStyle ()
134+ BroadcastStyle (a:: DefaultArrayStyle{0} , b:: ModalTravStyle ) = ModalTravStyle ()
135+ BroadcastStyle (a:: ModalTravStyle , b:: DefaultArrayStyle{M} ) where {M} = BroadcastStyle (BlockStyle {1} (), b)
136+ BroadcastStyle (a:: DefaultArrayStyle{M} , b:: ModalTravStyle ) where {M} = BroadcastStyle (a, BlockStyle {1} ())
137+
138+ function similar (bc:: Broadcasted{ModalTravStyle} , :: Type{T} ) where T
139+ N = blocklength (axes (bc,1 ))
140+ n = 2 N- 1
141+ m = n ÷ 4 + 1
142+ ModalTrav (Matrix {T} (undef,m,n))
143+ end
144+
145+ _modal2matrix (a:: ModalTrav ) = a. matrix
146+ _modal2matrix (a:: Broadcasted ) = broadcasted (a. f, map (_modal2matrix, a. args)... )
147+ _modal2matrix (a) = a
148+
149+ function copyto! (dest:: ModalTrav , bc:: Broadcasted{ModalTravStyle} )
150+ broadcast! (bc. f, dest. matrix, map (_modal2matrix, bc. args)... )
151+ dest
152+ end
153+
154+ function resize! (a:: ModalTrav , N:: Block{1} )
155+ n = 2 Int (N)- 1
156+ m = n ÷ 4 + 1
157+ ModalTrav (a. matrix[1 : m,1 : n])
158+ end
159+
160+
161+ """
162+ ModalInterlace(ops, (M,N), (l,u))
163+
164+ interlaces the entries of a vector of banded matrices
165+ acting on the different Fourier modes. That is, a ModalInterlace
166+ multiplying a DiagTrav is the same as the operators multiplying the matrix
167+ that the DiagTrav wraps. We assume the same operator acts on the Sin and Cos.
3168"""
4169struct ModalInterlace{T, MMNN<: Tuple } <: AbstractBandedBlockBandedMatrix{T}
5170 ops
@@ -8,7 +173,7 @@ struct ModalInterlace{T, MMNN<:Tuple} <: AbstractBandedBlockBandedMatrix{T}
8173end
9174
10175ModalInterlace {T} (ops, MN:: NTuple{2,Integer} , bandwidths:: NTuple{2,Int} ) where T = ModalInterlace {T,typeof(MN)} (ops, MN, bandwidths)
11- ModalInterlace (ops:: AbstractVector{<:AbstractMatrix{T}} , MN:: NTuple{2,Integer} , bandwidths:: NTuple{2,Int} ) where T = ModalInterlace {T } (ops, MN, bandwidths)
176+ ModalInterlace (ops:: AbstractVector{<:AbstractMatrix} , MN:: NTuple{2,Integer} , bandwidths:: NTuple{2,Int} ) = ModalInterlace {eltype(eltype(ops)) } (ops, MN, bandwidths)
12177
13178axes (Z:: ModalInterlace ) = blockedrange .(oneto .(Z. MN))
14179
@@ -52,8 +217,36 @@ function sub_materialize(::ModalInterlaceLayout, V::AbstractMatrix{T}) where T
52217 KR,JR = kr. block,jr. block
53218 M,N = Int (last (KR)), Int (last (JR))
54219 R = parent (V)
55- ModalInterlace {T} ([R. ops[m][ 1 : (M- m+ 2 )÷ 2 ,1 : (N- m+ 2 )÷ 2 ] for m= 1 : min (N,M)], (M,N), R. bandwidths)
220+ ModalInterlace {T} ([layout_getindex ( R. ops[m], 1 : (M- m+ 2 )÷ 2 ,1 : (N- m+ 2 )÷ 2 ) for m= 1 : min (N,M)], (M,N), R. bandwidths)
56221end
57222
58223# act like lazy array
59- Base. BroadcastStyle (:: Type {<: ModalInterlace{<:Any,NTuple{2,InfiniteCardinal{0}}} }) = LazyArrayStyle {2} ()
224+ BroadcastStyle (:: Type {<: ModalInterlace{<:Any,NTuple{2,InfiniteCardinal{0}}} }) = LazyArrayStyle {2} ()
225+
226+ # TODO : overload muladd!
227+ function * (A:: ModalInterlace , b:: ModalTrav )
228+ M = b. matrix
229+ ret = ModalTrav {promote_type(eltype(A), eltype(b))} (undef, size (A,1 )). matrix
230+ mul! (view (ret,:,1 ), A. ops[1 ], M[:,1 ])
231+ for j = 1 : size (ret,2 )÷ 4
232+ mul! (@view (ret[1 : end - j,4 j- 2 ]), A. ops[2 j], @view (M[1 : end - j,4 j- 2 ]))
233+ mul! (@view (ret[1 : end - j,4 j- 1 ]), A. ops[2 j], @view (M[1 : end - j,4 j- 1 ]))
234+ mul! (@view (ret[1 : end - j,4 j]), A. ops[2 j+ 1 ], @view (M[1 : end - j,4 j]))
235+ mul! (@view (ret[1 : end - j,4 j+ 1 ]), A. ops[2 j+ 1 ], @view (M[1 : end - j,4 j+ 1 ]))
236+ end
237+ ModalTrav (ret)
238+ end
239+
240+
241+ function \ (A:: ModalInterlace , b:: ModalTrav )
242+ M = b. matrix
243+ ret = similar (M, promote_type (eltype (A),eltype (b)))
244+ ldiv! (view (ret,:,1 ), A. ops[1 ], M[:,1 ])
245+ for j = 1 : size (M,2 )÷ 4
246+ ldiv! (@view (ret[1 : end - j,4 j- 2 ]), A. ops[2 j], @view (M[1 : end - j,4 j- 2 ]))
247+ ldiv! (@view (ret[1 : end - j,4 j- 1 ]), A. ops[2 j], @view (M[1 : end - j,4 j- 1 ]))
248+ ldiv! (@view (ret[1 : end - j,4 j]), A. ops[2 j+ 1 ], @view (M[1 : end - j,4 j]))
249+ ldiv! (@view (ret[1 : end - j,4 j+ 1 ]), A. ops[2 j+ 1 ], @view (M[1 : end - j,4 j+ 1 ]))
250+ end
251+ ModalTrav (ret)
252+ end
0 commit comments