Skip to content

Commit 4fe2744

Browse files
committed
add differentiation matrices for ops
1 parent c8b1ac7 commit 4fe2744

File tree

5 files changed

+138
-19
lines changed

5 files changed

+138
-19
lines changed

src/bases/poly/chebyshev/ChebyshevT.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ mapped_dict(dict::ChebyshevT{T}, map::ScalarAffineMap{S}) where {S,T} =
3535
MappedChebyshev{promote_type(S,T)}(dict, map)
3636

3737
hasinterpolationgrid(b::ChebyshevT) = true
38-
hasderivative(b::ChebyshevT) = true
3938
hasderivative(b::ChebyshevT, order::Int) = true
4039
hasantiderivative(b::ChebyshevT) = true
4140

src/bases/poly/monomials.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ function differentiation(::Type{T}, src::Monomials, dest::Monomials, order::Int;
6060
@assert src == dest
6161
IdentityOperator{T}(src)
6262
else
63-
A = zeros(T, m, n)
63+
A = BandedMatrix{T}(undef, (m,n), (0,1))
64+
fill!(A, 0)
6465
for i in 1:n-order
6566
A[i,i+1] = i
6667
end

src/bases/poly/ops/connections.jl

Lines changed: 126 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ isequaldict2(b1::Jacobi, b2::Ultraspherical) = isequaldict1(b2, b1)
1212

1313
const RECURRENCEBASIS = Union{Monomials,OrthogonalPolynomials}
1414

15+
###########################
16+
# Polynomial conversions
17+
###########################
18+
1519
function conversion1(::Type{T}, src::RECURRENCEBASIS, dest::RECURRENCEBASIS; options...) where T
1620
if length(dest) < length(src)
1721
throw(ArgumentError("Cannot convert to a smaller basis."))
@@ -31,11 +35,11 @@ function conversion1(::Type{T}, src::RECURRENCEBASIS, dest::RECURRENCEBASIS; opt
3135
end
3236

3337
conversion_using_recurrences(::Type{T}, src::RECURRENCEBASIS, dest::RECURRENCEBASIS; options...) where T =
34-
generic_conversion_using_recurrences(T, src, dest; options...)
38+
generic_conversion_using_recurrences(T, src, dest)
3539

3640
# For two bases satisfying a recurrence relation we use that relation to compute the connection
3741
# coefficients to transform between them.
38-
function generic_conversion_using_recurrences(::Type{T}, src::RECURRENCEBASIS, dest::RECURRENCEBASIS; options...) where T
42+
function generic_conversion_using_recurrences(::Type{T}, src::RECURRENCEBASIS, dest::RECURRENCEBASIS) where T
3943
@assert length(dest) == length(src)
4044
n = length(dest)
4145
A = zeros(T, n, n)
@@ -208,3 +212,123 @@ function conversion_using_recurrences(::Type{T}, src::Jacobi, dest::ChebyshevU;
208212
generic_conversion_using_recurrences(T, src, dest; options...)
209213
end
210214
end
215+
216+
###########################
217+
# Differentiation matrices
218+
###########################
219+
220+
differentiation(::Type{T}, src::B, dest::B, order::Int; options...) where {T,B<:OrthogonalPolynomials} =
221+
differentiation_for_ops(T, src, dest, order; options...)
222+
223+
function differentiation_for_ops(::Type{T}, src::B, dest::B, order::Int; options...) where {T,B<:OrthogonalPolynomials}
224+
@assert order == 1
225+
if length(src) == length(dest)
226+
A = differentiation_using_recurrences(T, src; options...)
227+
ArrayOperator(A, src, dest)
228+
elseif length(src) == length(dest)+1
229+
A = differentiation_using_recurrences(T, src; options...)
230+
restriction(T, src, dest) ArrayOperator(A, src, src)
231+
else
232+
throw(ArgumentError("Incompatible sizes of src and dest dictionaries for differentiation."))
233+
end
234+
end
235+
236+
237+
differentiation_using_recurrences(::Type{T}, src::RECURRENCEBASIS; options...) where T =
238+
generic_differentiation_using_recurrences(T, src)
239+
240+
function generic_differentiation_using_recurrences(::Type{T}, src::RECURRENCEBASIS) where T
241+
n = length(src)
242+
M = zeros(T, n, n)
243+
if n >= 2
244+
A0 = rec_An(src, 0)
245+
M[1,2] = A0
246+
end
247+
if n >= 3
248+
B0 = rec_Bn(src, 0)
249+
A1 = rec_An(src, 1)
250+
B1 = rec_Bn(src, 1)
251+
M[1,3] = B1*A0 - A1*B0
252+
M[2,3] = 2A1
253+
end
254+
for k in 2:n-2
255+
C1 = rec_Cn(src, 1)
256+
Ak = rec_An(src, k)
257+
Bk = rec_Bn(src, k)
258+
Ck = rec_Cn(src, k)
259+
Akm1 = rec_An(src, k-1)
260+
Bkm1 = rec_Bn(src, k-1)
261+
Akm2 = rec_An(src, k-2)
262+
M[1,k+2] = Bk * M[1,k+1] - Ck*M[1,k] - M[1,k+1]*Ak*B0/A0 + M[2,k+1]*Ak*C1/A1
263+
for j in 1:k-2
264+
Aj = rec_An(src, j)
265+
Bj = rec_Bn(src, j)
266+
Cj = rec_Bn(src, j)
267+
Ajm1 = rec_An(src, j-1)
268+
Ajp1 = rec_An(src, j+1)
269+
Cjp1 = rec_Cn(src, j+1)
270+
M[j+1,k+2] = Bk * M[j+1,k+1] - Ck*M[j+1,k] + M[j,k+1]*Ak/Ajm1 - M[j+1,k+1]*Ak*Bj/Aj + M[j+2,k+1]*Ak*Cjp1/Ajp1
271+
end
272+
M[k,k+2] = Bk*M[k,k+1] + M[k-1,k+1]*Ak/Akm2 - M[k,k+1]*Ak*Bkm1/Akm1
273+
M[k+1,k+2] = Ak+M[k,k+1]*Ak/Akm1
274+
end
275+
UpperTriangular(M)
276+
end
277+
278+
# Some special cases
279+
280+
function chebyshevt_to_chebyshevu_differentiation(::Type{T}, n, m) where T
281+
@assert n-1 <= m <= n
282+
A = BandedMatrix{T}(undef, (m,n), (0,1))
283+
for k in 1:n-1
284+
A[k,k] = 0
285+
A[k,k+1] = k
286+
end
287+
if m == n
288+
A[n,n] = 0
289+
end
290+
A
291+
end
292+
293+
function differentiation(::Type{T}, src::ChebyshevT, dest::ChebyshevU, order::Int; options...) where T
294+
@assert order == 1
295+
n = length(src)
296+
m = length(dest)
297+
if n-1 <= m <= n
298+
A = chebyshevt_to_chebyshevu_differentiation(T, n, m)
299+
ArrayOperator(A, src, dest)
300+
else
301+
throw(ArgumentError("Incompatible length of dictionaries for differentiation."))
302+
end
303+
end
304+
305+
function ultraspherical_differentiation::T, n, m) where T
306+
@assert n-1 <= m <= n
307+
A = BandedMatrix{T}(undef, (m,n), (0,1))
308+
for k in 1:n-1
309+
A[k,k] = 0
310+
A[k,k+1] = 2λ
311+
end
312+
if m == n
313+
A[n,n] = 0
314+
end
315+
A
316+
end
317+
318+
function differentiation(::Type{T}, src::Ultraspherical, dest::Ultraspherical, order::Int; options...) where T
319+
@assert order == 1
320+
if ultraspherical_λ(dest) == ultraspherical_λ(src) + 1
321+
n = length(src)
322+
m = length(dest)
323+
if n-1 <= m <= n
324+
A = ultraspherical_differentiation(ultraspherical_λ(src), n, m)
325+
ArrayOperator(A, src, dest)
326+
else
327+
throw(ArgumentError("Incompatible length of dictionaries for differentiation."))
328+
end
329+
elseif ultraspherical_λ(dest) == ultraspherical_λ(src)
330+
differentiation_for_ops(T, src, dest, order; options...)
331+
else
332+
throw(ArgumentError("Incompatible dictionaries for differentiation."))
333+
end
334+
end

src/bases/poly/ops/legendre.jl

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,23 +50,16 @@ same_ops_family(b1::Legendre, b2::Legendre) = true
5050
show(io::IO, b::Legendre{Float64}) = print(io, "Legendre($(length(b)))")
5151
show(io::IO, b::Legendre{T}) where T = print(io, "Legendre{$(T)}($(length(b)))")
5252

53-
hasderivative(b::Legendre) = true
54-
function differentiation(::Type{T}, src::Legendre, dest::Legendre, order::Int; options...) where {T}
55-
@assert order >= 0
56-
if order == 0
57-
IdentityOperator{T}(src, dest)
58-
elseif order == 1
59-
A = zeros(T, length(dest), length(src))
60-
n = length(src)
61-
for i in 0:n-1
62-
for j in i-1:-2:0
63-
A[j+1,i+1] = 2*(i-1-2*((i-j)>>1))+1
64-
end
53+
# hasderivative(b::Legendre) = true
54+
function differentiation_using_recurrences(::Type{T}, src::Legendre; options...) where {T}
55+
n = length(src)
56+
A = zeros(T, n, n)
57+
for i in 0:n-1
58+
for j in i-1:-2:0
59+
A[j+1,i+1] = 2*(i-1-2*((i-j)>>1))+1
6560
end
66-
ArrayOperator{T}(A, src, dest)
67-
else
68-
error("Higher order differentiation of Legendre not implemented.")
6961
end
62+
UpperTriangular(A)
7063
end
7164

7265

src/bases/poly/ops/orthopoly.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ abstract type OrthogonalPolynomial{T} <: Polynomial{T} end
1818

1919
approx_length(b::OPS, n::Int) = n
2020

21+
hasderivative(dict::OPS) = true
22+
2123
# Taking the derivative of a polynomial lowers its degree. This results in a
2224
# rectangular differentiation matrix. With the reducedegree option set to false,
2325
# the degree is maintained (resulting in a square differentiation matrix).

0 commit comments

Comments
 (0)