Skip to content

Commit 4347fa9

Browse files
committed
Add option to test with FFTW backend
1 parent 03ef58b commit 4347fa9

File tree

5 files changed

+264
-231
lines changed

5 files changed

+264
-231
lines changed

.github/workflows/CI.yml

+9
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ jobs:
2222
- windows-latest
2323
arch:
2424
- x64
25+
group:
26+
- TestPlans
27+
- FFTW
28+
exclude:
29+
- version: '1.0'
30+
group: FFTW
2531
steps:
2632
- uses: actions/checkout@v2
2733
- uses: julia-actions/setup-julia@v1
@@ -40,7 +46,10 @@ jobs:
4046
${{ runner.os }}-
4147
- uses: julia-actions/julia-buildpkg@v1
4248
- uses: julia-actions/julia-runtest@v1
49+
env:
50+
GROUP: ${{ matrix.group }}
4351
- uses: julia-actions/julia-processcoverage@v1
4452
- uses: codecov/codecov-action@v1
4553
with:
4654
file: lcov.info
55+
flag-name: group-${{ matrix.group }} # unique name for coverage report of each group

Project.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ julia = "^1.0"
1212

1313
[extras]
1414
ChainRulesTestUtils = "cdddcdb0-9152-4a09-a978-84456f9df70a"
15+
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
1516
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1617
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1718
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
1819

1920
[targets]
20-
test = ["ChainRulesTestUtils", "Random", "Test", "Unitful"]
21+
test = ["ChainRulesTestUtils", "FFTW", "Random", "Test", "Unitful"]

test/testplans.jl test/TestPlans.jl

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
module TestPlans
2+
3+
using AbstractFFTs
4+
using AbstractFFTs: Plan
5+
16
mutable struct TestPlan{T,N} <: Plan{T}
27
region
38
sz::NTuple{N,Int}
@@ -226,3 +231,5 @@ function Base.:*(p::InverseTestRPlan, x::AbstractArray)
226231

227232
return y
228233
end
234+
235+
end

test/runtests.jl

+9-230
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# This file contains code that was formerly part of Julia. License is MIT: https://julialang.org/license
2-
31
using AbstractFFTs
42
using AbstractFFTs: Plan
53
using ChainRulesTestUtils
@@ -12,235 +10,16 @@ import Unitful
1210

1311
Random.seed!(1234)
1412

15-
include("testplans.jl")
16-
17-
@testset "rfft sizes" begin
18-
A = rand(11, 10)
19-
@test @inferred(AbstractFFTs.rfft_output_size(A, 1)) == (6, 10)
20-
@test @inferred(AbstractFFTs.rfft_output_size(A, 2)) == (11, 6)
21-
A1 = rand(6, 10); A2 = rand(11, 6)
22-
@test @inferred(AbstractFFTs.brfft_output_size(A1, 11, 1)) == (11, 10)
23-
@test @inferred(AbstractFFTs.brfft_output_size(A2, 10, 2)) == (11, 10)
24-
@test_throws AssertionError AbstractFFTs.brfft_output_size(A1, 10, 2)
25-
end
26-
27-
@testset "Custom Plan" begin
28-
# DFT along last dimension, results computed using FFTW
29-
for (x, fftw_fft) in (
30-
(collect(1:7),
31-
[28.0 + 0.0im,
32-
-3.5 + 7.267824888003178im,
33-
-3.5 + 2.7911568610884143im,
34-
-3.5 + 0.7988521603655248im,
35-
-3.5 - 0.7988521603655248im,
36-
-3.5 - 2.7911568610884143im,
37-
-3.5 - 7.267824888003178im]),
38-
(collect(1:8),
39-
[36.0 + 0.0im,
40-
-4.0 + 9.65685424949238im,
41-
-4.0 + 4.0im,
42-
-4.0 + 1.6568542494923806im,
43-
-4.0 + 0.0im,
44-
-4.0 - 1.6568542494923806im,
45-
-4.0 - 4.0im,
46-
-4.0 - 9.65685424949238im]),
47-
(collect(reshape(1:8, 2, 4)),
48-
[16.0+0.0im -4.0+4.0im -4.0+0.0im -4.0-4.0im;
49-
20.0+0.0im -4.0+4.0im -4.0+0.0im -4.0-4.0im]),
50-
(collect(reshape(1:9, 3, 3)),
51-
[12.0+0.0im -4.5+2.598076211353316im -4.5-2.598076211353316im;
52-
15.0+0.0im -4.5+2.598076211353316im -4.5-2.598076211353316im;
53-
18.0+0.0im -4.5+2.598076211353316im -4.5-2.598076211353316im]),
54-
)
55-
# FFT
56-
dims = ndims(x)
57-
y = AbstractFFTs.fft(x, dims)
58-
@test y fftw_fft
59-
P = plan_fft(x, dims)
60-
@test eltype(P) === ComplexF64
61-
@test P * x fftw_fft
62-
@test P \ (P * x) x
63-
@test fftdims(P) == dims
64-
65-
fftw_bfft = complex.(size(x, dims) .* x)
66-
@test AbstractFFTs.bfft(y, dims) fftw_bfft
67-
P = plan_bfft(x, dims)
68-
@test P * y fftw_bfft
69-
@test P \ (P * y) y
70-
@test fftdims(P) == dims
71-
72-
fftw_ifft = complex.(x)
73-
@test AbstractFFTs.ifft(y, dims) fftw_ifft
74-
P = plan_ifft(x, dims)
75-
@test P * y fftw_ifft
76-
@test P \ (P * y) y
77-
@test fftdims(P) == dims
78-
79-
# real FFT
80-
fftw_rfft = fftw_fft[
81-
(Colon() for _ in 1:(ndims(fftw_fft) - 1))...,
82-
1:(size(fftw_fft, ndims(fftw_fft)) ÷ 2 + 1)
83-
]
84-
ry = AbstractFFTs.rfft(x, dims)
85-
@test ry fftw_rfft
86-
P = plan_rfft(x, dims)
87-
@test eltype(P) === Int
88-
@test P * x fftw_rfft
89-
@test P \ (P * x) x
90-
@test fftdims(P) == dims
91-
92-
fftw_brfft = complex.(size(x, dims) .* x)
93-
@test AbstractFFTs.brfft(ry, size(x, dims), dims) fftw_brfft
94-
P = plan_brfft(ry, size(x, dims), dims)
95-
@test P * ry fftw_brfft
96-
@test P \ (P * ry) ry
97-
@test fftdims(P) == dims
13+
const GROUP = get(ENV, "GROUP", "All")
9814

99-
fftw_irfft = complex.(x)
100-
@test AbstractFFTs.irfft(ry, size(x, dims), dims) fftw_irfft
101-
P = plan_irfft(ry, size(x, dims), dims)
102-
@test P * ry fftw_irfft
103-
@test P \ (P * ry) ry
104-
@test fftdims(P) == dims
105-
end
106-
end
107-
108-
@testset "Shift functions" begin
109-
@test @inferred(AbstractFFTs.fftshift([1 2 3])) == [3 1 2]
110-
@test @inferred(AbstractFFTs.fftshift([1, 2, 3])) == [3, 1, 2]
111-
@test @inferred(AbstractFFTs.fftshift([1 2 3; 4 5 6])) == [6 4 5; 3 1 2]
112-
a = [0 0 0]
113-
b = [0, 0, 0]
114-
c = [0 0 0; 0 0 0]
115-
@test (AbstractFFTs.fftshift!(a, [1 2 3]); a == [3 1 2])
116-
@test (AbstractFFTs.fftshift!(b, [1, 2, 3]); b == [3, 1, 2])
117-
@test (AbstractFFTs.fftshift!(c, [1 2 3; 4 5 6]); c == [6 4 5; 3 1 2])
118-
119-
@test @inferred(AbstractFFTs.fftshift([1 2 3; 4 5 6], 1)) == [4 5 6; 1 2 3]
120-
@test @inferred(AbstractFFTs.fftshift([1 2 3; 4 5 6], ())) == [1 2 3; 4 5 6]
121-
@test @inferred(AbstractFFTs.fftshift([1 2 3; 4 5 6], (1,2))) == [6 4 5; 3 1 2]
122-
@test @inferred(AbstractFFTs.fftshift([1 2 3; 4 5 6], 1:2)) == [6 4 5; 3 1 2]
123-
@test (AbstractFFTs.fftshift!(c, [1 2 3; 4 5 6], 1); c == [4 5 6; 1 2 3])
124-
@test (AbstractFFTs.fftshift!(c, [1 2 3; 4 5 6], ()); c == [1 2 3; 4 5 6])
125-
@test (AbstractFFTs.fftshift!(c, [1 2 3; 4 5 6], (1,2)); c == [6 4 5; 3 1 2])
126-
@test (AbstractFFTs.fftshift!(c, [1 2 3; 4 5 6], 1:2); c == [6 4 5; 3 1 2])
127-
128-
@test @inferred(AbstractFFTs.ifftshift([1 2 3])) == [2 3 1]
129-
@test @inferred(AbstractFFTs.ifftshift([1, 2, 3])) == [2, 3, 1]
130-
@test @inferred(AbstractFFTs.ifftshift([1 2 3; 4 5 6])) == [5 6 4; 2 3 1]
131-
@test (AbstractFFTs.ifftshift!(a, [1 2 3]); a == [2 3 1])
132-
@test (AbstractFFTs.ifftshift!(b, [1, 2, 3]); b == [2, 3, 1])
133-
@test (AbstractFFTs.ifftshift!(c, [1 2 3; 4 5 6]); c == [5 6 4; 2 3 1])
15+
include("TestPlans.jl")
16+
include("testfft.jl")
13417

135-
@test @inferred(AbstractFFTs.ifftshift([1 2 3; 4 5 6], 1)) == [4 5 6; 1 2 3]
136-
@test @inferred(AbstractFFTs.ifftshift([1 2 3; 4 5 6], ())) == [1 2 3; 4 5 6]
137-
@test @inferred(AbstractFFTs.ifftshift([1 2 3; 4 5 6], (1,2))) == [5 6 4; 2 3 1]
138-
@test @inferred(AbstractFFTs.ifftshift([1 2 3; 4 5 6], 1:2)) == [5 6 4; 2 3 1]
139-
@test (AbstractFFTs.ifftshift!(c, [1 2 3; 4 5 6], 1); c == [4 5 6; 1 2 3])
140-
@test (AbstractFFTs.ifftshift!(c, [1 2 3; 4 5 6], ()); c == [1 2 3; 4 5 6])
141-
@test (AbstractFFTs.ifftshift!(c, [1 2 3; 4 5 6], (1,2)); c == [5 6 4; 2 3 1])
142-
@test (AbstractFFTs.ifftshift!(c, [1 2 3; 4 5 6], 1:2); c == [5 6 4; 2 3 1])
18+
if GROUP == "All" || GROUP == "TestPlans"
19+
using .TestPlans
20+
testfft()
21+
elseif GROUP == "All" || GROUP == "FFTW" # integration test with FFTW
22+
using FFTW
23+
testfft()
14324
end
14425

145-
@testset "FFT Frequencies" begin
146-
@test fftfreq(8) isa Frequencies
147-
@test copy(fftfreq(8)) isa Frequencies
148-
149-
# N even
150-
@test fftfreq(8) == [0.0, 0.125, 0.25, 0.375, -0.5, -0.375, -0.25, -0.125]
151-
@test rfftfreq(8) == [0.0, 0.125, 0.25, 0.375, 0.5]
152-
@test fftshift(fftfreq(8)) == -0.5:0.125:0.375
153-
154-
# N odd
155-
@test fftfreq(5) == [0.0, 0.2, 0.4, -0.4, -0.2]
156-
@test rfftfreq(5) == [0.0, 0.2, 0.4]
157-
@test fftshift(fftfreq(5)) == -0.4:0.2:0.4
158-
159-
# Sampling Frequency
160-
@test fftfreq(5, 2) == [0.0, 0.4, 0.8, -0.8, -0.4]
161-
# <:Number type compatibility
162-
@test eltype(fftfreq(5, ComplexF64(2))) == ComplexF64
163-
164-
@test_throws ArgumentError Frequencies(12, 10, 1)
165-
166-
@testset "scaling" begin
167-
@test fftfreq(4, 1) * 2 === fftfreq(4, 2)
168-
@test fftfreq(4, 1) .* 2 === fftfreq(4, 2)
169-
@test 2 * fftfreq(4, 1) === fftfreq(4, 2)
170-
@test 2 .* fftfreq(4, 1) === fftfreq(4, 2)
171-
172-
@test fftfreq(4, 1) / 2 === fftfreq(4, 1/2)
173-
@test fftfreq(4, 1) ./ 2 === fftfreq(4, 1/2)
174-
175-
@test 2 \ fftfreq(4, 1) === fftfreq(4, 1/2)
176-
@test 2 .\ fftfreq(4, 1) === fftfreq(4, 1/2)
177-
end
178-
179-
@testset "extrema" begin
180-
function check_extrema(freqs)
181-
for f in [minimum, maximum, extrema]
182-
@test f(freqs) == f(collect(freqs)) == f(fftshift(freqs))
183-
end
184-
end
185-
for f in (fftfreq, rfftfreq), n in (8, 9), multiplier in (2, 1/3, -1/7, 1.0*Unitful.mm)
186-
freqs = f(n, multiplier)
187-
check_extrema(freqs)
188-
end
189-
end
190-
end
191-
192-
@testset "normalization" begin
193-
# normalization should be inferable even if region is only inferred as ::Any,
194-
# need to wrap in another function to test this (note that p.region::Any for
195-
# p::TestPlan)
196-
f9(p::Plan{T}, sz) where {T} = AbstractFFTs.normalization(real(T), sz, fftdims(p))
197-
@test @inferred(f9(plan_fft(zeros(10), 1), 10)) == 1/10
198-
end
199-
200-
@testset "ChainRules" begin
201-
@testset "shift functions" begin
202-
for x in (randn(3), randn(3, 4), randn(3, 4, 5))
203-
for dims in ((), 1, 2, (1,2), 1:2)
204-
any(d > ndims(x) for d in dims) && continue
205-
206-
# type inference checks of `rrule` fail on old Julia versions
207-
# for higher-dimensional arrays:
208-
# https://github.com/JuliaMath/AbstractFFTs.jl/pull/58#issuecomment-916530016
209-
check_inferred = ndims(x) < 3 || VERSION >= v"1.6"
210-
211-
test_frule(AbstractFFTs.fftshift, x, dims)
212-
test_rrule(AbstractFFTs.fftshift, x, dims; check_inferred=check_inferred)
213-
214-
test_frule(AbstractFFTs.ifftshift, x, dims)
215-
test_rrule(AbstractFFTs.ifftshift, x, dims; check_inferred=check_inferred)
216-
end
217-
end
218-
end
219-
220-
@testset "fft" begin
221-
for x in (randn(3), randn(3, 4), randn(3, 4, 5))
222-
N = ndims(x)
223-
complex_x = complex.(x)
224-
for dims in unique((1, 1:N, N))
225-
for f in (fft, ifft, bfft)
226-
test_frule(f, x, dims)
227-
test_rrule(f, x, dims)
228-
test_frule(f, complex_x, dims)
229-
test_rrule(f, complex_x, dims)
230-
end
231-
232-
test_frule(rfft, x, dims)
233-
test_rrule(rfft, x, dims)
234-
235-
for f in (irfft, brfft)
236-
for d in (2 * size(x, first(dims)) - 1, 2 * size(x, first(dims)) - 2)
237-
test_frule(f, x, d, dims)
238-
test_rrule(f, x, d, dims)
239-
test_frule(f, complex_x, d, dims)
240-
test_rrule(f, complex_x, d, dims)
241-
end
242-
end
243-
end
244-
end
245-
end
246-
end

0 commit comments

Comments
 (0)