|
161 | 161 | IChebyshevTransformPlan{T,kind,K}(F::FFTW.r2rFFTWPlan{T,K,inplace,N,R}) where {T,kind,K,inplace,N,R} =
|
162 | 162 | IChebyshevTransformPlan{T,kind,K,inplace,N,R}(F)
|
163 | 163 |
|
164 |
| -size(P::IChebyshevTransformPlan) = isdefined(P, :plan) ? size(P.plan) : (0,) |
165 |
| -length(P::IChebyshevTransformPlan) = isdefined(P, :plan) ? length(P.plan) : 0 |
166 | 164 |
|
167 | 165 |
|
168 | 166 | # second kind Chebyshev transforms share a plan with their inverse
|
@@ -242,9 +240,8 @@ function *(P::IChebyshevTransformPlan{T,1,K,true,N}, x::AbstractArray{T,N}) wher
|
242 | 240 | end
|
243 | 241 |
|
244 | 242 | function mul!(y::AbstractArray{T,N}, P::IChebyshevTransformPlan{T,1,K,false,N}, x::AbstractArray{T,N}) where {T<:fftwNumber,K,N}
|
245 |
| - n = length(x) |
246 |
| - length(y) == n || throw(DimensionMismatch("output must match dimension")) |
247 |
| - n == 0 && return y |
| 243 | + size(y) == size(x) || throw(DimensionMismatch("output must match dimension")) |
| 244 | + isempty(x) && return y |
248 | 245 |
|
249 | 246 | _icheb1_prescale!(P.plan.region, x) # Todo: don't mutate x
|
250 | 247 | _plan_mul!(y, P.plan, x)
|
|
408 | 405 | @inline function _chebu2_postscale!(_, x::AbstractVector{T}) where T
|
409 | 406 | n = length(x)
|
410 | 407 | c = one(T)/ (n+1)
|
411 |
| - for k=1:n # sqrt(1-x_j^2) weight |
| 408 | + @inbounds for k=1:n # sqrt(1-x_j^2) weight |
412 | 409 | x[k] /= sinpi(k*c)
|
413 | 410 | end
|
414 | 411 | x
|
@@ -447,87 +444,109 @@ chebyshevutransform(x, dims...; kws...) = plan_chebyshevutransform(x, dims...; k
|
447 | 444 |
|
448 | 445 |
|
449 | 446 | ## Inverse transforms take ChebyshevU coefficients and produce values at ChebyshevU points of the first and second kinds
|
| 447 | +const IUFIRSTKIND = FFTW.RODFT01 |
450 | 448 |
|
451 |
| - |
452 |
| -struct IChebyshevUTransformPlan{T,kind,inplace,P} <: ChebyshevPlan{T} |
453 |
| - plan::FFTW.r2rFFTWPlan{T,P,true,1,UnitRange{Int}} |
454 |
| - IChebyshevUTransformPlan{T,kind,inplace,P}(plan) where {T,kind,inplace,P} = new{T,kind,inplace,P}(plan) |
455 |
| - IChebyshevUTransformPlan{T,kind,inplace,P}() where {T,kind,inplace,P} = new{T,kind,inplace,P}() |
| 449 | +struct IChebyshevUTransformPlan{T,kind,K,inplace,N,R} <: ChebyshevPlan{T} |
| 450 | + plan::FFTW.r2rFFTWPlan{T,K,inplace,N,R} |
| 451 | + IChebyshevUTransformPlan{T,kind,K,inplace,N,R}(plan) where {T,kind,K,inplace,N,R} = new{T,kind,K,inplace,N,R}(plan) |
| 452 | + IChebyshevUTransformPlan{T,kind,K,inplace,N,R}() where {T,kind,K,inplace,N,R} = new{T,kind,K,inplace,N,R}() |
456 | 453 | end
|
457 | 454 |
|
458 |
| -IChebyshevUTransformPlan{T,kind,inplace}(F::FFTW.r2rFFTWPlan{T,P}) where {T,kind,inplace,P} = |
459 |
| - IChebyshevUTransformPlan{T,kind,inplace,P}(F) |
460 |
| - |
461 |
| -IChebyshevUTransformPlan{T,kind,true}(F::IChebyshevUTransformPlan{T,kind,false,P}) where {T,kind,P} = |
462 |
| - IChebyshevUTransformPlan{T,kind,true,P}(F.plan) |
| 455 | +IChebyshevUTransformPlan{T,kind,K}(F::FFTW.r2rFFTWPlan{T,K,inplace,N,R}) where {T,kind,K,inplace,N,R} = |
| 456 | + IChebyshevUTransformPlan{T,kind,K,inplace,N,R}(F) |
463 | 457 |
|
464 |
| -function plan_ichebyshevutransform!(x::AbstractVector{T}, ::Val{1}) where T<:fftwNumber |
| 458 | +function plan_ichebyshevutransform!(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} |
465 | 459 | if isempty(x)
|
466 |
| - IChebyshevUTransformPlan{T,1,true,(8,)}() |
| 460 | + IChebyshevUTransformPlan{T,1,kindtuple(IUFIRSTKIND,N,dims...),true,N,isempty(dims) ? UnitRange{Int} : typeof(dims)}() |
467 | 461 | else
|
468 |
| - IChebyshevUTransformPlan{T,1,true,(8,)}(FFTW.plan_r2r!(x, FFTW.RODFT01)) |
| 462 | + IChebyshevUTransformPlan{T,1,kindtuple(IUFIRSTKIND,N,dims...)}(FFTW.plan_r2r!(x, IUFIRSTKIND, dims...; kws...)) |
469 | 463 | end
|
470 | 464 | end
|
471 |
| -function plan_ichebyshevutransform!(x::AbstractVector{T}, ::Val{2}) where T<:fftwNumber |
472 |
| - length(x) ≤ 1 && throw(ArgumentError("Vector must contain at least 2 entries")) |
473 |
| - IChebyshevUTransformPlan{T,2,true,(7,)}(FFTW.plan_r2r!(x, FFTW.RODFT00)) |
| 465 | +function plan_ichebyshevutransform!(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} |
| 466 | + any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) |
| 467 | + IChebyshevUTransformPlan{T,2,kindtuple(USECONDKIND,N,dims...)}(FFTW.plan_r2r!(x, USECONDKIND)) |
474 | 468 | end
|
475 | 469 |
|
476 |
| -function plan_ichebyshevutransform(x::AbstractVector{T}, ::Val{1}) where T<:fftwNumber |
| 470 | +function plan_ichebyshevutransform(x::AbstractArray{T,N}, ::Val{1}, dims...; kws...) where {T<:fftwNumber,N} |
477 | 471 | if isempty(x)
|
478 |
| - IChebyshevUTransformPlan{T,1,false,(8,)}() |
| 472 | + IChebyshevUTransformPlan{T,1,kindtuple(IUFIRSTKIND,N,dims...),false,N,isempty(dims) ? UnitRange{Int} : typeof(dims)}() |
479 | 473 | else
|
480 |
| - IChebyshevUTransformPlan{T,1,false,(8,)}(FFTW.plan_r2r!(x, FFTW.RODFT01)) |
| 474 | + IChebyshevUTransformPlan{T,1,kindtuple(IUFIRSTKIND,N,dims...)}(FFTW.plan_r2r(x, IUFIRSTKIND, dims...; kws...)) |
481 | 475 | end
|
482 | 476 | end
|
483 |
| -function plan_ichebyshevutransform(x::AbstractVector{T}, ::Val{2}) where T<:fftwNumber |
484 |
| - length(x) ≤ 1 && throw(ArgumentError("Vector must contain at least 2 entries")) |
485 |
| - IChebyshevUTransformPlan{T,2,false,(7,)}(FFTW.plan_r2r!(x, FFTW.RODFT00)) |
| 477 | +function plan_ichebyshevutransform(x::AbstractArray{T,N}, ::Val{2}, dims...; kws...) where {T<:fftwNumber,N} |
| 478 | + any(≤(1),size(x)) && throw(ArgumentError("Array must contain at least 2 entries")) |
| 479 | + IChebyshevUTransformPlan{T,2,kindtuple(USECONDKIND,N,dims...)}(FFTW.plan_r2r(x, USECONDKIND)) |
486 | 480 | end
|
487 | 481 |
|
488 |
| -plan_ichebyshevutransform!(x::AbstractVector) = plan_ichebyshevutransform!(x, Val(1)) |
489 |
| -plan_ichebyshevutransform(x::AbstractVector) = plan_ichebyshevutransform(x, Val(1)) |
490 | 482 |
|
| 483 | +plan_ichebyshevutransform!(x::AbstractArray, dims...; kws...) = plan_ichebyshevutransform!(x, Val(1), dims...; kws...) |
| 484 | +plan_ichebyshevutransform(x::AbstractArray, dims...; kws...) = plan_ichebyshevutransform(x, Val(1), dims...; kws...) |
491 | 485 |
|
492 |
| -function *(P::IChebyshevUTransformPlan{T,1,true}, x::AbstractVector{T}) where T<:fftwNumber |
| 486 | +function _ichebyu1_postscale!(_, x::AbstractVector{T}) where T |
493 | 487 | n = length(x)
|
494 |
| - n ≤ 1 && return x |
495 |
| - |
496 |
| - x = P.plan * x |
497 |
| - for k=1:n # sqrt(1-x_j^2) weight |
| 488 | + @inbounds for k=1:n # sqrt(1-x_j^2) weight |
498 | 489 | x[k] /= 2sinpi(one(T)/(2n) + (k-one(T))/n)
|
499 | 490 | end
|
500 | 491 | x
|
501 | 492 | end
|
| 493 | +function *(P::IChebyshevUTransformPlan{T,1,K,true}, x::AbstractVector{T}) where {T<:fftwNumber,K} |
| 494 | + n = length(x) |
| 495 | + n ≤ 1 && return x |
502 | 496 |
|
| 497 | + x = P.plan * x |
| 498 | + _ichebyu1_postscale!(P.plan.region, x) |
| 499 | +end |
503 | 500 |
|
504 |
| - |
505 |
| -function *(P::IChebyshevUTransformPlan{T,2,true}, x::AbstractVector{T}) where T<:fftwNumber |
| 501 | +function mul!(y::AbstractVector{T}, P::IChebyshevUTransformPlan{T,1,K,false}, x::AbstractVector{T}) where {T<:fftwNumber,K} |
506 | 502 | n = length(x)
|
| 503 | + length(y) == n || throw(DimensionMismatch("output must match dimension")) |
507 | 504 | n ≤ 1 && return x
|
508 | 505 |
|
| 506 | + _plan_mul!(y, P.plan, x) |
| 507 | + _ichebyu1_postscale!(P.plan.region, y) |
| 508 | +end |
| 509 | + |
| 510 | +function _ichebu2_rescale!(_, x::AbstractVector{T}) where T |
| 511 | + n = length(x) |
509 | 512 | c = one(T)/ (n+1)
|
510 |
| - lmul!((n+1)/(2n+2*one(T)), x) |
511 |
| - x = P.plan * x |
512 | 513 | for k=1:n # sqrt(1-x_j^2) weight
|
513 | 514 | x[k] /= sinpi(k*c)
|
514 | 515 | end
|
| 516 | + ldiv!(2, x) |
515 | 517 | x
|
516 | 518 | end
|
517 | 519 |
|
518 |
| -ichebyshevutransform!(x::AbstractVector{T}, kind=Val(1)) where {T<:fftwNumber} = |
519 |
| - plan_ichebyshevutransform!(x, kind)*x |
| 520 | +function *(P::IChebyshevUTransformPlan{T,2,K,true}, x::AbstractVector{T}) where {T<:fftwNumber,K} |
| 521 | + n = length(x) |
| 522 | + n ≤ 1 && return x |
520 | 523 |
|
521 |
| -ichebyshevutransform(x, kind=Val(1)) = ichebyshevutransform!(Array(x), kind) |
| 524 | + x = P.plan * x |
| 525 | + _ichebu2_rescale!(P.plan.region, x) |
| 526 | +end |
522 | 527 |
|
523 |
| -*(P::IChebyshevUTransformPlan{T,k,false},x::AbstractVector{T}) where {T,k} = |
524 |
| - IChebyshevUTransformPlan{T,k,true}(P)*Array(x) |
| 528 | +function mul!(y::AbstractVector{T}, P::IChebyshevUTransformPlan{T,2,K,false}, x::AbstractVector{T}) where {T<:fftwNumber,K} |
| 529 | + n = length(x) |
| 530 | + length(y) == n || throw(DimensionMismatch("output must match dimension")) |
| 531 | + n ≤ 1 && return x |
| 532 | + |
| 533 | + _plan_mul!(y, P.plan, x) |
| 534 | + _ichebu2_rescale!(P.plan.region, y) |
| 535 | +end |
| 536 | + |
| 537 | +ichebyshevutransform!(x::AbstractVector{T}, dims...; kwds...) where {T<:fftwNumber} = |
| 538 | + plan_ichebyshevutransform!(x, dims...; kwds...)*x |
| 539 | + |
| 540 | +ichebyshevutransform(x, dims...; kwds...) = plan_ichebyshevutransform(x, dims...; kwds...)*x |
| 541 | + |
| 542 | +*(P::IChebyshevUTransformPlan{T,k,K,false,N}, x::AbstractArray{T,N}) where {T,k,K,N} = |
| 543 | + mul!(similar(x), P, x) |
525 | 544 |
|
526 | 545 |
|
527 | 546 | ## Code generation for integer inputs
|
528 | 547 |
|
529 | 548 | for func in (:chebyshevtransform,:ichebyshevtransform,:chebyshevutransform,:ichebyshevutransform)
|
530 |
| - @eval $func(x::AbstractVector{T}, kind=Val(1)) where {T<:Integer} = $func(convert(AbstractVector{Float64},x), kind) |
| 549 | + @eval $func(x::AbstractVector{T}, dims...; kwds...) where {T<:Integer} = $func(convert(AbstractVector{Float64},x), dims...; kwds...) |
531 | 550 | end
|
532 | 551 |
|
533 | 552 |
|
|
0 commit comments