From 8d384b15aaaec34928a8f68124627937849f6530 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Mon, 12 Jun 2023 18:49:28 +0530 Subject: [PATCH 1/3] Wrap r2r plans --- Project.toml | 2 +- src/chebyshevtransform.jl | 231 ++++++++++++++++++++------------------ test/chebyshevtests.jl | 29 +++++ 3 files changed, 153 insertions(+), 109 deletions(-) diff --git a/Project.toml b/Project.toml index 2b22f02f..239fb701 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "FastTransforms" uuid = "057dd010-8810-581a-b7be-e3fc3b93f78c" -version = "0.15.3" +version = "0.16.0" [deps] AbstractFFTs = "621f4979-c628-5d54-868e-fcf4e3e8185c" diff --git a/src/chebyshevtransform.jl b/src/chebyshevtransform.jl index c77941d8..ffcfb407 100644 --- a/src/chebyshevtransform.jl +++ b/src/chebyshevtransform.jl @@ -9,41 +9,59 @@ length(P::ChebyshevPlan) = isdefined(P, :plan) ? length(P.plan) : 0 const FIRSTKIND = FFTW.REDFT10 const SECONDKIND = FFTW.REDFT00 -struct ChebyshevTransformPlan{T,kind,K,inplace,N,R} <: ChebyshevPlan{T} - plan::FFTW.r2rFFTWPlan{T,K,inplace,N,R} - ChebyshevTransformPlan{T,kind,K,inplace,N,R}(plan) where {T,kind,K,inplace,N,R} = new{T,kind,K,inplace,N,R}(plan) - ChebyshevTransformPlan{T,kind,K,inplace,N,R}() where {T,kind,K,inplace,N,R} = new{T,kind,K,inplace,N,R}() +struct ChebyshevTransformPlan{T,kind,K,inplace,N,P} <: ChebyshevPlan{T} + plan::P + function ChebyshevTransformPlan{T,kind,K,inplace,N,P}(plan::P) where {T,kind,K,inplace,N,P} + new{T,kind,K,inplace,N,P}(plan) + end + function ChebyshevTransformPlan{T,kind,K,inplace,N,P}() where {T,kind,K,inplace,N,P} + new{T,kind,K,inplace,N,P}() + end end -ChebyshevTransformPlan{T,kind}(plan::FFTW.r2rFFTWPlan{T,K,inplace,N,R}) where {T,kind,K,inplace,N,R} = - ChebyshevTransformPlan{T,kind,K,inplace,N,R}(plan) +ChebyshevTransformPlan{T,kind,K,inplace,N}(plan::P) where {T,kind,K,inplace,N,P} = + ChebyshevTransformPlan{T,kind,K,inplace,N,P}(plan) # jump through some hoops to make inferrable -@inline kindtuple(N) = NTuple{N,Int32} -@inline kindtuple(N,region...) = Vector{Int32} -function plan_chebyshevtransform!(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} + +isinplace(::typeof(FFTW.plan_r2r)) = false +isinplace(::typeof(FFTW.plan_r2r!)) = true + +function createplan(::Type{CP}, x::AbstractArray{T,N}, ::Val{kind}, + planfn::F, rfftkind, dims...; kws...) where {CP,T<:fftwNumber,N,F,kind} + + inplace = isinplace(planfn) if isempty(x) - ChebyshevTransformPlan{T,1,kindtuple(N,dims...),true,N,isempty(dims) ? NTuple{N,Int} : typeof(dims[1])}() + flags = get(kws, :flags, FFTW.ESTIMATE) + szA = size(x) .+ 1 + A = if flags & FFTW.ESTIMATE != 0 + FFTW.FakeArray{T}(szA) + else + Array{T}(undef, szA) + end + plan = planfn(A, rfftkind, dims...; kws...) + CP{T,kind,:fftw,inplace,N,typeof(plan)}() else - ChebyshevTransformPlan{T,1}(FFTW.plan_r2r!(x, FIRSTKIND, dims...; kws...)) + plan = planfn(x, rfftkind, dims...; kws...) + CP{T,kind,:fftw,inplace,N}(plan) end end + +function plan_chebyshevtransform!(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} + createplan(ChebyshevTransformPlan, x, Val(1), FFTW.plan_r2r!, FIRSTKIND, dims...; kws...) +end function plan_chebyshevtransform!(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) - ChebyshevTransformPlan{T,2}(FFTW.plan_r2r!(x, SECONDKIND, dims...; kws...)) + createplan(ChebyshevTransformPlan, x, Val(2), FFTW.plan_r2r!, SECONDKIND, dims...; kws...) end function plan_chebyshevtransform(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} - if isempty(x) - ChebyshevTransformPlan{T,1,kindtuple(N,dims...),false,N,isempty(dims) ? NTuple{N,Int} : typeof(dims[1])}() - else - ChebyshevTransformPlan{T,1}(FFTW.plan_r2r(x, FIRSTKIND, dims...; kws...)) - end + createplan(ChebyshevTransformPlan, x, Val(1), FFTW.plan_r2r, FIRSTKIND, dims...; kws...) end function plan_chebyshevtransform(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) - ChebyshevTransformPlan{T,2}(FFTW.plan_r2r(x, SECONDKIND, dims...; kws...)) + createplan(ChebyshevTransformPlan, x, Val(2), FFTW.plan_r2r, SECONDKIND, dims...; kws...) end plan_chebyshevtransform!(x::AbstractArray, dims...; kws...) = plan_chebyshevtransform!(x, Val(1), dims...; kws...) @@ -150,7 +168,7 @@ end ldiv!(_prod_size(size(y), d), y) end -function *(P::ChebyshevTransformPlan{T,1,K,true,N}, x::AbstractArray{T,N}) where {T,K,N} +function *(P::ChebyshevTransformPlan{T,1,:fftw,true,N}, x::AbstractArray{T,N}) where {T,N} n = length(x) n == 0 && return x @@ -158,7 +176,7 @@ function *(P::ChebyshevTransformPlan{T,1,K,true,N}, x::AbstractArray{T,N}) where _cheb1_rescale!(P.plan.region, y) end -function mul!(y::AbstractArray{T,N}, P::ChebyshevTransformPlan{T,1,K,false,N}, x::AbstractArray{<:Any,N}) where {T,K,N} +function mul!(y::AbstractArray{T,N}, P::ChebyshevTransformPlan{T,1,:fftw,false,N}, x::AbstractArray{<:Any,N}) where {T,N} n = length(x) length(y) == n || throw(DimensionMismatch("output must match dimension")) n == 0 && return y @@ -184,13 +202,13 @@ function _cheb2_rescale!(d, y::AbstractArray) ldiv!(_prod_size(size(y) .- 1, d), y) end -function *(P::ChebyshevTransformPlan{T,2,K,true,N}, x::AbstractArray{T,N}) where {T,K,N} +function *(P::ChebyshevTransformPlan{T,2,:fftw,true,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,N} n = length(x) y = P.plan*x # will be === x if in-place _cheb2_rescale!(P.plan.region, y) end -function mul!(y::AbstractArray{T,N}, P::ChebyshevTransformPlan{T,2,K,false,N}, x::AbstractArray{<:Any,N}) where {T,K,N} +function mul!(y::AbstractArray{T,N}, P::ChebyshevTransformPlan{T,2,:fftw,false,N}, x::AbstractArray{<:Any,N}) where {T<:fftwNumber,N} n = length(x) length(y) == n || throw(DimensionMismatch("output must match dimension")) _plan_mul!(y, P.plan, x) @@ -223,24 +241,35 @@ chebyshevtransform(x, dims...; kws...) = plan_chebyshevtransform(x, dims...; kws const IFIRSTKIND = FFTW.REDFT01 -struct IChebyshevTransformPlan{T,kind,K,inplace,N,R} <: ChebyshevPlan{T} - plan::FFTW.r2rFFTWPlan{T,K,inplace,N,R} - IChebyshevTransformPlan{T,kind,K,inplace,N,R}(plan) where {T,kind,K,inplace,N,R} = new{T,kind,K,inplace,N,R}(plan) - IChebyshevTransformPlan{T,kind,K,inplace,N,R}() where {T,kind,K,inplace,N,R} = new{T,kind,K,inplace,N,R}() +struct IChebyshevTransformPlan{T,kind,K,inplace,N,P} <: ChebyshevPlan{T} + plan::P + function IChebyshevTransformPlan{T,kind,K,inplace,N,P}(plan::P) where {T,kind,K,inplace,N,P} + new{T,kind,K,inplace,N,P}(plan) + end + function IChebyshevTransformPlan{T,kind,K,inplace,N,P}() where {T,kind,K,inplace,N,P} + new{T,kind,K,inplace,N,P}() + end end -IChebyshevTransformPlan{T,kind}(F::FFTW.r2rFFTWPlan{T,K,inplace,N,R}) where {T,kind,K,inplace,N,R} = - IChebyshevTransformPlan{T,kind,K,inplace,N,R}(F) - +IChebyshevTransformPlan{T,kind,K,inplace,N}(F::P) where {T,kind,K,inplace,N,P} = + IChebyshevTransformPlan{T,kind,K,inplace,N,P}(F) # second kind Chebyshev transforms share a plan with their inverse # so we support this via inv -inv(P::ChebyshevTransformPlan{T,2}) where {T} = IChebyshevTransformPlan{T,2}(P.plan) -inv(P::IChebyshevTransformPlan{T,2}) where {T} = ChebyshevTransformPlan{T,2}(P.plan) +function inv(P::ChebyshevTransformPlan{T,2,K,inplace,N}) where {T,K,inplace,N} + IChebyshevTransformPlan{T,2,K,inplace,N}(P.plan) +end +function inv(P::IChebyshevTransformPlan{T,2,K,inplace,N}) where {T,K,inplace,N} + ChebyshevTransformPlan{T,2,K,inplace,N}(P.plan) +end -inv(P::ChebyshevTransformPlan{T,1}) where {T} = IChebyshevTransformPlan{T,1}(inv(P.plan).p) -inv(P::IChebyshevTransformPlan{T,1}) where {T} = ChebyshevTransformPlan{T,1}(inv(P.plan).p) +function inv(P::ChebyshevTransformPlan{T,1,K,inplace,N}) where {T,K,inplace,N} + IChebyshevTransformPlan{T,1,K,inplace,N}(inv(P.plan).p) +end +function inv(P::IChebyshevTransformPlan{T,1,K,inplace,N}) where {T,K,inplace,N} + ChebyshevTransformPlan{T,1,K,inplace,N}(inv(P.plan).p) +end @@ -249,11 +278,7 @@ inv(P::IChebyshevTransformPlan{T,1}) where {T} = ChebyshevTransformPlan{T,1}(inv function plan_ichebyshevtransform!(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} - if isempty(x) - IChebyshevTransformPlan{T,1,kindtuple(N,dims...),true,N,isempty(dims) ? NTuple{N,Int} : typeof(dims[1])}() - else - IChebyshevTransformPlan{T,1}(FFTW.plan_r2r!(x, IFIRSTKIND, dims...; kws...)) - end + createplan(IChebyshevTransformPlan, x, Val(1), FFTW.plan_r2r!, IFIRSTKIND, dims...; kws...) end function plan_ichebyshevtransform!(x::AbstractArray{T}, ::Val{2}, dims...; kws...) where T<:fftwNumber @@ -261,11 +286,7 @@ function plan_ichebyshevtransform!(x::AbstractArray{T}, ::Val{2}, dims...; kws.. end function plan_ichebyshevtransform(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} - if isempty(x) - IChebyshevTransformPlan{T,1,kindtuple(N,dims...),false,N,isempty(dims) ? NTuple{N,Int} : typeof(dims[1])}() - else - IChebyshevTransformPlan{T,1}(FFTW.plan_r2r(x, IFIRSTKIND, dims...; kws...)) - end + createplan(IChebyshevTransformPlan, x, Val(1), FFTW.plan_r2r, IFIRSTKIND, dims...; kws...) end function plan_ichebyshevtransform(x::AbstractArray{T}, ::Val{2}, dims...; kws...) where T<:fftwNumber @@ -297,7 +318,7 @@ end x end -function *(P::IChebyshevTransformPlan{T,1,K,true,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,K,N} +function *(P::IChebyshevTransformPlan{T,1,:fftw,true,N}, x::AbstractArray{T,N}) where {T,N} n = length(x) n == 0 && return x @@ -306,7 +327,7 @@ function *(P::IChebyshevTransformPlan{T,1,K,true,N}, x::AbstractArray{T,N}) wher x end -function mul!(y::AbstractArray{T,N}, P::IChebyshevTransformPlan{T,1,K,false,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,K,N} +function mul!(y::AbstractArray{T,N}, P::IChebyshevTransformPlan{T,1,:fftw,false,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,N} size(y) == size(x) || throw(DimensionMismatch("output must match dimension")) isempty(x) && return y @@ -350,7 +371,7 @@ end y end -function *(P::IChebyshevTransformPlan{T,2,K,true,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,K,N} +function *(P::IChebyshevTransformPlan{T,2,:fftw,true,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,N} n = length(x) _icheb2_prescale!(P.plan.region, x) @@ -358,7 +379,7 @@ function *(P::IChebyshevTransformPlan{T,2,K,true,N}, x::AbstractArray{T,N}) wher _icheb2_rescale!(P.plan.region, x) end -function mul!(y::AbstractArray{T,N}, P::IChebyshevTransformPlan{T,2,K,false,N}, x::AbstractArray{<:Any,N}) where {T<:fftwNumber,K,N} +function mul!(y::AbstractArray{T,N}, P::IChebyshevTransformPlan{T,2,:fftw,false,N}, x::AbstractArray{<:Any,N}) where {T<:fftwNumber,N} n = length(x) length(y) == n || throw(DimensionMismatch("output must match dimension")) @@ -368,7 +389,7 @@ function mul!(y::AbstractArray{T,N}, P::IChebyshevTransformPlan{T,2,K,false,N}, _icheb2_rescale!(P.plan.region, y) end -*(P::IChebyshevTransformPlan{T,kind,K,false,N}, x::AbstractArray{T,N}) where {T,kind,K,N} = mul!(similar(x), P, x) +*(P::IChebyshevTransformPlan{T,kind,:fftw,false,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,kind,N} = mul!(similar(x), P, x) ichebyshevtransform!(x::AbstractArray, dims...; kwds...) = plan_ichebyshevtransform!(x, dims...; kwds...)*x ichebyshevtransform(x, dims...; kwds...) = plan_ichebyshevtransform(x, dims...; kwds...)*x @@ -378,38 +399,34 @@ ichebyshevtransform(x, dims...; kwds...) = plan_ichebyshevtransform(x, dims...; const UFIRSTKIND = FFTW.RODFT10 const USECONDKIND = FFTW.RODFT00 -struct ChebyshevUTransformPlan{T,kind,K,inplace,N,R} <: ChebyshevPlan{T} - plan::FFTW.r2rFFTWPlan{T,K,inplace,N,R} - ChebyshevUTransformPlan{T,kind,K,inplace,N,R}(plan) where {T,kind,K,inplace,N,R} = new{T,kind,K,inplace,N,R}(plan) - ChebyshevUTransformPlan{T,kind,K,inplace,N,R}() where {T,kind,K,inplace,N,R} = new{T,kind,K,inplace,N,R}() +struct ChebyshevUTransformPlan{T,kind,K,inplace,N,P} <: ChebyshevPlan{T} + plan::P + function ChebyshevUTransformPlan{T,kind,K,inplace,N,P}(plan::P) where {T,kind,K,inplace,N,P} + new{T,kind,K,inplace,N,P}(plan) + end + function ChebyshevUTransformPlan{T,kind,K,inplace,N,P}() where {T,kind,K,inplace,N,P} + new{T,kind,K,inplace,N,P}() + end end -ChebyshevUTransformPlan{T,kind}(plan::FFTW.r2rFFTWPlan{T,K,inplace,N,R}) where {T,kind,K,inplace,N,R} = - ChebyshevUTransformPlan{T,kind,K,inplace,N,R}(plan) +ChebyshevUTransformPlan{T,kind,K,inplace,N}(plan::P) where {T,kind,K,inplace,N,P} = + ChebyshevUTransformPlan{T,kind,K,inplace,N,P}(plan) function plan_chebyshevutransform!(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} - if isempty(x) - ChebyshevUTransformPlan{T,1,kindtuple(N,dims...),true,N,isempty(dims) ? NTuple{N,Int} : typeof(dims[1])}() - else - ChebyshevUTransformPlan{T,1}(FFTW.plan_r2r!(x, UFIRSTKIND, dims...; kws...)) - end + createplan(ChebyshevUTransformPlan, x, Val(1), FFTW.plan_r2r!, UFIRSTKIND, dims...; kws...) end function plan_chebyshevutransform!(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) - ChebyshevUTransformPlan{T,2}(FFTW.plan_r2r!(x, USECONDKIND, dims...; kws...)) + createplan(ChebyshevUTransformPlan, x, Val(2), FFTW.plan_r2r!, USECONDKIND, dims...; kws...) end function plan_chebyshevutransform(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} - if isempty(x) - ChebyshevUTransformPlan{T,1,kindtuple(N,dims...),false,N,isempty(dims) ? NTuple{N,Int} : typeof(dims[1])}() - else - ChebyshevUTransformPlan{T,1}(FFTW.plan_r2r(x, UFIRSTKIND, dims...; kws...)) - end + createplan(ChebyshevUTransformPlan, x, Val(1), FFTW.plan_r2r, UFIRSTKIND, dims...; kws...) end function plan_chebyshevutransform(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) - ChebyshevUTransformPlan{T,2}(FFTW.plan_r2r(x, USECONDKIND, dims...; kws...)) + createplan(ChebyshevUTransformPlan, x, Val(2), FFTW.plan_r2r, USECONDKIND, dims...; kws...) end plan_chebyshevutransform!(x::AbstractArray, dims...; kws...) = plan_chebyshevutransform!(x, Val(1), dims...; kws...) @@ -432,13 +449,13 @@ end x end -function *(P::ChebyshevUTransformPlan{T,1,K,true}, x::AbstractVector{T}) where {T,K} +function *(P::ChebyshevUTransformPlan{T,1,:fftw,true}, x::AbstractVector{T}) where {T} length(x) ≤ 1 && return x _chebu1_prescale!(P.plan.region, x) P.plan * x end -function mul!(y::AbstractVector{T}, P::ChebyshevUTransformPlan{T,1,K,false}, x::AbstractVector{T}) where {T,K} +function mul!(y::AbstractVector{T}, P::ChebyshevUTransformPlan{T,1,:fftw,false}, x::AbstractVector{T}) where {T} n = length(x) length(x) ≤ 1 && return copyto!(y, x) _chebu1_prescale!(P.plan.region, x) @@ -465,14 +482,14 @@ end x end -function *(P::ChebyshevUTransformPlan{T,2,K,true}, x::AbstractVector{T}) where {T,K} +function *(P::ChebyshevUTransformPlan{T,2,:fftw,true}, x::AbstractVector{T}) where {T} n = length(x) n ≤ 1 && return x _chebu2_prescale!(P.plan.region, x) lmul!(one(T)/ (n+1), P.plan * x) end -function mul!(y::AbstractVector{T}, P::ChebyshevUTransformPlan{T,2,K,false}, x::AbstractVector{T}) where {T,K} +function mul!(y::AbstractVector{T}, P::ChebyshevUTransformPlan{T,2,:fftw,false}, x::AbstractVector{T}) where {T} n = length(x) n ≤ 1 && return copyto!(y, x) _chebu2_prescale!(P.plan.region, x) @@ -481,7 +498,7 @@ function mul!(y::AbstractVector{T}, P::ChebyshevUTransformPlan{T,2,K,false}, x:: lmul!(one(T)/ (n+1), y) end -*(P::ChebyshevUTransformPlan{T,kind,K,false,N}, x::AbstractArray{T,N}) where {T,kind,K,N} = +*(P::ChebyshevUTransformPlan{T,kind,:fftw,false,N}, x::AbstractArray{T,N}) where {T,kind,N} = mul!(similar(x), P, x) chebyshevutransform!(x::AbstractVector{T}, dims...; kws...) where {T<:fftwNumber} = @@ -500,37 +517,33 @@ chebyshevutransform(x, dims...; kws...) = plan_chebyshevutransform(x, dims...; k ## Inverse transforms take ChebyshevU coefficients and produce values at ChebyshevU points of the first and second kinds const IUFIRSTKIND = FFTW.RODFT01 -struct IChebyshevUTransformPlan{T,kind,K,inplace,N,R} <: ChebyshevPlan{T} - plan::FFTW.r2rFFTWPlan{T,K,inplace,N,R} - IChebyshevUTransformPlan{T,kind,K,inplace,N,R}(plan) where {T,kind,K,inplace,N,R} = new{T,kind,K,inplace,N,R}(plan) - IChebyshevUTransformPlan{T,kind,K,inplace,N,R}() where {T,kind,K,inplace,N,R} = new{T,kind,K,inplace,N,R}() +struct IChebyshevUTransformPlan{T,kind,K,inplace,N,P} <: ChebyshevPlan{T} + plan::P + function IChebyshevUTransformPlan{T,kind,K,inplace,N,P}(plan::P) where {T,kind,K,inplace,N,P} + new{T,kind,K,inplace,N,P}(plan) + end + function IChebyshevUTransformPlan{T,kind,K,inplace,N,P}() where {T,kind,K,inplace,N,P} + new{T,kind,K,inplace,N,P}() + end end -IChebyshevUTransformPlan{T,kind}(F::FFTW.r2rFFTWPlan{T,K,inplace,N,R}) where {T,kind,K,inplace,N,R} = - IChebyshevUTransformPlan{T,kind,K,inplace,N,R}(F) +IChebyshevUTransformPlan{T,kind,K,inplace,N}(F::P) where {T,kind,K,inplace,N,P} = + IChebyshevUTransformPlan{T,kind,K,inplace,N,P}(F) function plan_ichebyshevutransform!(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} - if isempty(x) - IChebyshevUTransformPlan{T,1,kindtuple(N,dims...),true,N,isempty(dims) ? NTuple{N,Int} : typeof(dims[1])}() - else - IChebyshevUTransformPlan{T,1}(FFTW.plan_r2r!(x, IUFIRSTKIND, dims...; kws...)) - end + createplan(IChebyshevUTransformPlan, x, Val(1), FFTW.plan_r2r!, IUFIRSTKIND, dims...; kws...) end function plan_ichebyshevutransform!(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) - IChebyshevUTransformPlan{T,2}(FFTW.plan_r2r!(x, USECONDKIND)) + createplan(IChebyshevUTransformPlan, x, Val(2), FFTW.plan_r2r!, USECONDKIND, dims...; kws...) end function plan_ichebyshevutransform(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} - if isempty(x) - IChebyshevUTransformPlan{T,1,kindtuple(N,dims...),false,N,isempty(dims) ? NTuple{N,Int} : typeof(dims[1])}() - else - IChebyshevUTransformPlan{T,1}(FFTW.plan_r2r(x, IUFIRSTKIND, dims...; kws...)) - end + createplan(IChebyshevUTransformPlan, x, Val(1), FFTW.plan_r2r, IUFIRSTKIND, dims...; kws...) end function plan_ichebyshevutransform(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) - IChebyshevUTransformPlan{T,2}(FFTW.plan_r2r(x, USECONDKIND, dims...; kws...)) + createplan(IChebyshevUTransformPlan, x, Val(2), FFTW.plan_r2r, USECONDKIND, dims...; kws...) end @@ -539,11 +552,19 @@ plan_ichebyshevutransform(x::AbstractArray, dims...; kws...) = plan_ichebyshevut # second kind Chebyshev transforms share a plan with their inverse # so we support this via inv -inv(P::ChebyshevUTransformPlan{T,2}) where {T} = IChebyshevUTransformPlan{T,2}(P.plan) -inv(P::IChebyshevUTransformPlan{T,2}) where {T} = ChebyshevUTransformPlan{T,2}(P.plan) +function inv(P::ChebyshevUTransformPlan{T,2,K,inplace,N}) where {T,K,inplace,N} + IChebyshevUTransformPlan{T,2,K,inplace,N}(P.plan) +end +function inv(P::IChebyshevUTransformPlan{T,2,K,inplace,N}) where {T,K,inplace,N} + ChebyshevUTransformPlan{T,2,K,inplace,N}(P.plan) +end -inv(P::ChebyshevUTransformPlan{T,1}) where {T} = IChebyshevUTransformPlan{T,1}(inv(P.plan).p) -inv(P::IChebyshevUTransformPlan{T,1}) where {T} = ChebyshevUTransformPlan{T,1}(inv(P.plan).p) +function inv(P::ChebyshevUTransformPlan{T,1,K,inplace,N}) where {T,K,inplace,N} + IChebyshevUTransformPlan{T,1,K,inplace,N}(inv(P.plan).p) +end +function inv(P::IChebyshevUTransformPlan{T,1,K,inplace,N}) where {T,K,inplace,N} + ChebyshevUTransformPlan{T,1,K,inplace,N}(inv(P.plan).p) +end function _ichebyu1_postscale!(_, x::AbstractVector{T}) where T @@ -553,7 +574,7 @@ function _ichebyu1_postscale!(_, x::AbstractVector{T}) where T end x end -function *(P::IChebyshevUTransformPlan{T,1,K,true}, x::AbstractVector{T}) where {T<:fftwNumber,K} +function *(P::IChebyshevUTransformPlan{T,1,:fftw,true}, x::AbstractVector{T}) where {T<:fftwNumber} n = length(x) n ≤ 1 && return x @@ -561,7 +582,7 @@ function *(P::IChebyshevUTransformPlan{T,1,K,true}, x::AbstractVector{T}) where _ichebyu1_postscale!(P.plan.region, x) end -function mul!(y::AbstractVector{T}, P::IChebyshevUTransformPlan{T,1,K,false}, x::AbstractVector{T}) where {T<:fftwNumber,K} +function mul!(y::AbstractVector{T}, P::IChebyshevUTransformPlan{T,1,:fftw,false}, x::AbstractVector{T}) where {T<:fftwNumber} n = length(x) length(y) == n || throw(DimensionMismatch("output must match dimension")) n ≤ 1 && return x @@ -580,7 +601,7 @@ function _ichebu2_rescale!(_, x::AbstractVector{T}) where T x end -function *(P::IChebyshevUTransformPlan{T,2,K,true}, x::AbstractVector{T}) where {T<:fftwNumber,K} +function *(P::IChebyshevUTransformPlan{T,2,:fftw,true}, x::AbstractVector{T}) where {T<:fftwNumber} n = length(x) n ≤ 1 && return x @@ -588,7 +609,7 @@ function *(P::IChebyshevUTransformPlan{T,2,K,true}, x::AbstractVector{T}) where _ichebu2_rescale!(P.plan.region, x) end -function mul!(y::AbstractVector{T}, P::IChebyshevUTransformPlan{T,2,K,false}, x::AbstractVector{T}) where {T<:fftwNumber,K} +function mul!(y::AbstractVector{T}, P::IChebyshevUTransformPlan{T,2,:fftw,false}, x::AbstractVector{T}) where {T<:fftwNumber} n = length(x) length(y) == n || throw(DimensionMismatch("output must match dimension")) n ≤ 1 && return x @@ -602,7 +623,7 @@ ichebyshevutransform!(x::AbstractVector{T}, dims...; kwds...) where {T<:fftwNumb ichebyshevutransform(x, dims...; kwds...) = plan_ichebyshevutransform(x, dims...; kwds...)*x -*(P::IChebyshevUTransformPlan{T,k,K,false,N}, x::AbstractArray{T,N}) where {T,k,K,N} = +*(P::IChebyshevUTransformPlan{T,k,:fftw,false,N}, x::AbstractArray{T,N}) where {T,k,N} = mul!(similar(x), P, x) @@ -661,21 +682,15 @@ chebyshevpoints(n::Integer, kind=Val(1)) = chebyshevpoints(Float64, n, kind) # end -### -# BigFloat -# Use `Nothing` and fall back to FFT -### - - plan_chebyshevtransform(x::AbstractArray{T,N}, ::Val{kind}, dims...; kws...) where {T,N,kind} = - ChebyshevTransformPlan{T,kind,Nothing,false,N,UnitRange{Int}}() + ChebyshevTransformPlan{T,kind,Nothing,false,N,Nothing}() plan_ichebyshevtransform(x::AbstractArray{T,N}, ::Val{kind}, dims...; kws...) where {T,N,kind} = - IChebyshevTransformPlan{T,kind,Nothing,false,N,UnitRange{Int}}() + IChebyshevTransformPlan{T,kind,Nothing,false,N,Nothing}() plan_chebyshevtransform!(x::AbstractArray{T,N}, ::Val{kind}, dims...; kws...) where {T,N,kind} = - ChebyshevTransformPlan{T,kind,Nothing,true,N,UnitRange{Int}}() + ChebyshevTransformPlan{T,kind,Nothing,true,N,Nothing}() plan_ichebyshevtransform!(x::AbstractArray{T,N}, ::Val{kind}, dims...; kws...) where {T,N,kind} = - IChebyshevTransformPlan{T,kind,Nothing,true,N,UnitRange{Int}}() + IChebyshevTransformPlan{T,kind,Nothing,true,N,Nothing}() #following Chebfun's @Chebtech1/vals2coeffs.m and @Chebtech2/vals2coeffs.m diff --git a/test/chebyshevtests.jl b/test/chebyshevtests.jl index ae438ac0..5169ff06 100644 --- a/test/chebyshevtests.jl +++ b/test/chebyshevtests.jl @@ -1,4 +1,5 @@ using FastTransforms, Test +using FFTW @testset "Chebyshev transform" begin @testset "Chebyshev points" begin @@ -138,6 +139,20 @@ using FastTransforms, Test @test_throws ArgumentError ichebyshevtransform(T[1], Val(2)) @test_throws ArgumentError chebyshevtransform(T[], Val(2)) @test_throws ArgumentError ichebyshevtransform(T[], Val(2)) + + @testset "FFTW flags" begin + x = Float64[] + P = @inferred plan_chebyshevtransform(x, flags=FFTW.PATIENT) + @test P * x isa AbstractVector{Float64} + @test P * x == x == Float64[] + P = @inferred plan_ichebyshevtransform(x, flags=FFTW.PATIENT) + @test P * x isa AbstractVector{Float64} + @test P * x == x == Float64[] + P = @inferred plan_chebyshevtransform!(x, flags=FFTW.PATIENT) + @test P * x === x && x == Float64[] + P = @inferred plan_ichebyshevtransform!(x, flags=FFTW.PATIENT) + @test P * x === x && x == Float64[] + end end end @@ -196,6 +211,20 @@ using FastTransforms, Test @test ichebyshevutransform(T[1]) == T[1] @test chebyshevutransform(T[]) == T[] @test ichebyshevutransform(T[]) == T[] + + @testset "FFTW flags" begin + x = Float64[] + P = @inferred plan_chebyshevutransform(x, flags=FFTW.PATIENT) + @test P * x isa AbstractVector{Float64} + @test P * x == x == Float64[] + P = @inferred plan_ichebyshevutransform(x, flags=FFTW.PATIENT) + @test P * x isa AbstractVector{Float64} + @test P * x == x == Float64[] + P = @inferred plan_chebyshevutransform!(x, flags=FFTW.PATIENT) + @test P * x === x && x == Float64[] + P = @inferred plan_ichebyshevutransform!(x, flags=FFTW.PATIENT) + @test P * x === x && x == Float64[] + end end end @testset "Chebyshev second kind points <-> second kind coefficients" begin From da47f796134c222f1df277e2d3405952ea97633a Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Mon, 12 Jun 2023 19:23:37 +0530 Subject: [PATCH 2/3] remove K parameter from plans --- src/chebyshevtransform.jl | 156 +++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/src/chebyshevtransform.jl b/src/chebyshevtransform.jl index ffcfb407..a98e014e 100644 --- a/src/chebyshevtransform.jl +++ b/src/chebyshevtransform.jl @@ -9,18 +9,18 @@ length(P::ChebyshevPlan) = isdefined(P, :plan) ? length(P.plan) : 0 const FIRSTKIND = FFTW.REDFT10 const SECONDKIND = FFTW.REDFT00 -struct ChebyshevTransformPlan{T,kind,K,inplace,N,P} <: ChebyshevPlan{T} +struct ChebyshevTransformPlan{T,kind,inplace,N,P} <: ChebyshevPlan{T} plan::P - function ChebyshevTransformPlan{T,kind,K,inplace,N,P}(plan::P) where {T,kind,K,inplace,N,P} - new{T,kind,K,inplace,N,P}(plan) + function ChebyshevTransformPlan{T,kind,inplace,N,P}(plan::P) where {T,kind,inplace,N,P} + new{T,kind,inplace,N,P}(plan) end - function ChebyshevTransformPlan{T,kind,K,inplace,N,P}() where {T,kind,K,inplace,N,P} - new{T,kind,K,inplace,N,P}() + function ChebyshevTransformPlan{T,kind,inplace,N,P}() where {T,kind,inplace,N,P} + new{T,kind,inplace,N,P}() end end -ChebyshevTransformPlan{T,kind,K,inplace,N}(plan::P) where {T,kind,K,inplace,N,P} = - ChebyshevTransformPlan{T,kind,K,inplace,N,P}(plan) +ChebyshevTransformPlan{T,kind,inplace,N}(plan::P) where {T,kind,inplace,N,P} = + ChebyshevTransformPlan{T,kind,inplace,N,P}(plan) # jump through some hoops to make inferrable @@ -40,10 +40,10 @@ function createplan(::Type{CP}, x::AbstractArray{T,N}, ::Val{kind}, Array{T}(undef, szA) end plan = planfn(A, rfftkind, dims...; kws...) - CP{T,kind,:fftw,inplace,N,typeof(plan)}() + CP{T,kind,inplace,N,typeof(plan)}() else plan = planfn(x, rfftkind, dims...; kws...) - CP{T,kind,:fftw,inplace,N}(plan) + CP{T,kind,inplace,N}(plan) end end @@ -168,7 +168,7 @@ end ldiv!(_prod_size(size(y), d), y) end -function *(P::ChebyshevTransformPlan{T,1,:fftw,true,N}, x::AbstractArray{T,N}) where {T,N} +function *(P::ChebyshevTransformPlan{T,1,true,N}, x::AbstractArray{T,N}) where {T,N} n = length(x) n == 0 && return x @@ -176,7 +176,7 @@ function *(P::ChebyshevTransformPlan{T,1,:fftw,true,N}, x::AbstractArray{T,N}) w _cheb1_rescale!(P.plan.region, y) end -function mul!(y::AbstractArray{T,N}, P::ChebyshevTransformPlan{T,1,:fftw,false,N}, x::AbstractArray{<:Any,N}) where {T,N} +function mul!(y::AbstractArray{T,N}, P::ChebyshevTransformPlan{T,1,false,N}, x::AbstractArray{<:Any,N}) where {T,N} n = length(x) length(y) == n || throw(DimensionMismatch("output must match dimension")) n == 0 && return y @@ -202,20 +202,20 @@ function _cheb2_rescale!(d, y::AbstractArray) ldiv!(_prod_size(size(y) .- 1, d), y) end -function *(P::ChebyshevTransformPlan{T,2,:fftw,true,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,N} +function *(P::ChebyshevTransformPlan{T,2,true,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,N} n = length(x) y = P.plan*x # will be === x if in-place _cheb2_rescale!(P.plan.region, y) end -function mul!(y::AbstractArray{T,N}, P::ChebyshevTransformPlan{T,2,:fftw,false,N}, x::AbstractArray{<:Any,N}) where {T<:fftwNumber,N} +function mul!(y::AbstractArray{T,N}, P::ChebyshevTransformPlan{T,2,false,N}, x::AbstractArray{<:Any,N}) where {T<:fftwNumber,N} n = length(x) length(y) == n || throw(DimensionMismatch("output must match dimension")) _plan_mul!(y, P.plan, x) _cheb2_rescale!(P.plan.region, y) end -*(P::ChebyshevTransformPlan{T,kind,K,false,N}, x::AbstractArray{T,N}) where {T,kind,K,N} = +*(P::ChebyshevTransformPlan{T,kind,false,N}, x::AbstractArray{T,N}) where {T,kind,N} = mul!(similar(x), P, x) """ @@ -241,34 +241,34 @@ chebyshevtransform(x, dims...; kws...) = plan_chebyshevtransform(x, dims...; kws const IFIRSTKIND = FFTW.REDFT01 -struct IChebyshevTransformPlan{T,kind,K,inplace,N,P} <: ChebyshevPlan{T} +struct IChebyshevTransformPlan{T,kind,inplace,N,P} <: ChebyshevPlan{T} plan::P - function IChebyshevTransformPlan{T,kind,K,inplace,N,P}(plan::P) where {T,kind,K,inplace,N,P} - new{T,kind,K,inplace,N,P}(plan) + function IChebyshevTransformPlan{T,kind,inplace,N,P}(plan::P) where {T,kind,inplace,N,P} + new{T,kind,inplace,N,P}(plan) end - function IChebyshevTransformPlan{T,kind,K,inplace,N,P}() where {T,kind,K,inplace,N,P} - new{T,kind,K,inplace,N,P}() + function IChebyshevTransformPlan{T,kind,inplace,N,P}() where {T,kind,inplace,N,P} + new{T,kind,inplace,N,P}() end end -IChebyshevTransformPlan{T,kind,K,inplace,N}(F::P) where {T,kind,K,inplace,N,P} = - IChebyshevTransformPlan{T,kind,K,inplace,N,P}(F) +IChebyshevTransformPlan{T,kind,inplace,N}(F::P) where {T,kind,inplace,N,P} = + IChebyshevTransformPlan{T,kind,inplace,N,P}(F) # second kind Chebyshev transforms share a plan with their inverse # so we support this via inv -function inv(P::ChebyshevTransformPlan{T,2,K,inplace,N}) where {T,K,inplace,N} - IChebyshevTransformPlan{T,2,K,inplace,N}(P.plan) +function inv(P::ChebyshevTransformPlan{T,2,inplace,N}) where {T,inplace,N} + IChebyshevTransformPlan{T,2,inplace,N}(P.plan) end -function inv(P::IChebyshevTransformPlan{T,2,K,inplace,N}) where {T,K,inplace,N} - ChebyshevTransformPlan{T,2,K,inplace,N}(P.plan) +function inv(P::IChebyshevTransformPlan{T,2,inplace,N}) where {T,inplace,N} + ChebyshevTransformPlan{T,2,inplace,N}(P.plan) end -function inv(P::ChebyshevTransformPlan{T,1,K,inplace,N}) where {T,K,inplace,N} - IChebyshevTransformPlan{T,1,K,inplace,N}(inv(P.plan).p) +function inv(P::ChebyshevTransformPlan{T,1,inplace,N}) where {T,inplace,N} + IChebyshevTransformPlan{T,1,inplace,N}(inv(P.plan).p) end -function inv(P::IChebyshevTransformPlan{T,1,K,inplace,N}) where {T,K,inplace,N} - ChebyshevTransformPlan{T,1,K,inplace,N}(inv(P.plan).p) +function inv(P::IChebyshevTransformPlan{T,1,inplace,N}) where {T,inplace,N} + ChebyshevTransformPlan{T,1,inplace,N}(inv(P.plan).p) end @@ -318,7 +318,7 @@ end x end -function *(P::IChebyshevTransformPlan{T,1,:fftw,true,N}, x::AbstractArray{T,N}) where {T,N} +function *(P::IChebyshevTransformPlan{T,1,true,N}, x::AbstractArray{T,N}) where {T,N} n = length(x) n == 0 && return x @@ -327,7 +327,7 @@ function *(P::IChebyshevTransformPlan{T,1,:fftw,true,N}, x::AbstractArray{T,N}) x end -function mul!(y::AbstractArray{T,N}, P::IChebyshevTransformPlan{T,1,:fftw,false,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,N} +function mul!(y::AbstractArray{T,N}, P::IChebyshevTransformPlan{T,1,false,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,N} size(y) == size(x) || throw(DimensionMismatch("output must match dimension")) isempty(x) && return y @@ -371,7 +371,7 @@ end y end -function *(P::IChebyshevTransformPlan{T,2,:fftw,true,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,N} +function *(P::IChebyshevTransformPlan{T,2,true,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,N} n = length(x) _icheb2_prescale!(P.plan.region, x) @@ -379,7 +379,7 @@ function *(P::IChebyshevTransformPlan{T,2,:fftw,true,N}, x::AbstractArray{T,N}) _icheb2_rescale!(P.plan.region, x) end -function mul!(y::AbstractArray{T,N}, P::IChebyshevTransformPlan{T,2,:fftw,false,N}, x::AbstractArray{<:Any,N}) where {T<:fftwNumber,N} +function mul!(y::AbstractArray{T,N}, P::IChebyshevTransformPlan{T,2,false,N}, x::AbstractArray{<:Any,N}) where {T<:fftwNumber,N} n = length(x) length(y) == n || throw(DimensionMismatch("output must match dimension")) @@ -389,7 +389,7 @@ function mul!(y::AbstractArray{T,N}, P::IChebyshevTransformPlan{T,2,:fftw,false, _icheb2_rescale!(P.plan.region, y) end -*(P::IChebyshevTransformPlan{T,kind,:fftw,false,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,kind,N} = mul!(similar(x), P, x) +*(P::IChebyshevTransformPlan{T,kind,false,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,kind,N} = mul!(similar(x), P, x) ichebyshevtransform!(x::AbstractArray, dims...; kwds...) = plan_ichebyshevtransform!(x, dims...; kwds...)*x ichebyshevtransform(x, dims...; kwds...) = plan_ichebyshevtransform(x, dims...; kwds...)*x @@ -399,18 +399,18 @@ ichebyshevtransform(x, dims...; kwds...) = plan_ichebyshevtransform(x, dims...; const UFIRSTKIND = FFTW.RODFT10 const USECONDKIND = FFTW.RODFT00 -struct ChebyshevUTransformPlan{T,kind,K,inplace,N,P} <: ChebyshevPlan{T} +struct ChebyshevUTransformPlan{T,kind,inplace,N,P} <: ChebyshevPlan{T} plan::P - function ChebyshevUTransformPlan{T,kind,K,inplace,N,P}(plan::P) where {T,kind,K,inplace,N,P} - new{T,kind,K,inplace,N,P}(plan) + function ChebyshevUTransformPlan{T,kind,inplace,N,P}(plan::P) where {T,kind,inplace,N,P} + new{T,kind,inplace,N,P}(plan) end - function ChebyshevUTransformPlan{T,kind,K,inplace,N,P}() where {T,kind,K,inplace,N,P} - new{T,kind,K,inplace,N,P}() + function ChebyshevUTransformPlan{T,kind,inplace,N,P}() where {T,kind,inplace,N,P} + new{T,kind,inplace,N,P}() end end -ChebyshevUTransformPlan{T,kind,K,inplace,N}(plan::P) where {T,kind,K,inplace,N,P} = - ChebyshevUTransformPlan{T,kind,K,inplace,N,P}(plan) +ChebyshevUTransformPlan{T,kind,inplace,N}(plan::P) where {T,kind,inplace,N,P} = + ChebyshevUTransformPlan{T,kind,inplace,N,P}(plan) function plan_chebyshevutransform!(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} @@ -449,13 +449,13 @@ end x end -function *(P::ChebyshevUTransformPlan{T,1,:fftw,true}, x::AbstractVector{T}) where {T} +function *(P::ChebyshevUTransformPlan{T,1,true}, x::AbstractVector{T}) where {T} length(x) ≤ 1 && return x _chebu1_prescale!(P.plan.region, x) P.plan * x end -function mul!(y::AbstractVector{T}, P::ChebyshevUTransformPlan{T,1,:fftw,false}, x::AbstractVector{T}) where {T} +function mul!(y::AbstractVector{T}, P::ChebyshevUTransformPlan{T,1,false}, x::AbstractVector{T}) where {T} n = length(x) length(x) ≤ 1 && return copyto!(y, x) _chebu1_prescale!(P.plan.region, x) @@ -482,14 +482,14 @@ end x end -function *(P::ChebyshevUTransformPlan{T,2,:fftw,true}, x::AbstractVector{T}) where {T} +function *(P::ChebyshevUTransformPlan{T,2,true}, x::AbstractVector{T}) where {T} n = length(x) n ≤ 1 && return x _chebu2_prescale!(P.plan.region, x) lmul!(one(T)/ (n+1), P.plan * x) end -function mul!(y::AbstractVector{T}, P::ChebyshevUTransformPlan{T,2,:fftw,false}, x::AbstractVector{T}) where {T} +function mul!(y::AbstractVector{T}, P::ChebyshevUTransformPlan{T,2,false}, x::AbstractVector{T}) where {T} n = length(x) n ≤ 1 && return copyto!(y, x) _chebu2_prescale!(P.plan.region, x) @@ -498,7 +498,7 @@ function mul!(y::AbstractVector{T}, P::ChebyshevUTransformPlan{T,2,:fftw,false}, lmul!(one(T)/ (n+1), y) end -*(P::ChebyshevUTransformPlan{T,kind,:fftw,false,N}, x::AbstractArray{T,N}) where {T,kind,N} = +*(P::ChebyshevUTransformPlan{T,kind,false,N}, x::AbstractArray{T,N}) where {T,kind,N} = mul!(similar(x), P, x) chebyshevutransform!(x::AbstractVector{T}, dims...; kws...) where {T<:fftwNumber} = @@ -517,18 +517,18 @@ chebyshevutransform(x, dims...; kws...) = plan_chebyshevutransform(x, dims...; k ## Inverse transforms take ChebyshevU coefficients and produce values at ChebyshevU points of the first and second kinds const IUFIRSTKIND = FFTW.RODFT01 -struct IChebyshevUTransformPlan{T,kind,K,inplace,N,P} <: ChebyshevPlan{T} +struct IChebyshevUTransformPlan{T,kind,inplace,N,P} <: ChebyshevPlan{T} plan::P - function IChebyshevUTransformPlan{T,kind,K,inplace,N,P}(plan::P) where {T,kind,K,inplace,N,P} - new{T,kind,K,inplace,N,P}(plan) + function IChebyshevUTransformPlan{T,kind,inplace,N,P}(plan::P) where {T,kind,inplace,N,P} + new{T,kind,inplace,N,P}(plan) end - function IChebyshevUTransformPlan{T,kind,K,inplace,N,P}() where {T,kind,K,inplace,N,P} - new{T,kind,K,inplace,N,P}() + function IChebyshevUTransformPlan{T,kind,inplace,N,P}() where {T,kind,inplace,N,P} + new{T,kind,inplace,N,P}() end end -IChebyshevUTransformPlan{T,kind,K,inplace,N}(F::P) where {T,kind,K,inplace,N,P} = - IChebyshevUTransformPlan{T,kind,K,inplace,N,P}(F) +IChebyshevUTransformPlan{T,kind,inplace,N}(F::P) where {T,kind,inplace,N,P} = + IChebyshevUTransformPlan{T,kind,inplace,N,P}(F) function plan_ichebyshevutransform!(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} createplan(IChebyshevUTransformPlan, x, Val(1), FFTW.plan_r2r!, IUFIRSTKIND, dims...; kws...) @@ -552,18 +552,18 @@ plan_ichebyshevutransform(x::AbstractArray, dims...; kws...) = plan_ichebyshevut # second kind Chebyshev transforms share a plan with their inverse # so we support this via inv -function inv(P::ChebyshevUTransformPlan{T,2,K,inplace,N}) where {T,K,inplace,N} - IChebyshevUTransformPlan{T,2,K,inplace,N}(P.plan) +function inv(P::ChebyshevUTransformPlan{T,2,inplace,N}) where {T,inplace,N} + IChebyshevUTransformPlan{T,2,inplace,N}(P.plan) end -function inv(P::IChebyshevUTransformPlan{T,2,K,inplace,N}) where {T,K,inplace,N} - ChebyshevUTransformPlan{T,2,K,inplace,N}(P.plan) +function inv(P::IChebyshevUTransformPlan{T,2,inplace,N}) where {T,inplace,N} + ChebyshevUTransformPlan{T,2,inplace,N}(P.plan) end -function inv(P::ChebyshevUTransformPlan{T,1,K,inplace,N}) where {T,K,inplace,N} - IChebyshevUTransformPlan{T,1,K,inplace,N}(inv(P.plan).p) +function inv(P::ChebyshevUTransformPlan{T,1,inplace,N}) where {T,inplace,N} + IChebyshevUTransformPlan{T,1,inplace,N}(inv(P.plan).p) end -function inv(P::IChebyshevUTransformPlan{T,1,K,inplace,N}) where {T,K,inplace,N} - ChebyshevUTransformPlan{T,1,K,inplace,N}(inv(P.plan).p) +function inv(P::IChebyshevUTransformPlan{T,1,inplace,N}) where {T,inplace,N} + ChebyshevUTransformPlan{T,1,inplace,N}(inv(P.plan).p) end @@ -574,7 +574,7 @@ function _ichebyu1_postscale!(_, x::AbstractVector{T}) where T end x end -function *(P::IChebyshevUTransformPlan{T,1,:fftw,true}, x::AbstractVector{T}) where {T<:fftwNumber} +function *(P::IChebyshevUTransformPlan{T,1,true}, x::AbstractVector{T}) where {T<:fftwNumber} n = length(x) n ≤ 1 && return x @@ -582,7 +582,7 @@ function *(P::IChebyshevUTransformPlan{T,1,:fftw,true}, x::AbstractVector{T}) wh _ichebyu1_postscale!(P.plan.region, x) end -function mul!(y::AbstractVector{T}, P::IChebyshevUTransformPlan{T,1,:fftw,false}, x::AbstractVector{T}) where {T<:fftwNumber} +function mul!(y::AbstractVector{T}, P::IChebyshevUTransformPlan{T,1,false}, x::AbstractVector{T}) where {T<:fftwNumber} n = length(x) length(y) == n || throw(DimensionMismatch("output must match dimension")) n ≤ 1 && return x @@ -601,7 +601,7 @@ function _ichebu2_rescale!(_, x::AbstractVector{T}) where T x end -function *(P::IChebyshevUTransformPlan{T,2,:fftw,true}, x::AbstractVector{T}) where {T<:fftwNumber} +function *(P::IChebyshevUTransformPlan{T,2,true}, x::AbstractVector{T}) where {T<:fftwNumber} n = length(x) n ≤ 1 && return x @@ -609,7 +609,7 @@ function *(P::IChebyshevUTransformPlan{T,2,:fftw,true}, x::AbstractVector{T}) wh _ichebu2_rescale!(P.plan.region, x) end -function mul!(y::AbstractVector{T}, P::IChebyshevUTransformPlan{T,2,:fftw,false}, x::AbstractVector{T}) where {T<:fftwNumber} +function mul!(y::AbstractVector{T}, P::IChebyshevUTransformPlan{T,2,false}, x::AbstractVector{T}) where {T<:fftwNumber} n = length(x) length(y) == n || throw(DimensionMismatch("output must match dimension")) n ≤ 1 && return x @@ -623,7 +623,7 @@ ichebyshevutransform!(x::AbstractVector{T}, dims...; kwds...) where {T<:fftwNumb ichebyshevutransform(x, dims...; kwds...) = plan_ichebyshevutransform(x, dims...; kwds...)*x -*(P::IChebyshevUTransformPlan{T,k,:fftw,false,N}, x::AbstractArray{T,N}) where {T,k,N} = +*(P::IChebyshevUTransformPlan{T,k,false,N}, x::AbstractArray{T,N}) where {T,k,N} = mul!(similar(x), P, x) @@ -683,18 +683,18 @@ chebyshevpoints(n::Integer, kind=Val(1)) = chebyshevpoints(Float64, n, kind) plan_chebyshevtransform(x::AbstractArray{T,N}, ::Val{kind}, dims...; kws...) where {T,N,kind} = - ChebyshevTransformPlan{T,kind,Nothing,false,N,Nothing}() + ChebyshevTransformPlan{T,kind,false,N,Nothing}() plan_ichebyshevtransform(x::AbstractArray{T,N}, ::Val{kind}, dims...; kws...) where {T,N,kind} = - IChebyshevTransformPlan{T,kind,Nothing,false,N,Nothing}() + IChebyshevTransformPlan{T,kind,false,N,Nothing}() plan_chebyshevtransform!(x::AbstractArray{T,N}, ::Val{kind}, dims...; kws...) where {T,N,kind} = - ChebyshevTransformPlan{T,kind,Nothing,true,N,Nothing}() + ChebyshevTransformPlan{T,kind,true,N,Nothing}() plan_ichebyshevtransform!(x::AbstractArray{T,N}, ::Val{kind}, dims...; kws...) where {T,N,kind} = - IChebyshevTransformPlan{T,kind,Nothing,true,N,Nothing}() + IChebyshevTransformPlan{T,kind,true,N,Nothing}() #following Chebfun's @Chebtech1/vals2coeffs.m and @Chebtech2/vals2coeffs.m -function *(P::ChebyshevTransformPlan{T,1,Nothing,false}, x::AbstractVector{T}) where T +function *(P::ChebyshevTransformPlan{T,1,false,1,Nothing}, x::AbstractVector{T}) where T n = length(x) if n == 1 x @@ -708,7 +708,7 @@ function *(P::ChebyshevTransformPlan{T,1,Nothing,false}, x::AbstractVector{T}) w end -# function *(P::ChebyshevTransformPlan{T,1,K,Nothing,false}, x::AbstractVector{T}) where {T,K} +# function *(P::ChebyshevTransformPlan{T,1,false,1,Nothing}, x::AbstractVector{T}) where {T} # n = length(x) # if n == 1 # x @@ -721,14 +721,14 @@ end # end -*(P::ChebyshevTransformPlan{T,1,Nothing,true,N,R}, x::AbstractVector{T}) where {T,N,R} = - copyto!(x, ChebyshevTransformPlan{T,1,Nothing,false,N,R}() * x) +*(P::ChebyshevTransformPlan{T,1,true,N,Nothing}, x::AbstractArray{T,N}) where {T,N} = + copyto!(x, ChebyshevTransformPlan{T,1,false,N,Nothing}() * x) # *(P::ChebyshevTransformPlan{T,2,true,Nothing}, x::AbstractVector{T}) where T = # copyto!(x, ChebyshevTransformPlan{T,2,false,Nothing}() * x) #following Chebfun's @Chebtech1/vals2coeffs.m and @Chebtech2/vals2coeffs.m -function *(P::IChebyshevTransformPlan{T,1,Nothing,false}, x::AbstractVector{T}) where T +function *(P::IChebyshevTransformPlan{T,1,false,1,Nothing}, x::AbstractVector{T}) where T n = length(x) if n == 1 x @@ -741,7 +741,7 @@ function *(P::IChebyshevTransformPlan{T,1,Nothing,false}, x::AbstractVector{T}) end end -# function *(P::IChebyshevTransformPlan{T,2,K,Nothing,true}, x::AbstractVector{T}) where {T,K} +# function *(P::IChebyshevTransformPlan{T,2,true,1,Nothing}, x::AbstractVector{T}) where {T} # n = length(x) # if n == 1 # x @@ -754,7 +754,7 @@ end # end # end -*(P::IChebyshevTransformPlan{T,1,Nothing,true,N,R}, x::AbstractVector{T}) where {T,N,R} = - copyto!(x, IChebyshevTransformPlan{T,1,Nothing,false,N,R}() * x) +*(P::IChebyshevTransformPlan{T,1,true,N,Nothing}, x::AbstractArray{T,N}) where {T,N} = + copyto!(x, IChebyshevTransformPlan{T,1,false,N,Nothing}() * x) # *(P::IChebyshevTransformPlan{T,SECONDKIND,false,Nothing}, x::AbstractVector{T}) where T = # IChebyshevTransformPlan{T,SECONDKIND,true,Nothing}() * copy(x) From e3daa45a3548f0ee7b55b3d77c0a2df4fe5f1327 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Mon, 12 Jun 2023 20:05:42 +0530 Subject: [PATCH 3/3] inline createplan --- src/chebyshevtransform.jl | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/chebyshevtransform.jl b/src/chebyshevtransform.jl index a98e014e..91793761 100644 --- a/src/chebyshevtransform.jl +++ b/src/chebyshevtransform.jl @@ -27,11 +27,21 @@ ChebyshevTransformPlan{T,kind,inplace,N}(plan::P) where {T,kind,inplace,N,P} = isinplace(::typeof(FFTW.plan_r2r)) = false isinplace(::typeof(FFTW.plan_r2r!)) = true -function createplan(::Type{CP}, x::AbstractArray{T,N}, ::Val{kind}, - planfn::F, rfftkind, dims...; kws...) where {CP,T<:fftwNumber,N,F,kind} +@inline function createplan_validlength(::Type{CP}, x::AbstractArray{T,N}, ::Val{kind}, + planfn::F, rfftkind, dims...; + kws...) where {CP,T<:fftwNumber,N,F,kind} inplace = isinplace(planfn) + plan = planfn(x, rfftkind, dims...; kws...) + CP{T,kind,inplace,N}(plan) +end + +@inline function createplan(::Type{CP}, x::AbstractArray{T,N}, ::Val{kind}, + planfn::F, rfftkind, dims...; + kws...) where {CP,T<:fftwNumber,N,F,kind} + if isempty(x) + inplace = isinplace(planfn) flags = get(kws, :flags, FFTW.ESTIMATE) szA = size(x) .+ 1 A = if flags & FFTW.ESTIMATE != 0 @@ -42,8 +52,7 @@ function createplan(::Type{CP}, x::AbstractArray{T,N}, ::Val{kind}, plan = planfn(A, rfftkind, dims...; kws...) CP{T,kind,inplace,N,typeof(plan)}() else - plan = planfn(x, rfftkind, dims...; kws...) - CP{T,kind,inplace,N}(plan) + createplan_validlength(CP, x, Val(kind), planfn, rfftkind, dims...; kws...) end end @@ -52,7 +61,8 @@ function plan_chebyshevtransform!(x::AbstractArray{T,N}, ::Val{1}, dims...; kws. end function plan_chebyshevtransform!(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) - createplan(ChebyshevTransformPlan, x, Val(2), FFTW.plan_r2r!, SECONDKIND, dims...; kws...) + createplan_validlength(ChebyshevTransformPlan, x, Val(2), FFTW.plan_r2r!, + SECONDKIND, dims...; kws...) end @@ -61,7 +71,8 @@ function plan_chebyshevtransform(x::AbstractArray{T,N}, ::Val{1}, dims...; kws.. end function plan_chebyshevtransform(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) - createplan(ChebyshevTransformPlan, x, Val(2), FFTW.plan_r2r, SECONDKIND, dims...; kws...) + createplan_validlength(ChebyshevTransformPlan, x, Val(2), FFTW.plan_r2r, + SECONDKIND, dims...; kws...) end plan_chebyshevtransform!(x::AbstractArray, dims...; kws...) = plan_chebyshevtransform!(x, Val(1), dims...; kws...) @@ -418,7 +429,8 @@ function plan_chebyshevutransform!(x::AbstractArray{T,N}, ::Val{1}, dims...; kws end function plan_chebyshevutransform!(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) - createplan(ChebyshevUTransformPlan, x, Val(2), FFTW.plan_r2r!, USECONDKIND, dims...; kws...) + createplan_validlength(ChebyshevUTransformPlan, x, Val(2), FFTW.plan_r2r!, + USECONDKIND, dims...; kws...) end function plan_chebyshevutransform(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} @@ -426,7 +438,8 @@ function plan_chebyshevutransform(x::AbstractArray{T,N}, ::Val{1}, dims...; kws. end function plan_chebyshevutransform(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) - createplan(ChebyshevUTransformPlan, x, Val(2), FFTW.plan_r2r, USECONDKIND, dims...; kws...) + createplan_validlength(ChebyshevUTransformPlan, x, Val(2), FFTW.plan_r2r, + USECONDKIND, dims...; kws...) end plan_chebyshevutransform!(x::AbstractArray, dims...; kws...) = plan_chebyshevutransform!(x, Val(1), dims...; kws...) @@ -535,7 +548,8 @@ function plan_ichebyshevutransform!(x::AbstractArray{T,N}, ::Val{1}, dims...; kw end function plan_ichebyshevutransform!(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) - createplan(IChebyshevUTransformPlan, x, Val(2), FFTW.plan_r2r!, USECONDKIND, dims...; kws...) + createplan_validlength(IChebyshevUTransformPlan, x, Val(2), FFTW.plan_r2r!, + USECONDKIND, dims...; kws...) end function plan_ichebyshevutransform(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} @@ -543,7 +557,8 @@ function plan_ichebyshevutransform(x::AbstractArray{T,N}, ::Val{1}, dims...; kws end function plan_ichebyshevutransform(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) - createplan(IChebyshevUTransformPlan, x, Val(2), FFTW.plan_r2r, USECONDKIND, dims...; kws...) + createplan_validlength(IChebyshevUTransformPlan, x, Val(2), FFTW.plan_r2r, + USECONDKIND, dims...; kws...) end