Skip to content

Commit fdf090f

Browse files
committed
Usability improvements for orthogonal polynomials
1 parent 2e5d6fb commit fdf090f

File tree

17 files changed

+177
-36
lines changed

17 files changed

+177
-36
lines changed

Project.toml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "BasisFunctions"
22
uuid = "4343a256-5453-507d-8aad-01a9d7189916"
33
authors = ["Daan Huybrechs <daan.huybrechs@kuleuven.be>"]
4-
version = "0.6.5"
4+
version = "0.6.6"
55

66
[deps]
77
BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
@@ -38,25 +38,30 @@ BasisFunctionsPGFPlotsXExt = "PGFPlotsX"
3838

3939
[compat]
4040
BlockArrays = "0.16"
41+
Calculus = "0.5"
4142
CompositeTypes = "0.1.3"
4243
DomainIntegrals = "0.4.5"
4344
DomainSets = "0.7"
45+
DoubleFloats = "1"
4446
FFTW = "1.6"
4547
FastGaussQuadrature = "0.4,0.5"
4648
FillArrays = "0.13,1"
4749
GaussQuadrature = "0.5.7"
4850
GenericFFT = "0.1.3"
4951
GenericLinearAlgebra = "0.3"
50-
GridArrays = "0.2.2"
52+
GridArrays = "0.2.3"
5153
IterativeSolvers = "0.9"
54+
LinearAlgebra = "1"
5255
MacroTools = "0.5"
5356
OrderedCollections = "1.2"
5457
PGFPlotsX = "1.4"
5558
QuadGK = "2.4"
59+
Random = "1"
5660
RecipesBase = "1.0"
5761
Reexport = "1.0"
5862
SpecialFunctions = "1.0, 2.0"
5963
StaticArrays = "1.4"
64+
Test = "1"
6065
ToeplitzMatrices = "0.7"
6166
julia = "1.9"
6267

src/BasisFunctions.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,8 @@ export Legendre, Jacobi, Laguerre, Hermite,
300300
recurrence_eval, recurrence_eval_derivative, monic_recurrence_eval,
301301
monic_recurrence_coefficients,
302302
symmetric_jacobi_matrix, roots, gauss_rule, sorted_gauss_rule, first_moment,
303-
leading_order_coefficient
303+
leading_order_coefficient,
304+
ops_roots
304305

305306
# from specialOPS.jl
306307
export HalfRangeChebyshevIkind, HalfRangeChebyshevIIkind, WaveOPS,

src/bases/dictionary/basisfunction.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,25 @@ promote_rule(::Type{<:TypedFunction{S1,T1}}, ::Type{<:TypedFunction{S2,T2}}) whe
2323
"The supertype of functions that can be associated with a dictionary or a family of basis functions."
2424
abstract type AbstractBasisFunction{S,T} <: TypedFunction{S,T} end
2525

26+
function expansion::AbstractBasisFunction)
27+
coef = zeros(dictionary(φ))
28+
coef[index(φ)] = 1
29+
expansion(dictionary(φ), coef)
30+
end
31+
32+
roots::AbstractBasisFunction) = roots(expansion(φ))
33+
34+
function Base.:^::AbstractBasisFunction, i::Int)
35+
@assert i >= 0
36+
if i == 1
37+
φ
38+
elseif i == 2
39+
φ * φ
40+
else
41+
φ^(i-1) * φ
42+
end
43+
end
44+
2645
"A `BasisFunction` is one element of a dictionary."
2746
struct BasisFunction{S,T,D<:Dictionary{S,T},I} <: AbstractBasisFunction{S,T}
2847
dictionary :: D

src/bases/dictionary/expansions.jl

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,17 @@ ei(dim,i, coefficients) = tuple((coefficients*Matrix{Int}(I, dim, dim)[:,i])...)
119119
differentiate(f::Expansion, var, order) = differentiate(f, ei(dimension(f), var, order))
120120
antidifferentiate(f::Expansion, var, order) = antidifferentiate(f, ei(dimension(f), var, order))
121121

122+
function Base.:^(f::Expansion, i::Int)
123+
@assert i >= 0
124+
if i == 1
125+
f
126+
elseif i == 2
127+
f * f
128+
else
129+
f^(i-1) * f
130+
end
131+
end
132+
122133
# To be implemented: Laplacian (needs multiplying functions)
123134
## Δ(f::Expansion)
124135

@@ -127,7 +138,9 @@ adjoint(f::Expansion) = differentiate(f)
127138

128139
(f::Expansion) = antidifferentiate(f)
129140

130-
roots(f::Expansion) = roots(dictionary(f), coefficients(f))
141+
roots(f::Expansion) = expansion_roots(dictionary(f), coefficients(f))
142+
143+
Base.@deprecate roots(dict::Dictionary, coef::AbstractVector) expansion_roots(dict, coef)
131144

132145
show(io::IO, mime::MIME"text/plain", fun::Expansion) = composite_show(io, mime, fun)
133146
Display.displaystencil(fun::Expansion) = ["Expansion(", dictionary(fun), ", ", coefficients(fun), ")"]
@@ -146,7 +159,10 @@ iscompatible(d1::Dictionary, d2::Dictionary) = false
146159

147160
iscompatible(e1::Expansion, e2::Expansion) = iscompatible(dictionary(e1),dictionary(e2))
148161

149-
function compatible_dictionary(d1::Dictionary, d2::Dictionary)
162+
compatible_dictionary(d1::Dictionary, d2::Dictionary) =
163+
default_compatible_dictionary(d1, d2)
164+
165+
function default_compatible_dictionary(d1::Dictionary, d2::Dictionary)
150166
if d1 == d2
151167
d1
152168
else
@@ -184,7 +200,6 @@ function to_compatible_expansions(e1::Expansion, e2::Expansion)
184200
end
185201

186202
function (+)(f::Expansion, g::Expansion)
187-
@assert iscompatible(f, g)
188203
dict, coef = expansion_sum(dictionary(f),dictionary(g),coefficients(f),coefficients(g))
189204
Expansion(dict, coef)
190205
end
@@ -208,7 +223,7 @@ function expansion_sum2(dict1, dict2, coef1, coef2)
208223
if iscompatible(dict1, dict2)
209224
default_expansion_sum(dict1, dict2, coef1, coef2)
210225
else
211-
error("Multiplication of expansions in these dictionaries is not implemented.")
226+
error("Summation of expansions in these dictionaries is not implemented.")
212227
end
213228
end
214229

@@ -265,3 +280,23 @@ iterate(e::Expansion, state) = iterate(coefficients(e), state)
265280
Base.collect(e::Expansion) = coefficients(e)
266281

267282
Base.BroadcastStyle(e::Expansion) = Base.Broadcast.DefaultArrayStyle{dimension(e)}()
283+
284+
# Interoperate with basis functions.
285+
# TODO: implement cleaner using promotion mechanism
286+
287+
Base.:*(φ1::AbstractBasisFunction, φ2::AbstractBasisFunction) = expansion(φ1) * expansion(φ2)
288+
Base.:*(f::Expansion, φ2::AbstractBasisFunction) = f * expansion(φ2)
289+
Base.:*(φ1::AbstractBasisFunction, f::Expansion) = expansion(φ1) * f
290+
291+
Base.:*(A::Number, φ::AbstractBasisFunction) = A * expansion(φ)
292+
Base.:*::AbstractBasisFunction, A::Number) = A * expansion(φ)
293+
294+
Base.:+(φ1::AbstractBasisFunction, φ2::AbstractBasisFunction) = expansion(φ1) + expansion(φ2)
295+
Base.:+(f::Expansion, φ2::AbstractBasisFunction) = f + expansion(φ2)
296+
Base.:+(φ1::AbstractBasisFunction, f::Expansion) = expansion(φ1) + f
297+
298+
Base.:-(φ1::AbstractBasisFunction, φ2::AbstractBasisFunction) = expansion(φ1) - expansion(φ2)
299+
Base.:-(f::Expansion, φ2::AbstractBasisFunction) = f - expansion(φ2)
300+
Base.:-(φ1::AbstractBasisFunction, f::Expansion) = expansion(φ1) - f
301+
302+

src/bases/modifiers/mapped_dict.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,8 @@ function expansion_multiply(dict1::MappedDict, dict2::MappedDict, coef_src1, coe
362362
mapped_dict(mset, forward_map(dict1)), mcoef
363363
end
364364

365-
function roots(dict::MappedDict, coef)
366-
r = roots(superdict(dict), coef)
365+
function expansion_roots(dict::MappedDict, coef)
366+
r = expansion_roots(superdict(dict), coef)
367367
forward_map(dict).(r)
368368
end
369369

src/bases/modifiers/operated_dict.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ function (*)(op::DictionaryOperator, dict::OperatedDict)
308308
OperatedDict(operator(dict) op)
309309
end
310310

311-
roots(dict::OperatedDict, coef) = roots(superdict(dict), operator(dict)*coef)
311+
expansion_roots(dict::OperatedDict, coef) = expansion_roots(superdict(dict), operator(dict)*coef)
312312

313313
expansion_multiply1(dict1::OperatedDict, dict2, coef1, coef2) =
314314
expansion_multiply(superdict(dict1), dict2, operator(dict1)*coef1, coef2)

src/bases/poly/chebyshev/ChebyshevT.jl

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"""
33
A basis of Chebyshev polynomials of the first kind on the interval `[-1,1]`.
44
"""
5-
struct ChebyshevT{T} <: OPS{T}
5+
struct ChebyshevT{T} <: IntervalOPS{T}
66
n :: Int
77
end
88

@@ -11,8 +11,17 @@ show(io::IO, d::ChebyshevT{T}) where T = print(io, "ChebyshevT{$(T)}($(length(d)
1111

1212
ChebyshevT(n::Int) = ChebyshevT{Float64}(n)
1313

14+
ChebyshevT(d::PolynomialDegree) = ChebyshevT(value(d)+1)
15+
ChebyshevT{T}(d::PolynomialDegree) where T = ChebyshevT{T}(value(d)+1)
16+
1417
similar(b::ChebyshevT, ::Type{T}, n::Int) where {T} = ChebyshevT{T}(n)
1518

19+
to_chebyshev_dict(dict::IntervalOPS{T}) where T = ChebyshevT{T}(length(dict))
20+
to_chebyshev(f) = to_chebyshev(expansion(f))
21+
to_chebyshev(f::Expansion) = to_chebyshev(dictionary(f), coefficients(f))
22+
to_chebyshev(dict::Dictionary, coef) =
23+
conversion(dict, to_chebyshev_dict(dict)) * expansion(dict, coef)
24+
1625
convert(::Type{ChebyshevT{T}}, d::ChebyshevT) where {T} = ChebyshevT{T}(d.n)
1726

1827
"Mapped Chebyshev polynomials."
@@ -63,8 +72,6 @@ rec_An(b::ChebyshevT{T}, n::Int) where {T} = n==0 ? one(T) : 2one(T)
6372
rec_Bn(b::ChebyshevT{T}, n::Int) where {T} = zero(T)
6473
rec_Cn(b::ChebyshevT{T}, n::Int) where {T} = one(T)
6574

66-
support(b::ChebyshevT{T}) where {T} = ChebyshevInterval{T}()
67-
6875
# We can define this O(1) evaluation method, but only for points that are
6976
# real and lie in [-1,1]
7077
# Note that if x is not Real, recurrence_eval will be called by the OPS supertype
@@ -178,7 +185,8 @@ end
178185
transform_from_grid(T, src::GridBasis, dest::ChebyshevT, grid; options...) =
179186
inv(transform_to_grid(T, dest, src, grid; options...))
180187

181-
function roots(dict::ChebyshevT, coefficients::AbstractVector)
188+
function expansion_roots(dict::ChebyshevT, coefficients::AbstractVector)
189+
@assert length(dict) == length(coefficients)
182190
T = eltype(coefficients)
183191
n = length(dict)-1
184192
# construct the colleague matrix (according to ATAP)

src/bases/poly/chebyshev/ChebyshevU.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11

22
"A basis of Chebyshev polynomials of the second kind on the interval `[-1,1]`."
3-
struct ChebyshevU{T} <: OPS{T}
3+
struct ChebyshevU{T} <: IntervalOPS{T}
44
n :: Int
55
end
66

77
ChebyshevU(n::Int) = ChebyshevU{Float64}(n)
88

9+
ChebyshevU(d::PolynomialDegree) = ChebyshevU(value(d)+1)
10+
ChebyshevU{T}(d::PolynomialDegree) where T = ChebyshevU{T}(value(d)+1)
11+
912
similar(b::ChebyshevU, ::Type{T}, n::Int) where {T} = ChebyshevU{T}(n)
1013

1114
show(io::IO, d::ChebyshevU{Float64}) = print(io, "ChebyshevU($(length(d)))")
@@ -49,8 +52,6 @@ rec_Bn(b::ChebyshevU{T}, n::Int) where {T} = zero(T)
4952

5053
rec_Cn(b::ChebyshevU{T}, n::Int) where {T} = one(T)
5154

52-
support(b::ChebyshevU{T}) where {T} = ChebyshevInterval{T}()
53-
5455

5556
"A Chebyshev polynomial of the second kind"
5657
struct ChebyshevUPolynomial{T} <: OrthogonalPolynomial{T}

src/bases/poly/monomials.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ Monomials(n) = Monomials{Float64}(n)
1212
show(io::IO, b::Monomials{Float64}) = print(io, "Monomials($(length(b)))")
1313
show(io::IO, b::Monomials{T}) where T = print(io, "Monomials{$(T)}($(length(b)))")
1414

15+
to_monomials_dict(dict::PolynomialBasis{T}) where T = Monomials{T}(length(dict))
16+
to_monomials(f) = to_monomials(expansion(f))
17+
to_monomials(f::Expansion) = to_monomials(dictionary(f), coefficients(f))
18+
to_monomials(dict::Dictionary, coef) = conversion(dict, to_monomials_dict(dict)) * expansion(dict, coef)
19+
1520
support(dict::Monomials{T}) where {T} = DomainSets.FullSpace{T}()
1621

1722
size(dict::Monomials) = (dict.n,)

src/bases/poly/ops/hermite.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ end
1010

1111
Hermite(n::Int) = Hermite{Float64}(n)
1212

13+
Hermite(d::PolynomialDegree) = Hermite(value(d)+1)
14+
Hermite{T}(d::PolynomialDegree) where T = Hermite{T}(value(d)+1)
15+
1316
similar(b::Hermite, ::Type{T}, n::Int) where {T} = Hermite{T}(n)
1417

1518
support(b::Hermite{T}) where {T} = DomainSets.FullSpace(T)

0 commit comments

Comments
 (0)