From 2cae7696ef338a2458faca455d5bee887f7e7804 Mon Sep 17 00:00:00 2001 From: Andreas Noack Date: Wed, 7 Jan 2026 15:44:53 +0100 Subject: [PATCH] Drop AbstractFFT interface --- Project.toml | 2 -- src/FFTA.jl | 6 +++--- src/main.jl | 16 ++++++++++++++++ src/plan.jl | 11 +++++------ test/custom_element_types.jl | 9 --------- test/onedim/complex_backward.jl | 1 + test/onedim/real_backward.jl | 1 + test/qa/aqua.jl | 3 --- test/qa/explicit_imports.jl | 4 +--- 9 files changed, 27 insertions(+), 26 deletions(-) create mode 100644 src/main.jl diff --git a/Project.toml b/Project.toml index 9f649b8..6ec9962 100644 --- a/Project.toml +++ b/Project.toml @@ -4,7 +4,6 @@ version = "0.3.0" authors = ["Danny Sharp and contributors"] [deps] -AbstractFFTs = "621f4979-c628-5d54-868e-fcf4e3e8185c" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" @@ -13,7 +12,6 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" [compat] -AbstractFFTs = "1" Aqua = "0.8" DocStringExtensions = "0.9" ExplicitImports = "1.12" diff --git a/src/FFTA.jl b/src/FFTA.jl index 69b137f..157b32f 100644 --- a/src/FFTA.jl +++ b/src/FFTA.jl @@ -1,17 +1,17 @@ module FFTA -using AbstractFFTs: AbstractFFTs using DocStringExtensions: TYPEDSIGNATURES using LinearAlgebra: LinearAlgebra using MuladdMacro: @muladd using Primes: Primes using Reexport: @reexport -@reexport using AbstractFFTs +export fft, bfft, ifft, rfft, brfft, irfft +export plan_fft, plan_bfft, plan_rfft, plan_brfft include("callgraph.jl") include("algos.jl") include("plan.jl") - +include("main.jl") end diff --git a/src/main.jl b/src/main.jl new file mode 100644 index 0000000..7e9d5bd --- /dev/null +++ b/src/main.jl @@ -0,0 +1,16 @@ +fft(X::AbstractArray{<:Complex}, region::Union{Int,AbstractVector} = 1:ndims(X)) = plan_fft(X, region) * X +fft(X::AbstractArray, region::Union{Int,AbstractVector} = 1:ndims(X)) = fft(complex(X), region) + +bfft(X::AbstractArray{<:Complex}, region::Union{Int,AbstractVector} = 1:ndims(X)) = plan_bfft(X, region) * X + +ifft(X::AbstractArray{<:Complex}, region::Union{Int,AbstractVector} = 1:ndims(X)) = bfft(X, region) / mapreduce(Base.Fix1(size, X), *, region; init=1) + +rfft(X::AbstractArray{<:Real}, region::Union{Int,AbstractVector} = 1:ndims(X)) = plan_rfft(X, region) * X + +brfft(X::AbstractArray{<:Complex}, len::Int, region::Union{Int,AbstractVector} = 1:ndims(X)) = plan_brfft(X, len, region) * X + +function irfft(X::AbstractArray{<:Complex}, len::Int, region::Union{Int,AbstractVector} = 1:ndims(X)) + Y = brfft(X, len, region) + Y ./= mapreduce(Base.Fix1(size, Y), *, region; init=1) + return Y +end diff --git a/src/plan.jl b/src/plan.jl index 4b79925..db22a6e 100644 --- a/src/plan.jl +++ b/src/plan.jl @@ -1,6 +1,5 @@ # Plans - -abstract type FFTAPlan{T,N} <: AbstractFFTs.Plan{T} end +abstract type FFTAPlan{T,N} end struct FFTAInvPlan{T,N} <: FFTAPlan{T,N} end @@ -24,7 +23,7 @@ Base.size(p::FFTAPlan{<:Any,N}) where N = ntuple(Base.Fix1(size, p), Val{N}()) Base.complex(p::FFTAPlan_re{T,N}) where {T,N} = FFTAPlan_cx{T,N}(p.callgraph, p.region, p.dir, p.pinv) -function AbstractFFTs.plan_fft(x::AbstractArray{T,N}, region; kwargs...)::FFTAPlan_cx{T} where {T <: Complex, N} +function plan_fft(x::AbstractArray{T,N}, region::Union{Int,AbstractVector} = 1:N)::FFTAPlan_cx{T} where {T <: Complex, N} FFTN = length(region) if FFTN == 1 g = CallGraph{T}(size(x,region[])) @@ -41,7 +40,7 @@ function AbstractFFTs.plan_fft(x::AbstractArray{T,N}, region; kwargs...)::FFTAPl end end -function AbstractFFTs.plan_bfft(x::AbstractArray{T,N}, region; kwargs...)::FFTAPlan_cx{T} where {T <: Complex,N} +function plan_bfft(x::AbstractArray{T,N}, region::Union{Int,AbstractVector} = 1:N)::FFTAPlan_cx{T} where {T <: Complex,N} FFTN = length(region) if FFTN == 1 g = CallGraph{T}(size(x,region[])) @@ -58,7 +57,7 @@ function AbstractFFTs.plan_bfft(x::AbstractArray{T,N}, region; kwargs...)::FFTAP end end -function AbstractFFTs.plan_rfft(x::AbstractArray{T,N}, region; kwargs...)::FFTAPlan_re{Complex{T}} where {T <: Real,N} +function plan_rfft(x::AbstractArray{T,N}, region::Union{Int,AbstractVector} = 1:N)::FFTAPlan_re{Complex{T}} where {T <: Real,N} FFTN = length(region) if FFTN == 1 g = CallGraph{Complex{T}}(size(x,region[])) @@ -75,7 +74,7 @@ function AbstractFFTs.plan_rfft(x::AbstractArray{T,N}, region; kwargs...)::FFTAP end end -function AbstractFFTs.plan_brfft(x::AbstractArray{T,N}, len, region; kwargs...)::FFTAPlan_re{T} where {T,N} +function plan_brfft(x::AbstractArray{T,N}, len::Int, region::Union{Int,AbstractVector} = 1:N)::FFTAPlan_re{T} where {T,N} FFTN = length(region) if FFTN == 1 g = CallGraph{T}(len) diff --git a/test/custom_element_types.jl b/test/custom_element_types.jl index 3dd5314..96205a5 100644 --- a/test/custom_element_types.jl +++ b/test/custom_element_types.jl @@ -5,15 +5,6 @@ x = randn(2*3*4*5) @testset "element type: $T" for T in (Float16, BigFloat) Tx = T.(x) - @testset "AbstractFFTs believes that single and double precision is everything." begin - # Ref https://github.com/JuliaMath/FFTA.jl/issues/77 - if T == BigFloat - @test_broken fft(Tx) - else - @test_broken fft(Tx) isa Vector{Complex{T}} - end - end - # Complex cTx = complex(Tx) new_cTx = ifft(fft(cTx)) diff --git a/test/onedim/complex_backward.jl b/test/onedim/complex_backward.jl index 397d708..6ff4e1c 100644 --- a/test/onedim/complex_backward.jl +++ b/test/onedim/complex_backward.jl @@ -18,6 +18,7 @@ end end @testset "allocation regression" begin + bfft(y) # warm up @test (@test_allocations bfft(y)) <= 47 end end diff --git a/test/onedim/real_backward.jl b/test/onedim/real_backward.jl index b6f0adf..6277f66 100644 --- a/test/onedim/real_backward.jl +++ b/test/onedim/real_backward.jl @@ -22,6 +22,7 @@ end end @testset "allocation regression" begin + brfft(y, n) # warmup @test (@test_allocations brfft(y, n)) <= 55 end end diff --git a/test/qa/aqua.jl b/test/qa/aqua.jl index 3adebe2..f41e29a 100644 --- a/test/qa/aqua.jl +++ b/test/qa/aqua.jl @@ -4,8 +4,5 @@ import Aqua @testset "Aqua" begin Aqua.test_all( FFTA; - # This type piracy is caused by the problematic design of AbstractFFTs.jl - # Ref https://github.com/JuliaMath/AbstractFFTs.jl/issues/32 - piracies = (; treat_as_own = [plan_bfft, plan_brfft, plan_fft, plan_rfft]), ) end diff --git a/test/qa/explicit_imports.jl b/test/qa/explicit_imports.jl index 0e5e9f5..36a16b7 100644 --- a/test/qa/explicit_imports.jl +++ b/test/qa/explicit_imports.jl @@ -18,9 +18,7 @@ import ExplicitImports @test ExplicitImports.check_all_qualified_accesses_via_owners(FFTA) === nothing # No non-public accesses in FFTA (ie. no `... MyPkg._non_public_internal_func(...)`) - # AbstractFFTs requires subtyping of `Plan` but it is not public - # This is an upstream bug in AbstractFFTs.jl - @test ExplicitImports.check_all_qualified_accesses_are_public(FFTA; ignore = (:Plan, :require_one_based_indexing, :Fix1)) === nothing + @test ExplicitImports.check_all_qualified_accesses_are_public(FFTA; ignore = (:require_one_based_indexing, :Fix1)) === nothing # No self-qualified accesses in FFTA (ie. no `... FFTA.func(...)`) @test ExplicitImports.check_no_self_qualified_accesses(FFTA) === nothing