@@ -156,13 +156,12 @@ _grid(::WeightedBasisLayouts, P) = grid(unweighted(P))
156156grid (P) = _grid (MemoryLayout (P), P)
157157
158158
159- struct TransformFactorization{T,Grid,Plan,IPlan } <: Factorization{T}
159+ struct TransformFactorization{T,Grid,Plan} <: Factorization{T}
160160 grid:: Grid
161161 plan:: Plan
162- iplan:: IPlan
163162end
164163
165- TransformFactorization {T} (grid, plan) where T = TransformFactorization {T,typeof(grid),typeof(plan),Nothing } (grid, plan, nothing )
164+ TransformFactorization {T} (grid, plan) where T = TransformFactorization {T,typeof(grid),typeof(plan)} (grid, plan)
166165
167166"""
168167 TransformFactorization(grid, plan)
@@ -173,44 +172,84 @@ associates a planned transform with a grid. That is, if `F` is a `TransformFacto
173172TransformFactorization (grid, plan) = TransformFactorization {promote_type(eltype(eltype(grid)),eltype(plan))} (grid, plan)
174173
175174
176- TransformFactorization {T} (grid, :: Nothing , iplan) where T = TransformFactorization {T,typeof(grid),Nothing,typeof(iplan)} (grid, nothing , iplan)
177-
178- """
179- TransformFactorization(grid, nothing, iplan)
180-
181- associates a planned inverse transform with a grid. That is, if `F` is a `TransformFactorization`, then
182- `F \\ f` is equivalent to `F.iplan \\ f[F.grid]`.
183- """
184- TransformFactorization (grid, :: Nothing , iplan) = TransformFactorization {promote_type(eltype(eltype(grid)),eltype(iplan))} (grid, nothing , iplan)
185175
186176grid (T:: TransformFactorization ) = T. grid
187177function size (T:: TransformFactorization , k)
188178 @assert k == 2 # TODO : make consistent
189179 size (T. plan,1 )
190180end
191181
192- function size (T:: TransformFactorization{<:Any,<:Any,Nothing} , k)
193- @assert k == 2 # TODO : make consistent
194- size (T. iplan,2 )
182+
183+ \ (a:: TransformFactorization , b:: AbstractQuasiVector ) = a. plan * convert (Array, b[a. grid])
184+ \ (a:: TransformFactorization , b:: AbstractQuasiMatrix ) = a. plan * convert (Array, b[a. grid,:])
185+
186+ """
187+ InvPlan(factorization, dims)
188+
189+ Takes a factorization and supports it applied to different dimensions.
190+ """
191+ struct InvPlan{T, Fact, Dims} # <: Plan{T} We don't depend on AbstractFFTs
192+ factorization:: Fact
193+ dims:: Dims
195194end
196195
196+ InvPlan (fact, dims) = InvPlan {eltype(fact), typeof(fact), typeof(dims)} (fact, dims)
197197
198- \ (a:: TransformFactorization{<:Any,<:Any,Nothing} , b:: AbstractQuasiVector{T} ) where T = a. iplan \ convert (Array{T}, b[a. grid])
199- \ (a:: TransformFactorization , b:: AbstractQuasiVector ) = a. plan * convert (Array, b[a. grid])
200- \ (a:: TransformFactorization{<:Any,<:Any,Nothing} , b:: AbstractVector ) = a. iplan \ b
201- \ (a:: TransformFactorization , b:: AbstractVector ) = a. plan * b
202- ldiv! (ret:: AbstractVecOrMat , a:: TransformFactorization , b:: AbstractVecOrMat ) = mul! (ret, a. plan, b)
203- ldiv! (ret:: AbstractVecOrMat , a:: TransformFactorization{<:Any,<:Any,Nothing} , b:: AbstractVecOrMat ) = ldiv! (ret, a. iplan, b)
198+ size (F:: InvPlan , k... ) = size (F. factorization, k... )
199+
200+
201+ function * (P:: InvPlan{<:Any,<:Any,Int} , x:: AbstractVector )
202+ @assert P. dims == 1
203+ P. factorization \ x
204+ end
205+
206+ function * (P:: InvPlan{<:Any,<:Any,Int} , X:: AbstractMatrix )
207+ if P. dims == 1
208+ P. factorization \ X
209+ else
210+ @assert P. dims == 2
211+ permutedims (P. factorization \ permutedims (X))
212+ end
213+ end
204214
205- \ (a:: TransformFactorization{<:Any,<:Any,Nothing} , b:: AbstractQuasiMatrix{T} ) where T = a \ convert (Array{T}, b[a. grid,:])
206- \ (a:: TransformFactorization , b:: AbstractQuasiMatrix ) = a \ convert (Array, b[a. grid,:])
207- \ (a:: TransformFactorization , b:: AbstractMatrix ) = ldiv! (Array {promote_type(eltype(a),eltype(b))} (undef,size (a,2 ),size (b,2 )), a, b)
215+ function * (P:: InvPlan{<:Any,<:Any,Int} , X:: AbstractArray{<:Any,3} )
216+ Y = similar (X)
217+ if P. dims == 1
218+ for j in axes (X,3 )
219+ Y[:,:,j] = P. factorization \ X[:,:,j]
220+ end
221+ elseif P. dims == 2
222+ for k in axes (X,1 )
223+ Y[k,:,:] = P. factorization \ X[k,:,:]
224+ end
225+ else
226+ @assert P. dims == 3
227+ for k in axes (X,1 ), j in axes (X,2 )
228+ Y[k,j,:] = P. factorization \ X[k,j,:]
229+ end
230+ end
231+ Y
232+ end
208233
209- function _factorize (:: AbstractBasisLayout , L, dims... ; kws... )
234+ function * (P:: InvPlan , X:: AbstractArray )
235+ for d in P. dims
236+ X = InvPlan (P. factorization, d) * X
237+ end
238+ X
239+ end
240+
241+
242+ function plan_grid_transform (L, arr, dims= 1 : ndims (arr))
210243 p = grid (L)
211- TransformFactorization ( p, nothing , factorize (L[p,:]))
244+ p, InvPlan ( factorize (L[p,:]), dims )
212245end
213246
247+ plan_transform (P, arr, dims... ) = plan_grid_transform (P, arr, dims... )[2 ]
248+
249+ _factorize (:: AbstractBasisLayout , L, dims... ; kws... ) =
250+ TransformFactorization (plan_grid_transform (L, Array {eltype(L)} (undef, size (L,2 ), dims... ), 1 )... )
251+
252+
214253
215254"""
216255 ProjectionFactorization(F, inds)
225264
226265\ (a:: ProjectionFactorization , b:: AbstractQuasiVector ) = (a. F \ b)[a. inds]
227266\ (a:: ProjectionFactorization , b:: AbstractQuasiMatrix ) = (a. F \ b)[a. inds,:]
228- \ (a:: ProjectionFactorization , b:: AbstractVector ) = (a. F \ b)[a. inds]
229267
230- _factorize (:: SubBasisLayout , L, dims... ; kws... ) = ProjectionFactorization (factorize (parent (L), dims... ; kws... ), parentindices (L)[2 ])
268+
269+
270+ # if parent is finite dimensional default to its transform and project down
271+ _sub_factorize (:: Tuple{Any,Int} , (kr,jr), L, dims... ; kws... ) = ProjectionFactorization (factorize (parent (L), dims... ; kws... ), jr)
272+ _sub_factorize (:: Tuple{Any,Int} , (kr,jr):: Tuple{Any,OneTo} , L, dims... ; kws... ) = ProjectionFactorization (factorize (parent (L), dims... ; kws... ), jr)
273+
274+ # ∞-dimensional parents need to use transforms. For now we assume the size of the transform is equal to the size of the truncation
275+ _sub_factorize (:: Tuple{Any,Any} , (kr,jr):: Tuple{Any,OneTo} , L, dims... ; kws... ) =
276+ TransformFactorization (plan_grid_transform (parent (L), Array {eltype(L)} (undef, last (jr), dims... ), 1 )... )
277+
278+ # If jr is not OneTo we project
279+ _sub_factorize (:: Tuple{Any,Any} , (kr,jr), L, dims... ; kws... ) =
280+ ProjectionFactorization (factorize (parent (L)[:,OneTo (maximum (jr))]), jr)
281+
282+ _factorize (:: SubBasisLayout , L, dims... ; kws... ) = _sub_factorize (size (parent (L)), parentindices (L), L, dims... ; kws... )
231283
232284
233285"""
@@ -260,6 +312,29 @@ plan_ldiv(A, B::AbstractQuasiMatrix) = factorize(A, size(B,2))
260312transform_ldiv (A:: AbstractQuasiArray{T} , B:: AbstractQuasiArray{V} , _) where {T,V} = plan_ldiv (A, B) \ B
261313transform_ldiv (A, B) = transform_ldiv (A, B, size (A))
262314
315+
316+ """
317+ transform(A, f)
318+
319+ finds the coefficients of a function `f` expanded in a basis defined as the columns of a quasi matrix `A`.
320+ It is equivalent to
321+ ```
322+ A \\ f.(axes(A,1))
323+ ```
324+ """
325+ transform (A, f) = A \ f .(axes (A,1 ))
326+
327+ """
328+ expand(A, f)
329+
330+ expands a function `f` im a basis defined as the columns of a quasi matrix `A`.
331+ It is equivalent to
332+ ```
333+ A / A \\ f.(axes(A,1))
334+ ```
335+ """
336+ expand (A, f) = A * transform (A, f)
337+
263338copy (L:: Ldiv{<:AbstractBasisLayout} ) = transform_ldiv (L. A, L. B)
264339# TODO : redesign to use simplifiable(\, A, B)
265340copy (L:: Ldiv{<:AbstractBasisLayout,ApplyLayout{typeof(*)},<:Any,<:AbstractQuasiVector} ) = transform_ldiv (L. A, L. B)
573648__sum (:: ExpansionLayout , A, dims) = __sum (ApplyLayout {typeof(*)} (), A, dims)
574649__cumsum (:: ExpansionLayout , A, dims) = __cumsum (ApplyLayout {typeof(*)} (), A, dims)
575650
651+ include (" basisconcat.jl" )
652+ include (" basiskron.jl" )
576653include (" splines.jl" )
0 commit comments