Skip to content

Commit 4310c6e

Browse files
authored
Add tests for Polynomial spaces (#493)
* Add tests for Polynomial spaces * fix cachediterator test
1 parent 1dbbcdf commit 4310c6e

13 files changed

+3297
-2
lines changed

Project.toml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,32 @@ DSP = "0.6, 0.7"
3939
DomainSets = "0.5, 0.6"
4040
DualNumbers = "0.6.2"
4141
FFTW = "0.3, 1"
42+
FastGaussQuadrature = "0.4, 0.5"
43+
FastTransforms = "0.12, 0.13, 0.14, 0.15.1"
4244
FillArrays = "0.11, 0.12, 0.13, 1"
45+
HalfIntegers = "1.5"
4346
InfiniteArrays = "0.11, 0.12"
4447
InfiniteLinearAlgebra = "0.5, 0.6"
4548
Infinities = "0.1"
4649
IntervalSets = "0.5, 0.6, 0.7"
4750
LazyArrays = "0.20, 0.21, 0.22, 1"
4851
LowRankApprox = "0.2, 0.3, 0.4, 0.5"
52+
OddEvenIntegers = "0.1.8"
4953
SimpleTraits = "0.9"
5054
SpecialFunctions = "0.10, 1.0, 2"
55+
Static = "0.8"
5156
StaticArrays = "0.12, 1.0"
5257
julia = "1.6"
5358

5459
[extras]
5560
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
61+
FastGaussQuadrature = "442a2c76-b920-505d-bb47-c5924d526838"
62+
FastTransforms = "057dd010-8810-581a-b7be-e3fc3b93f78c"
63+
HalfIntegers = "f0d1745a-41c9-11e9-1dd9-e5d34d218721"
5664
Infinities = "e1ba4f0e-776d-440f-acd9-e1d2e9742647"
65+
OddEvenIntegers = "8d37c425-f37a-4ca2-9b9d-a61bc06559d2"
5766
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
67+
Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
5868

5969
[targets]
60-
test = ["Aqua", "Random", "Infinities"]
70+
test = ["Aqua", "Random", "FastTransforms", "FastGaussQuadrature", "HalfIntegers", "Infinities", "OddEvenIntegers", "Static"]

test/AFOP/Chebyshev/Chebyshev.jl

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
2+
export Chebyshev, NormalizedChebyshev
3+
4+
"""
5+
`Chebyshev()` is the space spanned by the Chebyshev polynomials
6+
```
7+
T_0(x),T_1(x),T_2(x),…
8+
```
9+
where `T_k(x) = cos(k*acos(x))`. This is the default space
10+
as there exists a fast transform and general smooth functions on `[-1,1]`
11+
can be easily resolved.
12+
"""
13+
struct Chebyshev{D<:Domain,R} <: PolynomialSpace{D,R}
14+
domain::D
15+
function Chebyshev{D,R}(d) where {D,R}
16+
isempty(d) && throw(ArgumentError("Domain cannot be empty"))
17+
new(d)
18+
end
19+
Chebyshev{D,R}() where {D,R} = new(strictconvert(D, ChebyshevInterval()))
20+
end
21+
22+
Chebyshev(d::Domain) = Chebyshev{typeof(d),real(prectype(d))}(d)
23+
Chebyshev() = Chebyshev(ChebyshevInterval())
24+
Chebyshev(d) = Chebyshev(Domain(d))
25+
const NormalizedChebyshev{D<:Domain,R} = NormalizedPolynomialSpace{Chebyshev{D, R}, D, R}
26+
NormalizedChebyshev() = NormalizedPolynomialSpace(Chebyshev())
27+
NormalizedChebyshev(d) = NormalizedPolynomialSpace(Chebyshev(d))
28+
29+
function Base.getproperty(S::Chebyshev{<:Any,<:Any},v::Symbol)
30+
if v==:b || v==:a
31+
-0.5
32+
else
33+
getfield(S,v)
34+
end
35+
end
36+
37+
normalization(::Type{T}, sp::Chebyshev, k::Int) where T = T(π)/(2-FastTransforms.δ(k,0))
38+
39+
Space(d::SegmentDomain) = Chebyshev(d)
40+
_norm(x) = norm(x)
41+
_norm(x::Real) = abs(x) # this preserves integers, whereas norm returns a float
42+
function Space(d::AbstractInterval)
43+
a,b = endpoints(d)
44+
d2 = if isinf(_norm(a)) && isinf(_norm(b))
45+
Line(d)
46+
elseif isinf(_norm(a)) || isinf(_norm(b))
47+
Ray(d)
48+
else
49+
d
50+
end
51+
Chebyshev(d2)
52+
end
53+
54+
55+
setdomain(S::Chebyshev, d::Domain) = Chebyshev(d)
56+
57+
ones(::Type{T}, S::Chebyshev) where {T<:Number} = Fun(S,fill(one(T),1))
58+
ones(S::Chebyshev) = Fun(S,fill(1.0,1))
59+
60+
function first(f::Fun{<:Chebyshev})
61+
n = ncoefficients(f)
62+
n == 0 && return zero(cfstype(f))
63+
n == 1 && return f.coefficients[1]
64+
foldr(-,coefficients(f))
65+
end
66+
67+
last(f::Fun{<:Chebyshev}) = reduce(+,coefficients(f))
68+
69+
spacescompatible(a::Chebyshev,b::Chebyshev) = domainscompatible(a,b)
70+
hasfasttransform(::Chebyshev) = true
71+
supportsinplacetransform(::Chebyshev{<:Domain{T},T}) where {T<:AbstractFloat} = true
72+
73+
74+
## Transform
75+
76+
transform(::Chebyshev,vals::AbstractVector,plan) = plan*vals
77+
itransform(::Chebyshev,cfs::AbstractVector,plan) = plan*cfs
78+
plan_transform(::Chebyshev,vals::AbstractVector) = plan_chebyshevtransform(vals)
79+
plan_itransform(::Chebyshev,cfs::AbstractVector) = plan_ichebyshevtransform(cfs)
80+
plan_transform!(::Chebyshev, vals::AbstractVector) = plan_chebyshevtransform!(vals)
81+
plan_itransform!(::Chebyshev, cfs::AbstractVector) = plan_ichebyshevtransform!(cfs)
82+
83+
## Evaluation
84+
85+
clenshaw(sp::Chebyshev, c::AbstractVector, x::AbstractArray) =
86+
clenshaw(c,x,ClenshawPlan(promote_type(eltype(c),eltype(x)),sp,length(c),length(x)))
87+
88+
clenshaw(::Chebyshev,c::AbstractVector,x) = chebyshev_clenshaw(c,x)
89+
90+
clenshaw(c::AbstractVector,x::AbstractVector,plan::ClenshawPlan{S,V}) where {S<:Chebyshev,V}=
91+
clenshaw(c,collect(x),plan)
92+
93+
#TODO: This modifies x, which is not threadsafe
94+
clenshaw(c::AbstractVector,x::Vector,plan::ClenshawPlan{<:Chebyshev}) = chebyshev_clenshaw(c,x,plan)
95+
96+
function clenshaw(c::AbstractMatrix{T},x::T,plan::ClenshawPlan{S,T}) where {S<:Chebyshev,T<:Number}
97+
bk=plan.bk
98+
bk1=plan.bk1
99+
bk2=plan.bk2
100+
101+
m,n=size(c) # m is # of coefficients, n is # of funs
102+
103+
@inbounds for i = 1:n
104+
bk1[i] = zero(T)
105+
bk2[i] = zero(T)
106+
end
107+
x = 2x
108+
109+
@inbounds for k=m:-1:2
110+
for j=1:n
111+
ck = c[k,j]
112+
bk[j] = muladd(x,bk1[j],ck - bk2[j])
113+
end
114+
bk2, bk1, bk = bk1, bk, bk2
115+
end
116+
117+
x = x/2
118+
@inbounds for i = 1:n
119+
ce = c[1,i]
120+
bk[i] = muladd(x,bk1[i],ce - bk2[i])
121+
end
122+
123+
bk
124+
end
125+
126+
function clenshaw(c::AbstractMatrix{T},x::AbstractVector{T},plan::ClenshawPlan{S,T}) where {S<:Chebyshev,T<:Number}
127+
bk=plan.bk
128+
bk1=plan.bk1
129+
bk2=plan.bk2
130+
131+
m,n=size(c) # m is # of coefficients, n is # of funs
132+
133+
@inbounds for i = 1:n
134+
x[i] = 2x[i]
135+
bk1[i] = zero(T)
136+
bk2[i] = zero(T)
137+
end
138+
139+
@inbounds for k=m:-1:2
140+
for j=1:n
141+
ck = c[k,j]
142+
bk[j] = muladd(x[j],bk1[j],ck - bk2[j])
143+
end
144+
bk2, bk1, bk = bk1, bk, bk2
145+
end
146+
147+
148+
@inbounds for i = 1:n
149+
x[i] = x[i]/2
150+
ce = c[1,i]
151+
bk[i] = muladd(x[i],bk1[i],ce - bk2[i])
152+
end
153+
154+
bk
155+
end
156+
157+
# overwrite x
158+
159+
function clenshaw!(c::AbstractVector,x::AbstractVector,plan::ClenshawPlan{S,V}) where {S<:Chebyshev,V}
160+
N,n = length(c),length(x)
161+
162+
if isempty(c)
163+
fill!(x,0)
164+
return x
165+
end
166+
167+
bk=plan.bk
168+
bk1=plan.bk1
169+
bk2=plan.bk2
170+
171+
@inbounds for i = 1:n
172+
x[i] = 2x[i]
173+
bk1[i] = zero(V)
174+
bk2[i] = zero(V)
175+
end
176+
177+
@inbounds for k = N:-1:2
178+
ck = c[k]
179+
for i = 1:n
180+
bk[i] = muladd(x[i],bk1[i],ck - bk2[i])
181+
end
182+
bk2, bk1, bk = bk1, bk, bk2
183+
end
184+
185+
ce = c[1]
186+
@inbounds for i = 1:n
187+
x[i] = x[i]/2
188+
x[i] = muladd(x[i],bk1[i],ce-bk2[i])
189+
end
190+
191+
x
192+
end
193+
194+
## Calculus
195+
196+
197+
# diff T -> U, then convert U -> T
198+
integrate(f::Fun{Chebyshev{D,R}}) where {D<:IntervalOrSegment,R} =
199+
Fun(f.space,fromcanonicalD(f,0)*ultraint!(ultraconversion(f.coefficients)))
200+
differentiate(f::Fun{Chebyshev{D,R}}) where {D<:IntervalOrSegment,R} =
201+
Fun(f.space,1/fromcanonicalD(f,0)*ultraiconversion(ultradiff(f.coefficients)))
202+
203+
204+
205+
206+
207+
## Multivariate
208+
209+
# determine correct parameter to have at least
210+
# N point
211+
_padua_length(N) = Int(cld(-3+sqrt(1+8N),2))
212+
213+
function squarepoints(::Type{T}, N) where T
214+
pts = paduapoints(T, _padua_length(N))
215+
n = size(pts,1)
216+
ret = Array{SVector{2,T}}(undef, n)
217+
@inbounds for k=1:n
218+
ret[k] = SVector{2,T}(pts[k,1],pts[k,2])
219+
end
220+
ret
221+
end
222+
223+
points(S::TensorSpace{<:Tuple{<:Chebyshev{<:ChebyshevInterval},<:Chebyshev{<:ChebyshevInterval}}}, N) =
224+
squarepoints(real(prectype(S)), N)
225+
226+
function points(S::TensorSpace{<:Tuple{<:Chebyshev,<:Chebyshev}},N)
227+
T = real(prectype(S))
228+
pts = squarepoints(T, N)
229+
pts .= fromcanonical.(Ref(domain(S)), pts)
230+
pts
231+
end
232+
233+
plan_transform(S::TensorSpace{<:Tuple{<:Chebyshev,<:Chebyshev}},v::AbstractVector) =
234+
plan_paduatransform!(v,Val{false})
235+
236+
transform(S::TensorSpace{<:Tuple{<:Chebyshev,<:Chebyshev}},v::AbstractVector,
237+
plan=plan_transform(S,v)) = plan*copy(v)
238+
239+
plan_itransform(S::TensorSpace{<:Tuple{<:Chebyshev,<:Chebyshev}},v::AbstractVector) =
240+
plan_ipaduatransform!(eltype(v),sum(1:Int(block(S,length(v)))),Val{false})
241+
242+
itransform(S::TensorSpace{<:Tuple{<:Chebyshev,<:Chebyshev}},v::AbstractVector,
243+
plan=plan_itransform(S,v)) = plan*pad(v,sum(1:Int(block(S,length(v)))))
244+
245+
246+
#TODO: adaptive
247+
for op in (:(Base.sin),:(Base.cos))
248+
@eval ($op)(f::ProductFun{<:Chebyshev,<:Chebyshev}) =
249+
ProductFun(chebyshevtransform($op.(values(f))),space(f))
250+
end
251+
252+
253+
254+
reverseorientation(f::Fun{<:Chebyshev}) =
255+
Fun(Chebyshev(reverseorientation(domain(f))),alternatesign!(copy(f.coefficients)))
256+
257+
258+
include("ChebyshevOperators.jl")

0 commit comments

Comments
 (0)