Skip to content

Commit 5867548

Browse files
tomtrogdondlfivefifty
authored andcommitted
Added mapping of points to deal with general Rays (#12)
* Added mapping of points to deal with general Rays * Added unit test for general rays * Working on scaled rays. * Incorporated SRay into Ray
1 parent 2320872 commit 5867548

File tree

5 files changed

+119
-66
lines changed

5 files changed

+119
-66
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ deps/deps.jl
55
test/.DS_Store
66
.DS_Store
77
Manifest.toml
8+
dev_code.jl

src/Domains/Domains.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ isless(d2::Ray{true,T2},d1::IntervalOrSegment{T1}) where {T1<:Real,T2<:Real} = d
1313
Base.setdiff(d::Union{AbstractInterval,Segment,Ray,Line}, ptsin::UnionDomain{AS}) where {AS <: AbstractVector{P}} where {P <: Point} =
1414
affine_setdiff(d, ptsin)
1515

16-
Base.setdiff(d::Union{AbstractInterval,Segment,Ray,Line}, ptsin::WrappedDomain{<:AbstractVector}) =
16+
Base.setdiff(d::Union{AbstractInterval,Segment,Ray,Line}, ptsin::WrappedDomain{<:AbstractVector}) =
1717
affine_setdiff(d, ptsin)
1818

19-
Base.setdiff(d::Union{AbstractInterval,Segment,Ray,Line}, ptsin::AbstractVector{<:Number}) =
19+
Base.setdiff(d::Union{AbstractInterval,Segment,Ray,Line}, ptsin::AbstractVector{<:Number}) =
2020
ApproxFunBase._affine_setdiff(d, ptsin)
2121

22-
Base.setdiff(d::Union{AbstractInterval,Segment,Ray,Line}, ptsin::Number) =
23-
ApproxFunBase._affine_setdiff(d, ptsin)
22+
Base.setdiff(d::Union{AbstractInterval,Segment,Ray,Line}, ptsin::Number) =
23+
ApproxFunBase._affine_setdiff(d, ptsin)

src/Domains/Ray.jl

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,33 @@
1-
2-
31
export Ray
42

5-
6-
7-
## Standard interval
8-
9-
# angle is (false==0) and π (true==1)
10-
# or ranges from (-1,1]. We use 1 as 1==true.
11-
#orientation true means oriented out
123
"""
13-
Ray{a}(c,o)
4+
Ray{a}(c,L,o)
145
15-
represents a ray at angle `a` starting at `c`, with orientation out to
6+
represents a scaled ray (with scale factor L) at angle `a` starting at `c`, with orientation out to
167
infinity (`o = true`) or back from infinity (`o = false`).
178
"""
189
struct Ray{angle,T<:Number} <: SegmentDomain{T}
1910
center::T
11+
L::T
2012
orientation::Bool
21-
Ray{angle,T}(c,o) where {angle,T} = new{angle,T}(c,o)
22-
Ray{angle,T}(c) where {angle,T} = new{angle,T}(c,true)
23-
Ray{angle,T}() where {angle,T} = new{angle,T}(zero(T),true)
13+
Ray{angle,T}(c,L,o) where {angle,T} = new{angle,T}(c,L,o)
14+
Ray{angle,T}(c,o) where {angle,T} = new{angle,T}(c,one(T),o)
15+
Ray{angle,T}(c) where {angle,T} = new{angle,T}(c,one(T),true)
16+
Ray{angle,T}() where {angle,T} = new{angle,T}(zero(T),one(T),true)
2417
Ray{angle,T}(r::Ray{angle,T}) where {angle,T} = r
2518
end
2619

27-
const RealRay{T} = Union{Ray{false,T},Ray{true,T}}
28-
29-
Ray{a}(c,o) where {a} = Ray{a,typeof(c)}(c,o)
20+
Ray{a}(c,L,o) where {a} = Ray{a,typeof(c)}(c,L,o)
21+
Ray{a}(c,o) where {a} = Ray{a,typeof(c)}(c,one(typeof(c)),o)
3022
Ray{a}(c::Number) where {a} = Ray{a,typeof(c)}(c)
3123
Ray{a}() where {a} = Ray{a,Float64}()
3224

3325
angle(d::Ray{a}) where {a} = a*π
3426

3527
# ensure the angle is always in (-1,1]
36-
Ray(c,a,o) = Ray{a==0 ? false : (abs(a)≈(1.0π) ? true : mod(a/π-1,-2)+1),typeof(c)}(c,o)
37-
Ray(c,a) = Ray(c,a,true)
28+
Ray(c,a,L,o) = Ray{a==0 ? false : (abs(a)≈(1.0π) ? true : mod(a/π-1,-2)+1),typeof(c)}(c,L,o)
29+
Ray(c,a,o) = Ray{a==0 ? false : (abs(a)≈(1.0π) ? true : mod(a/π-1,-2)+1),typeof(c)}(c,one(typeof(c)),o)
30+
Ray(c,a) = Ray(c,a,one(typeof(c)),true)
3831

3932
Ray() = Ray{false}()
4033

@@ -47,9 +40,9 @@ function convert(::Type{Ray}, d::AbstractInterval)
4740
@assert abs(a)==Inf || abs(b)==Inf
4841

4942
if abs(b)==Inf
50-
Ray(a,angle(b),true)
43+
Ray(a,angle(b),one(typeof(a)),true)
5144
else #abs(a)==Inf
52-
Ray(b,angle(a),false)
45+
Ray(b,angle(a),one(typeof(a)),false)
5346
end
5447
end
5548
Ray(d::AbstractInterval) = convert(Ray, d)
@@ -66,7 +59,7 @@ isempty(::Ray) = false
6659

6760
function mobiuspars(d::Ray)
6861
s=(d.orientation ? 1 : -1)
69-
α=conj(cisangle(d))
62+
α=conj(cisangle(d))/d.L
7063
c=d.center
7164
s*α,-s*(1+α*c),α,1-α*c
7265
end
@@ -84,40 +77,37 @@ ray_invfromcanonicalD(x) = (x-1)^2/2
8477

8578

8679
for op in (:ray_tocanonical,:ray_tocanonicalD)
87-
@eval $op(o,x)=(o ? 1 : -1)*$op(x)
80+
@eval $op(L,o,x)= (o ? 1 : -1)*$op(x/L)
8881
end
89-
ray_fromcanonical(o,x)=ray_fromcanonical((o ? 1 : -1)*x)
90-
ray_fromcanonicalD(o,x)=(o ? 1 : -1)*ray_fromcanonicalD((o ? 1 : -1)*x)
91-
ray_invfromcanonicalD(o,x)=(o ? 1 : -1)*ray_invfromcanonicalD((o ? 1 : -1)*x)
82+
83+
ray_fromcanonical(L,o,x)=L*ray_fromcanonical((o ? 1 : -1)*x)
84+
ray_fromcanonicalD(L,o,x)=L*(o ? 1 : -1)*ray_fromcanonicalD((o ? 1 : -1)*x)
85+
ray_invfromcanonicalD(L,o,x)=L*(o ? 1 : -1)*ray_invfromcanonicalD((o ? 1 : -1)*x)
9286

9387
cisangle(::Ray{a}) where {a}=cis(a*π)
9488
cisangle(::Ray{false})=1
9589
cisangle(::Ray{true})=-1
9690

9791
tocanonical(d::Ray,x) =
98-
ray_tocanonical(d.orientation,conj(cisangle(d)).*(x-d.center))
92+
ray_tocanonical(d.L,d.orientation,conj(cisangle(d)).*(x-d.center))
9993
tocanonicalD(d::Ray,x) =
100-
conj(cisangle(d)).*ray_tocanonicalD(d.orientation,conj(cisangle(d)).*(x-d.center))
101-
fromcanonical(d::Ray,x) = cisangle(d)*ray_fromcanonical(d.orientation,x)+d.center
102-
fromcanonical(d::Ray{false},x) = ray_fromcanonical(d.orientation,x)+d.center
103-
fromcanonical(d::Ray{true},x) = -ray_fromcanonical(d.orientation,x)+d.center
104-
fromcanonicalD(d::Ray,x) = cisangle(d)*ray_fromcanonicalD(d.orientation,x)
105-
invfromcanonicalD(d::Ray,x) = conj(cisangle(d))*ray_invfromcanonicalD(d.orientation,x)
106-
107-
108-
109-
94+
conj(cisangle(d)).*ray_tocanonicalD(d.L,d.orientation,conj(cisangle(d)).*(x-d.center))
95+
fromcanonical(d::Ray,x) = cisangle(d)*ray_fromcanonical(d.L,d.orientation,x)+d.center
96+
fromcanonical(d::Ray{false},x) = ray_fromcanonical(d.L,d.orientation,x)+d.center
97+
fromcanonical(d::Ray{true},x) = -ray_fromcanonical(d.L,d.orientation,x)+d.center
98+
fromcanonicalD(d::Ray,x) = cisangle(d)*ray_fromcanonicalD(d.L,d.orientation,x)
99+
invfromcanonicalD(d::Ray,x) = conj(cisangle(d))*ray_invfromcanonicalD(d.L,d.orientation,x)
110100
arclength(d::Ray) = Inf
111101

112-
==(d::Ray{a},m::Ray{a}) where {a} = d.center == m.center
102+
==(d::Ray{a},m::Ray{a}) where {a} = d.center == m.center && d.L == m.L
113103

114104

115105
mappoint(a::Ray{false}, b::Ray{false}, x::Number) =
116-
x - a.center + b.center
106+
b.center + b.L/a.L*(x - a.center)
117107

118108

119109
function mappoint(a::Ray, b::Ray, x::Number)
120110
d = x - a.center;
121-
k = d * exp((angle(b)-angle(d))*im)
111+
k = b.L/a.L * d * exp((angle(b)-angle(d))*im)
122112
k + b.center
123113
end

src/Spaces/Laguerre/Laguerre.jl

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export Laguerre, NormalizedLaguerre, LaguerreWeight, WeightedLaguerre
1414
# p_{n+1} = (A_n x + B_n)p_n - C_n p_{n-1}
1515
#####
1616

17+
1718
"""
1819
`Laguerre(α)` is a space spanned by generalized Laguerre polynomials `Lₙᵅ(x)` 's
1920
on `(0, Inf)`, which satisfy the differential equations
@@ -33,7 +34,7 @@ Laguerre() = Laguerre(0)
3334
NormalizedLaguerre(α) = NormalizedPolynomialSpace(Laguerre(α))
3435
NormalizedLaguerre() = NormalizedLaguerre(0)
3536

36-
spacescompatible(A::Laguerre,B::Laguerre) = A.α B.α
37+
spacescompatible(A::Laguerre,B::Laguerre) = A.α B.α && B.domain == A.domain
3738

3839
canonicaldomain(::Laguerre) = Ray()
3940
domain(d::Laguerre) = d.domain
@@ -101,31 +102,62 @@ laguerrel(n::AbstractRange,S::Laguerre,v) = laguerrel(n,S.a,S.b,v)
101102
laguerrel(n,S::Laguerre,v) = laguerrel(n,S.a,S.b,v)
102103

103104

105+
#struct LaguerreTransformPlan{T,TT}
106+
# space::Laguerre{TT}
107+
# points::Vector{T}
108+
# weights::Vector{T}
109+
#end
110+
104111
struct LaguerreTransformPlan{T,TT}
105112
space::Laguerre{TT}
106113
points::Vector{T}
107-
weights::Vector{T}
114+
transform::Array{T}
115+
c1::Vector{T}
116+
c2::Vector{T}
108117
end
109118

110-
plan_transform(S::Laguerre,v::AbstractVector) = LaguerreTransformPlan(S,gausslaguerre(length(v),1.0S.α)...)
111-
function *(plan::LaguerreTransformPlan,vals)
112-
# @assert S==plan.space
113-
x,w = plan.points, plan.weights
114-
V=laguerrel(0:length(vals)-1,plan.space.α,x)'
115-
#w2=w.*x.^(S.α-plan.space.α) # need to weight if plan is different
116-
w2=w
117-
nrm=(V.^2)*w2
118-
V*(w2.*vals)./nrm
119+
function Lag_conv(n::Int64::Float64)
120+
out = ones(Float64,n)
121+
out[1] = 1/gamma+1)
122+
for i in 2:n
123+
out[i] = out[i-1]*(i-1.0)/(i-1.0+α)
124+
end
125+
return sqrt.(out)
126+
end
127+
128+
function lag_transform(n::Int64::Float64)
129+
egn = eigen(SymTridiagonal([(2i + α + 1.) for i = 0:n-1],[-sqrt(i*(i+α)) for i = 1:n-1]))
130+
U = egn.vectors
131+
ns = sqrt(gamma+1))*U[1,:]
132+
egn.values, U, Lag_conv(n,α), ns
119133
end
120134

135+
# The old transform plan. Is this faster for n < 150?
136+
#plan_transform(S::Laguerre,v::AbstractVector) = LaguerreTransformPlan(S,gausslaguerre(length(v),1.0S.α)...)
137+
#function *(plan::LaguerreTransformPlan,vals)
138+
# @assert S==plan.space
139+
# x,w = plan.points, plan.weights
140+
# V=laguerrel(0:length(vals)-1,plan.space.α,x)'
141+
# #w2=w.*x.^(S.α-plan.space.α) # need to weight if plan is different
142+
# w2=w
143+
# nrm=(V.^2)*w2
144+
# V*(w2.*vals)./nrm
145+
#end
146+
147+
plan_transform(S::Laguerre,v::AbstractVector) = LaguerreTransformPlan(S,lag_transform(length(v),1.0S.α)...)
148+
function *(plan::LaguerreTransformPlan,vals)
149+
x,w,c1,c2 = plan.points, plan.transform, plan.c1, plan.c2
150+
c1.*(w*(c2.*vals))
151+
end
121152

122-
points(L::Laguerre,n) = gausslaguerre(n,1.0L.α)[1]
123153

154+
points(L::Laguerre,n) = map(x -> mappoint(Ray(),L.domain,x), gausslaguerre(n,1.0L.α)[1])
124155

125156

157+
# TODO: Separate off a real case for the real axis.
126158
Derivative(L::Laguerre,k) =
127-
DerivativeWrapper(SpaceOperator(ToeplitzOperator(Float64[],[zeros(k);(-1.)^k]),
128-
L,Laguerre(L.α+k)))
159+
DerivativeWrapper(SpaceOperator(ToeplitzOperator(Complex{Float64}[],[zeros(k);(-1.)^k]*conj(cisangle(L.domain))/L.domain.L),
160+
L,Laguerre(L.α+k,L.domain)))
129161

130162

131163
union_rule(A::Laguerre,B::Laguerre) = Laguerre(min(A.α,B.α))
@@ -164,15 +196,12 @@ struct LaguerreWeight{S,T} <: WeightSpace{S,Ray{false,Float64},Float64}
164196
L::T
165197
space::S
166198
end
167-
168-
169199
"""
170200
LaguerreWeight(α, space)
171201
172202
weights `space` by `x^α * exp(-x)`.
173203
"""
174204
LaguerreWeight(α, space::Space) = LaguerreWeight(α, one(α),space)
175-
176205
"""
177206
WeightedLaguerre(α)
178207
@@ -214,8 +243,9 @@ last(f::Fun{<:LaguerreWeight,T}) where T = zero(T)
214243
function Derivative(sp::LaguerreWeight,k)
215244
@assert sp.α == 0
216245
if k==1
246+
c = conj(cisangle(sp.space.domain))/sp.space.domain.L
217247
D=Derivative(sp.space)
218-
D2=D-sp.L*I
248+
D2=c*D-(c*sp.L)*I
219249
DerivativeWrapper(SpaceOperator(D2,sp,LaguerreWeight(sp.α,sp.L,rangespace(D2))),1)
220250
else
221251
D=Derivative(sp)
@@ -300,6 +330,3 @@ function Multiplication(f::Fun{LaguerreWeight{H,T}},S::Laguerre) where {H<:Lague
300330
rs=rangespace(M)
301331
MultiplicationWrapper(f,SpaceOperator(M,S,LaguerreWeight(space(f).α, space(f).L, rs)))
302332
end
303-
304-
305-

test/LaguerreTest.jl

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,42 @@
11
using ApproxFunOrthogonalPolynomials, ApproxFunBase, SpecialFunctions, Test
22
import ApproxFunBase: testbandedoperator
33

4-
@testset "Laguerre and WeightedLagueree" begin
4+
5+
@testset "Laguerre and WeightedLaguerre" begin
6+
7+
@testset "General scaled rays" begin
8+
r = Ray(-1.0,0.0,2.0,true)
9+
L = Laguerre(1.0,r)
10+
f = x -> exp.(-x)
11+
F = Fun(f, L)
12+
@test F(.3) -F'(.3)
13+
14+
r = Ray(1.0,0.0,2.0,false)
15+
L = Laguerre(1.0,r)
16+
f = x -> exp.(-x)
17+
F = Fun(f, L, 100)
18+
@test F(1.3) -F'(1.3)
19+
20+
r = Ray(1.0,π,2.0,true)
21+
L = Laguerre(1.0,r)
22+
f = x -> exp.(x)
23+
F = Fun(f, L, 100)
24+
@test F(.3) F'(.3)
25+
26+
r = Ray(-3.0,0.0,2.0,true)
27+
L = Laguerre(1.0,r)
28+
f = x -> exp.(-x)
29+
F = Fun(f, L) # overflow/underflow issues beyond 190ish
30+
@test abs(F(0.0) - f(0.)) < 1e-5
31+
@test abs(F(-2.0) - f(-2.)) < 1e-5
32+
33+
r = Ray(3.0,π,.1,false)
34+
L = Laguerre(1.0,r)
35+
f = x -> exp.(-x^2)
36+
F = Fun(f, L) # overflow/underflow issues beyond 190ish
37+
@test abs(F(-1.0) - f(-1.0)) < 1e-5
38+
end
39+
540
@testset "Evaluation" begin
641
f=Fun(Laguerre(0.), [1,2,3])
742
@test f(0.1) 5.215

0 commit comments

Comments
 (0)