Skip to content

Commit 051a6f1

Browse files
authored
Conversion between Fourier spaces (#41)
* conversion between Fourier * Tests * require one endpoint to match * Tests for coefficients * cancel concurrent CI runs * remove rounding in div * use union instead of union_by_union_rule * fix indexing for higher multiples * Add tests * remove unused names * fix sum with scaled/sum domains * fix bugfix with pts * clean-up imports --------- Co-authored-by: Jishnu Bhattacharya <jishnub@users.noreply.github.com>
1 parent 0264a39 commit 051a6f1

File tree

3 files changed

+125
-4
lines changed

3 files changed

+125
-4
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ on:
1212
- 'LICENSE'
1313
- 'README.md'
1414
- '.github/workflows/TagBot.yml'
15+
16+
concurrency:
17+
group: build-${{ github.event.pull_request.number || github.ref }}
18+
cancel-in-progress: true
19+
1520
jobs:
1621
pre_job:
1722
# continue-on-error: true # Uncomment once integration is finished

src/ApproxFunFourier.jl

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ using DomainSets
4343
import DomainSets: Domain, indomain, UnionDomain, Point, Interval,
4444
boundary, rightendpoint, leftendpoint, endpoints
4545

46-
import Base: convert, getindex, *, +, -, ==, /, eltype,
47-
show, sum, cumsum, conj, issubset, first, last, rand, setdiff,
48-
angle, isempty, zeros, one, promote_rule, real, imag
46+
import Base: convert, getindex, *, +, -, ==, /, eltype,
47+
show, sum, conj, issubset, first, last, rand, setdiff,
48+
union, angle, isempty, one, promote_rule, real, imag
4949

5050
import LinearAlgebra: norm, mul!, isdiag
5151

@@ -531,6 +531,74 @@ canonicalspace(S::Laurent{DD,RR}) where {DD<:PeriodicSegment,RR} = Fourier(domai
531531
canonicalspace(S::Fourier{DD,RR}) where {DD<:Circle,RR} = Laurent(domain(S))
532532
canonicalspace(S::Laurent{DD,RR}) where {DD<:PeriodicLine,RR} = S
533533

534+
# avoid cyclic recursion between CosSpace and Fourier
535+
# check if one domain is a multiple of another
536+
# return the multiple
537+
period(F::Fourier) = period(domain(F))
538+
function period(A::Domain)
539+
la, ra = leftendpoint(A), rightendpoint(A)
540+
ra - la
541+
end
542+
function domainsmultiple(A::Domain, B::Domain)
543+
isapprox(A, B) && return 1
544+
la, ra = leftendpoint(A), rightendpoint(A)
545+
lb, rb = leftendpoint(B), rightendpoint(B)
546+
pa = ra - la
547+
pb = rb - lb
548+
dmin, dmax = minmax(pa, pb)
549+
T = promote_type(eltype(A), eltype(B))
550+
if isapprox(mod(dmax, dmin), 0, atol=eps(T)) && isapprox(la, lb, atol=eps(T)) || isapprox(ra, rb, atol=eps(T))
551+
return round(Int, dmax/dmin, RoundNearest)
552+
end
553+
return nothing
554+
end
555+
domainsmultiple(A::Space, B::Space) = domainsmultiple(map(domain, (A,B))...)
556+
# check if one domain may be scaled to obtain the other
557+
function domainsscaled(A::Domain, B::Domain)
558+
la, ra = leftendpoint(A), rightendpoint(A)
559+
lb, rb = leftendpoint(B), rightendpoint(B)
560+
pa = ra - la
561+
pb = rb - lb
562+
dmin, dmax = minmax(pa, pb)
563+
T = promote_type(eltype(A), eltype(B))
564+
if isapprox(la, lb, atol=eps(T)) || isapprox(ra, rb, atol=eps(T))
565+
return Rational(dmax/dmin)
566+
end
567+
return nothing
568+
end
569+
domainsscaled(A::Space, B::Space) = domainsscaled(map(domain, (A,B))...)
570+
function union(A::Fourier, B::Fourier)
571+
dA, dB = map(domain, (A,B))
572+
AB = domainsmultiple(dA, dB)
573+
isnothing(AB) || return Fourier(max(dA, dB))
574+
scale = domainsscaled(dA, dB)
575+
isnothing(scale) || return Fourier(max(dA, dB) * denominator(scale))
576+
SumSpace(A, B)
577+
end
578+
_ind(i, n) = 2n * div(i, 2) + isodd(i)
579+
_invind(i, n) = 2div(i - isodd(i), 2n) + isodd(i)
580+
function coefficients(v::AbstractVector, A::Fourier, B::Fourier)
581+
n = domainsmultiple(A, B)
582+
isnothing(n) && error("spaces are not compatible")
583+
n == 1 && return copy(v)
584+
if period(A) < period(B)
585+
v2 = zeros(eltype(v), _ind(length(v), n))
586+
for (i, vi) in enumerate(v)
587+
v2[_ind(i, n)] = vi
588+
end
589+
else
590+
for (ind, vi) in enumerate(v)
591+
if isodd(div(ind, n)) && !isapprox(vi, 0, atol=eps(eltype(vi)))
592+
throw(ArgumentError("coefficients incompatible with space conversion"))
593+
end
594+
end
595+
v2 = zeros(eltype(v), _invind(length(v), n))
596+
for i in eachindex(v2)
597+
v2[i] = v[_ind(i, n)]
598+
end
599+
end
600+
return v2
601+
end
534602

535603
## Ones and zeros
536604

test/runtests.jl

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,62 @@ end
189189
@test norm(ApproxFunBase.Reverse(Fourier())*Fun(t->cos(cos(t-0.2)-0.1),Fourier()) - Fun(t->cos(cos(-t-0.2)-0.1),Fourier())) < 10eps()
190190
@test norm(ApproxFunBase.ReverseOrientation(Fourier())*Fun(t->cos(cos(t-0.2)-0.1),Fourier()) - Fun(t->cos(cos(t-0.2)-0.1),Fourier(PeriodicSegment(2π,0)))) < 10eps()
191191

192-
@testset "issue #741" begin
192+
@testset "ApproxFun issue #741" begin
193193
c = Fun(cos, Fourier())
194194
@test roots(c) (1:2:3) * pi/2
195195
c = Fun(cos, Fourier(0..4pi))
196196
@test roots(c) (1:2:7) * pi/2
197197
c = Fun(cos, Fourier(-2pi..2pi))
198198
@test roots(c) (-3:2:3) * pi/2
199199
end
200+
201+
@testset "ApproxFun issue #768" begin
202+
s1 = Fourier(0..pi)
203+
f1 = Fun(t -> sin(2*t),s1)
204+
@testset for d2 in [0..2pi, 0..3pi]
205+
s2 = Fourier(d2)
206+
f2 = Fun(t -> sin(2*t),s2)
207+
g = f1 + f2
208+
@test g(pi/3) f1(pi/3) + f2(pi/3)
209+
end
210+
f1 = Fun(sin, Fourier(0..2pi));
211+
f2 = Fun(x->sin((2/3)x), Fourier(0..3pi));
212+
g = f1 + f2
213+
pts = [0:6;]*pi
214+
@test g.(pts) f1.(pts) .+ f2.(pts)
215+
h = Fun(x-> sin(x)+sin(2*x/3),Fourier(0..6pi))
216+
@test g.(pts) h.(pts)
217+
218+
f1 = Fun(x->sin(2x), Fourier(pi..2pi))
219+
f2 = Fun(x->sin(2x), Fourier(3pi..4pi))
220+
g = f1 + f2
221+
pts = [0:5;]*pi
222+
@test g.(pts) f1.(pts) .+ f2.(pts)
223+
end
224+
225+
@testset "coeff conversion" begin
226+
f = t->1+2sin(t)+3cos(t)
227+
f1 = Fun(f, Fourier(0..2pi))
228+
229+
f2 = Fun(f, Fourier(0..4pi))
230+
@test coefficients(coefficients(f1), space(f1), space(f2)) coefficients(f2)
231+
232+
f3 = Fun(f, Fourier(0..8pi))
233+
@test coefficients(coefficients(f1), space(f1), space(f3)) coefficients(f3)
234+
235+
@test coefficients([1,0,0,2,3], Fourier(0..4pi), Fourier(0..2pi)) [1,2,3]
236+
@test coefficients([1,2,3], Fourier(0..2pi), Fourier(0..4pi)) [1; zeros(2); [2,3]]
237+
@test coefficients([1; zeros(2); [2,3]], Fourier(0..4pi), Fourier(0..2pi)) [1,2,3]
238+
@test coefficients([4,1], Fourier(0..2pi), Fourier(0..4pi)) [4; zeros(2); 1]
239+
@test coefficients([4,1], Fourier(0..2pi), Fourier(0..8pi)) [4; zeros(6); 1]
240+
@test coefficients([4,1,2], Fourier(0..2pi), Fourier(0..4pi)) [4; zeros(2); [1, 2]]
241+
@test coefficients([4,1,2], Fourier(0..2pi), Fourier(0..8pi)) [4; zeros(6); [1, 2]]
242+
@test coefficients([4,1,2,3], Fourier(0..2pi), Fourier(0..4pi)) [4; zeros(2); [1, 2]; zeros(2); 3]
243+
@test coefficients([4,1,2,3], Fourier(0..2pi), Fourier(0..6pi)) [4; zeros(4); [1, 2]; zeros(4); 3]
244+
@test coefficients([4,1,2,3], Fourier(0..2pi), Fourier(0..8pi)) [4; zeros(6); [1, 2]; zeros(6); 3]
245+
@test coefficients([4; zeros(4); [1, 2]; zeros(4); 3], Fourier(0..6pi), Fourier(0..2pi)) [4,1,2,3]
246+
@test coefficients([4; zeros(6); [1, 2]; zeros(6); 3], Fourier(0..8pi), Fourier(0..2pi)) [4,1,2,3]
247+
end
200248
end
201249

202250
@testset "Laurent" begin

0 commit comments

Comments
 (0)