Skip to content

Commit e9b80aa

Browse files
authored
Concrete operators in normalized spaces (#330)
* Concrete operators in normalized spaces * Concrete derivatives for Ultraspherical and Jacobi * Add tests
1 parent 2ad8335 commit e9b80aa

File tree

9 files changed

+115
-24
lines changed

9 files changed

+115
-24
lines changed

src/Spaces/Chebyshev/Chebyshev.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const NormalizedChebyshev{D<:Domain,R} = NormalizedPolynomialSpace{Chebyshev{D,
2626
NormalizedChebyshev() = NormalizedPolynomialSpace(Chebyshev())
2727
NormalizedChebyshev(d) = NormalizedPolynomialSpace(Chebyshev(d))
2828

29-
function Base.getproperty(S::Chebyshev{<:Any,<:Any},v::Symbol)
29+
function getproperty(S::Chebyshev, v::Symbol)
3030
if v==:b || v==:a
3131
-0.5
3232
else

src/Spaces/Chebyshev/ChebyshevOperators.jl

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -212,23 +212,24 @@ end
212212

213213
## Derivative
214214

215-
function Derivative(sp::Chebyshev{<:IntervalOrSegment}, order::Number)
215+
function Derivative(sp::MaybeNormalized{<:Chebyshev{<:IntervalOrSegment}}, order::Number)
216216
assert_integer(order)
217217
ConcreteDerivative(sp,order)
218218
end
219219

220220

221-
rangespace(D::ConcreteDerivative{<:Chebyshev{<:IntervalOrSegment}}) =
221+
rangespace(D::ConcreteDerivative{<:MaybeNormalized{<:Chebyshev{<:IntervalOrSegment}}}) =
222222
Ultraspherical(D.order,domain(D))
223223

224-
bandwidths(D::ConcreteDerivative{<:Chebyshev{<:IntervalOrSegment}}) = -D.order,D.order
225-
Base.stride(D::ConcreteDerivative{<:Chebyshev{<:IntervalOrSegment}}) = D.order
224+
bandwidths(D::ConcreteDerivative{<:MaybeNormalized{<:Chebyshev{<:IntervalOrSegment}}}) = -D.order,D.order
225+
Base.stride(D::ConcreteDerivative{<:MaybeNormalized{<:Chebyshev{<:IntervalOrSegment}}}) = D.order
226226

227-
isdiag(D::ConcreteDerivative{<:Chebyshev{<:IntervalOrSegment}}) = false
227+
isdiag(D::ConcreteDerivative{<:MaybeNormalized{<:Chebyshev{<:IntervalOrSegment}}}) = false
228228

229-
function getindex(D::ConcreteDerivative{<:Chebyshev{<:IntervalOrSegment},<:Any,T},k::Integer,j::Integer) where {T}
229+
function getindex(D::ConcreteDerivative{<:Chebyshev{<:IntervalOrSegment}}, k::Integer, j::Integer)
230230
m=D.order
231231
d=domain(D)
232+
T = eltype(D)
232233

233234
if j==k+m
234235
C=strictconvert(T,pochhammer(one(T),m-1)/2*(4/complexlength(d))^m)

src/Spaces/Jacobi/JacobiOperators.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
## Derivative
22

33
# specialize Derivative so that this is type-inferred even without constant propagation
4-
Derivative(J::Jacobi) = ConcreteDerivative(J,1)
4+
Derivative(J::MaybeNormalized{<:Jacobi}) = ConcreteDerivative(J,1)
55
@inline function _Derivative(J::Jacobi, k::Number)
66
assert_integer(k)
77
if k==1
@@ -20,9 +20,9 @@ else
2020
end
2121

2222

23-
rangespace(D::ConcreteDerivative{<:Jacobi}) = Jacobi(D.space.b+D.order,D.space.a+D.order,domain(D))
24-
bandwidths(D::ConcreteDerivative{<:Jacobi}) = -D.order,D.order
25-
isdiag(D::ConcreteDerivative{<:Jacobi}) = false
23+
rangespace(D::ConcreteDerivative{<:MaybeNormalized{<:Jacobi}}) = Jacobi(D.space.b+D.order,D.space.a+D.order,domain(D))
24+
bandwidths(D::ConcreteDerivative{<:MaybeNormalized{<:Jacobi}}) = -D.order,D.order
25+
isdiag(D::ConcreteDerivative{<:MaybeNormalized{<:Jacobi}}) = false
2626

2727
getindex(T::ConcreteDerivative{<:Jacobi}, k::Integer, j::Integer) =
2828
j==k+1 ? eltype(T)((k+1+T.space.a+T.space.b)/complexlength(domain(T))) : zero(eltype(T))

src/Spaces/PolynomialSpace.jl

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,11 @@ end
430430

431431
@containsconstants NormalizedPolynomialSpace
432432

433+
@inline function getproperty(N::NormalizedPolynomialSpace, v::Symbol)
434+
((v == :a) || (v == :b)) && return getproperty(getfield(N, :space), v)
435+
getfield(N, v)
436+
end
437+
433438
domain(S::NormalizedPolynomialSpace) = domain(S.space)
434439
canonicalspace(S::NormalizedPolynomialSpace) = S.space
435440
setdomain(NS::NormalizedPolynomialSpace, d::Domain) = NormalizedPolynomialSpace(setdomain(canonicalspace(NS), d))
@@ -505,8 +510,8 @@ end
505510

506511
# Conversion
507512

508-
bandwidths(C::ConcreteConversion{NormalizedPolynomialSpace{S,D,R},S}) where {S,D,R} = (0, 0)
509-
bandwidths(C::ConcreteConversion{S,NormalizedPolynomialSpace{S,D,R}}) where {S,D,R} = (0, 0)
513+
bandwidths(::ConcreteConversion{<:NormalizedPolynomialSpace{S},S}) where {S} = (0, 0)
514+
bandwidths(::ConcreteConversion{S,<:NormalizedPolynomialSpace{S}}) where {S} = (0, 0)
510515

511516
function getindex(C::ConcreteConversion{NormalizedPolynomialSpace{S,D,R},S,T},k::Integer,j::Integer) where {S,D<:IntervalOrSegment,R,T}
512517
if j==k
@@ -641,3 +646,12 @@ function evaluate(f::AbstractVector, S::NormalizedPolynomialSpace, x...)
641646
f_csp = mul_coefficients(C, f)
642647
evaluate(f_csp, csp, x...)
643648
end
649+
650+
# Methods for concrete operators in normalized spaces
651+
function getindex(D::ConcreteDerivative{<:NormalizedPolynomialSpace}, k::Integer, j::Integer)
652+
sp = domainspace(D)
653+
csp = canonicalspace(sp)
654+
Dcsp = ConcreteDerivative(csp, D.order)
655+
C = Conversion_normalizedspace(csp, Val(:backward))
656+
Dcsp[k, j] * C[j, j]
657+
end

src/Spaces/Ultraspherical/UltrasphericalOperators.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ end
5757
#Derivative(d::IntervalOrSegment)=Derivative(1,d)
5858

5959

60-
function Derivative(sp::Ultraspherical{LT,DD}, m::Number) where {LT,DD<:IntervalOrSegment}
60+
function Derivative(sp::MaybeNormalized{<:Ultraspherical{<:Any,<:IntervalOrSegment}}, m::Number)
6161
assert_integer(m)
6262
ConcreteDerivative(sp,m)
6363
end
@@ -75,15 +75,15 @@ function Integral(sp::Ultraspherical{<:Any,<:IntervalOrSegment}, m::Number)
7575
end
7676

7777

78-
rangespace(D::ConcreteDerivative{<:Ultraspherical{LT,DD}}) where {LT,DD<:IntervalOrSegment} =
78+
rangespace(D::ConcreteDerivative{<:MaybeNormalized{<:Ultraspherical{<:Any,<:IntervalOrSegment}}}) =
7979
Ultraspherical(order(domainspace(D))+D.order,domain(D))
8080

81-
bandwidths(D::ConcreteDerivative{<:Ultraspherical{LT,DD}}) where {LT,DD<:IntervalOrSegment} = -D.order,D.order
82-
bandwidths(D::ConcreteIntegral{<:Ultraspherical{LT,DD}}) where {LT,DD<:IntervalOrSegment} = D.order,-D.order
83-
Base.stride(D::ConcreteDerivative{<:Ultraspherical{LT,DD}}) where {LT,DD<:IntervalOrSegment} = D.order
81+
bandwidths(D::ConcreteDerivative{<:MaybeNormalized{<:Ultraspherical{<:Any,<:IntervalOrSegment}}}) = -D.order,D.order
82+
bandwidths(D::ConcreteIntegral{<:MaybeNormalized{<:Ultraspherical{<:Any,<:IntervalOrSegment}}}) = D.order,-D.order
83+
Base.stride(D::ConcreteDerivative{<:MaybeNormalized{<:Ultraspherical{<:Any,<:IntervalOrSegment}}}) = D.order
8484

85-
isdiag(D::ConcreteDerivative{<:Ultraspherical{<:Any,<:IntervalOrSegment}}) = false
86-
isdiag(D::ConcreteIntegral{<:Ultraspherical{<:Any,<:IntervalOrSegment}}) = false
85+
isdiag(D::ConcreteDerivative{<:MaybeNormalized{<:Ultraspherical{<:Any,<:IntervalOrSegment}}}) = false
86+
isdiag(D::ConcreteIntegral{<:MaybeNormalized{<:Ultraspherical{<:Any,<:IntervalOrSegment}}}) = false
8787

8888
function getindex(D::ConcreteDerivative{<:Ultraspherical{TT,DD},K,T},
8989
k::Integer,j::Integer) where {TT,DD<:IntervalOrSegment,K,T}

src/fastops.jl

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ end
7272

7373

7474

75-
function BandedMatrix(S::SubOperator{T,ConcreteDerivative{Chebyshev{DD,RR},K,T},
76-
NTuple{2,UnitRange{Int}}}) where {T,K,DD,RR}
75+
function BandedMatrix(S::SubOperator{T,<:ConcreteDerivative{<:Chebyshev,<:Any,T},
76+
NTuple{2,UnitRange{Int}}}) where {T}
7777

7878
n,m = size(S)
7979
ret = BandedMatrix{eltype(S)}(undef, (n,m), bandwidths(S))
@@ -98,8 +98,8 @@ function BandedMatrix(S::SubOperator{T,ConcreteDerivative{Chebyshev{DD,RR},K,T},
9898
end
9999

100100

101-
function BandedMatrix(S::SubOperator{T,ConcreteDerivative{Ultraspherical{LT,DD,RR},K,T},
102-
NTuple{2,UnitRange{Int}}}) where {T,K,DD,RR,LT}
101+
function BandedMatrix(S::SubOperator{T,<:ConcreteDerivative{<:Ultraspherical,T},
102+
NTuple{2,UnitRange{Int}}}) where {T}
103103
n,m = size(S)
104104
ret = BandedMatrix{eltype(S)}(undef, (n,m), bandwidths(S))
105105
kr,jr = parentindices(S)
@@ -116,3 +116,18 @@ function BandedMatrix(S::SubOperator{T,ConcreteDerivative{Ultraspherical{LT,DD,R
116116
ret
117117
end
118118

119+
function BandedMatrix(S::SubOperator{T,<:ConcreteDerivative{<:NormalizedPolynomialSpace,<:Any,T},
120+
NTuple{2,UnitRange{Int}}}) where {T}
121+
122+
D = parent(S)
123+
sp = domainspace(D)
124+
csp = canonicalspace(sp)
125+
ind1, ind2 = parentindices(S)
126+
B = BandedMatrix(view(ConcreteDerivative(csp, D.order), ind1, ind2))
127+
data = BandedMatrices.bandeddata(B)
128+
C = ConcreteConversion(sp, csp)
129+
for (ind, col) in enumerate(ind2)
130+
@views data[:, ind] .*= C[col, col]
131+
end
132+
B
133+
end

test/ChebyshevTest.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,12 @@ include("testutils.jl")
311311
else
312312
Derivative(s2)
313313
end
314+
@test D1 isa ApproxFunBase.ConcreteDerivative
315+
@test D2 isa ApproxFunBase.ConcreteDerivative
316+
@test !isdiag(D1)
317+
@test !isdiag(D2)
318+
@test D1[1,2] D2[1,2]
319+
@test D1[1:10, 1:10] D2[1:10, 1:10]
314320
f = x -> 3x^2 + 5x
315321
f1 = Fun(f, s1)
316322
f2 = Fun(f, s2)

test/JacobiTest.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,33 @@ include("testutils.jl")
404404
@test D * Fun(x->x^3, Legendre(0..1)) Fun(x->6x, Legendre(0..1))
405405
end
406406

407+
@testset "derivative in normalized space" begin
408+
s1 = NormalizedLegendre(-1..1)
409+
s2 = NormalizedLegendre()
410+
@test s1 == s2
411+
D1 = if VERSION >= v"1.8"
412+
@inferred Derivative(s1)
413+
else
414+
Derivative(s1)
415+
end
416+
D2 = if VERSION >= v"1.8"
417+
@inferred Derivative(s2)
418+
else
419+
Derivative(s2)
420+
end
421+
@test D1 isa ApproxFunBase.ConcreteDerivative
422+
@test D2 isa ApproxFunBase.ConcreteDerivative
423+
@test !isdiag(D1)
424+
@test !isdiag(D2)
425+
@test D1[1,2] D2[1,2]
426+
@test D1[1:10, 1:10] D2[1:10, 1:10]
427+
f = x -> 3x^2 + 5x
428+
f1 = Fun(f, s1)
429+
f2 = Fun(f, s2)
430+
@test f1 == f2
431+
@test D1 * f1 == D2 * f2
432+
end
433+
407434
@testset "identity Fun for interval domains" begin
408435
for d in [1..2, -1..1, 10..20], s in Any[Legendre(d), Jacobi(1, 2, d), Jacobi(1.2, 2.3, d)]
409436
f = Fun(identity, s)

test/UltrasphericalTest.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,34 @@ include("testutils.jl")
401401
@test M * f f2
402402
end
403403

404+
@testset "Derivative in a normalized space" begin
405+
s1 = NormalizedUltraspherical(1,-1..1)
406+
s2 = NormalizedUltraspherical(1)
407+
@test s1 == s2
408+
D1 = if VERSION >= v"1.8"
409+
@inferred Derivative(s1)
410+
else
411+
Derivative(s1)
412+
end
413+
D2 = if VERSION >= v"1.8"
414+
@inferred Derivative(s2)
415+
else
416+
Derivative(s2)
417+
end
418+
@test D1 isa ApproxFunBase.ConcreteDerivative
419+
@test D2 isa ApproxFunBase.ConcreteDerivative
420+
@test !isdiag(D1)
421+
@test !isdiag(D2)
422+
@test D1[1,2] D2[1,2]
423+
@test D1[1:10, 1:10] D2[1:10, 1:10]
424+
f = x -> 3x^2 + 5x
425+
f1 = Fun(f, s1)
426+
f2 = Fun(f, s2)
427+
@test f1 == f2
428+
df = x -> 6x + 5
429+
@test D1 * f1 == D2 * f2 Fun(df, s2)
430+
end
431+
404432
@testset "Integral" begin
405433
d = 0..1
406434
A = @inferred Integral(0..1)

0 commit comments

Comments
 (0)