Skip to content

Commit c86935a

Browse files
authored
Move fractional calculus from ApproxFun.jl (#61)
* move functions from ApproxFun * fix imported functions * allow SpecialFunctions v1
1 parent 39b1cbd commit c86935a

File tree

5 files changed

+396
-4
lines changed

5 files changed

+396
-4
lines changed

Project.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ApproxFunSingularities"
22
uuid = "f8fcb915-6b99-5be2-b79a-d6dbef8e6e7e"
3-
version = "0.3.9"
3+
version = "0.3.10"
44

55
[deps]
66
ApproxFunBase = "fbd15aa5-315a-5a7d-a8a4-24992e37be05"
@@ -9,6 +9,7 @@ DomainSets = "5b8099bc-c8ec-5219-889f-1d9e522a28bf"
99
IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953"
1010
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1111
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
12+
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
1213
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
1314
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
1415

@@ -20,7 +21,7 @@ Aqua = "0.5"
2021
DomainSets = "0.4, 0.5, 0.6"
2122
IntervalSets = "0.5, 0.6, 0.7"
2223
Reexport = "0.2, 1"
23-
SpecialFunctions = "2"
24+
SpecialFunctions = "1, 2"
2425
StaticArrays = "1"
2526
julia = "1.6"
2627

src/ApproxFunSingularities.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module ApproxFunSingularities
2-
using Base, LinearAlgebra, Reexport, IntervalSets, DomainSets, Statistics
2+
using Base, LinearAlgebra, Reexport, IntervalSets, DomainSets, Statistics, SpecialFunctions
33

44
@reexport using ApproxFunBase
55
@reexport using ApproxFunOrthogonalPolynomials
@@ -25,7 +25,9 @@ import ApproxFunBase: Fun, SumSpace, SubSpace, WeightSpace, NoSpace,
2525
coefficients, isconvertible, SpaceOperator, cfstype, mobius, roots,
2626
splitatroots, domaintype, rangetype, weight, isapproxinteger,
2727
dotu, components, promoterangespace, ∞, gamma,
28-
assert_integer, SpecialEvalPtType, isleftendpoint, isrightendpoint, evaluation_point
28+
assert_integer, SpecialEvalPtType, isleftendpoint, isrightendpoint, evaluation_point,
29+
@calculus_operator, ConcreteConversion, InterlaceOperator_Diagonal, UnsetSpace,
30+
choosedomainspace
2931

3032
import ApproxFunOrthogonalPolynomials: order
3133

@@ -52,6 +54,7 @@ include("JacobiWeightOperators.jl")
5254
include("JacobiWeightChebyshev.jl")
5355
include("LogWeight.jl")
5456
include("ExpWeight.jl")
57+
include("fractionalcalculus.jl")
5558

5659
/(c::Number,f::Fun{<:Ultraspherical}) = c/Fun(f,Chebyshev(domain(f)))
5760
/(c::Number,f::Fun{<:PolynomialSpace{<:IntervalOrSegment}}) = c/Fun(f,Chebyshev(domain(f)))

src/fractionalcalculus.jl

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
####
2+
# Support for Fractional derivatives
3+
#
4+
# defined as
5+
####
6+
7+
8+
9+
# export LeftIntegral,LeftDerivative, RightDerivative, RightIntegral
10+
11+
@calculus_operator LeftIntegral
12+
@calculus_operator LeftDerivative
13+
14+
@calculus_operator RightIntegral
15+
@calculus_operator RightDerivative
16+
17+
# DLMF18.17.9 with μ=0.5 and α=β=0
18+
19+
function LeftIntegral(S::Jacobi,k)
20+
if S.b==0
21+
ConcreteLeftIntegral(S,k)
22+
else
23+
J=Jacobi(zero(S.a),S.a,domain(S))
24+
CLI = ConcreteLeftIntegral(J,k)
25+
LeftIntegralWrapper(CLI*Conversion(S,J),k,S,rangespace(CLI))
26+
end
27+
end
28+
29+
function LeftIntegral(S::Ultraspherical,k)
30+
J = Jacobi(S)
31+
LI = LeftIntegral(J,k)
32+
LeftIntegralWrapper(LI*ConcreteConversion(S,J),0.5,S,rangespace(LI))
33+
end
34+
35+
function LeftIntegral(S::Chebyshev,k)
36+
SU = Ultraspherical(Legendre(domain(S)))
37+
LI = LeftIntegral(SU,k)
38+
LeftIntegralWrapper(LI*ConcreteConversion(S,SU),0.5,S,rangespace(LI))
39+
end
40+
41+
42+
function rangespace(Q::ConcreteLeftIntegral{<:Jacobi{<:IntervalOrSegment}})
43+
μ=Q.order
44+
S=domainspace(Q)
45+
46+
JacobiWeight(S.b+μ,zero(S.b),Jacobi(S.b+μ,S.a-μ,domain(S)))
47+
end
48+
49+
function RightIntegral(S::Jacobi,k)
50+
if S.a==0
51+
ConcreteRightIntegral(S,k)
52+
else
53+
J=Jacobi(S.b,zero(S.b),domain(S))
54+
CRI = ConcreteRightIntegral(J,k)
55+
RightIntegralWrapper(CRI*Conversion(S,J),k,S,rangespace(CRI))
56+
end
57+
end
58+
59+
function rangespace(Q::ConcreteRightIntegral{<:Jacobi{<:IntervalOrSegment}})
60+
μ=Q.order
61+
S=domainspace(Q)
62+
@assert S.a==0
63+
64+
JacobiWeight(zero(S.a),S.a+μ,Jacobi(S.b-μ,S.a+μ,domain(S)))
65+
end
66+
67+
for TYP in (:ConcreteLeftIntegral,:ConcreteRightIntegral)
68+
@eval begin
69+
bandwidths(Q::$TYP{<:Jacobi{<:IntervalOrSegment}}) = (0,0)
70+
getindex(Q::$TYP{<:Jacobi{<:IntervalOrSegment},<:Any,T},k::Integer,j::Integer) where {T} =
71+
convert(T, jacobi_frac_getindex(domain(Q),zero(T),Q.order,k,j))::T
72+
end
73+
end
74+
75+
76+
jacobi_frac_getindex(d::IntervalOrSegment,α,μ,k::Integer,j::Integer) =
77+
jacobi_frac_getindex((arclength(d)/2)^μ,α,μ,k,j)
78+
79+
jacobi_frac_getindex(c::Number,α,μ,k::Integer,j::Integer) =
80+
k==j ? c*exp(loggamma+k)-loggamma+μ+k)) : zero(promote_type(typeof(c),typeof(α),typeof(μ)))
81+
82+
83+
# jacobi_frac_addentries!(d::IntervalOrSegment,α,μ,A,kr::UnitRange)=
84+
# jacobi_frac_addentries!((arclength(d)/2)^μ,α,μ,A,kr)
85+
# function jacobi_frac_addentries!(c::Number,α,μ,A,kr::UnitRange)
86+
# γ=c*gamma(α+1)/gamma(α+1+μ)
87+
# for k=1:first(kr)-1
88+
# γ*=(α+k)/(α+μ+k)
89+
# end
90+
# for k=kr
91+
# A[k,k]+=γ
92+
# γ*=(α+k)/(α+μ+k)
93+
# #should be gamma(S.α+k)/gamma(S.α+μ+k)=
94+
# #(S.α+k-1)/(S.α+μ+k-1)*gamma(S.α+k-1)/gamma(S.α+μ+k-1)
95+
# end
96+
# A
97+
# end
98+
99+
100+
function LeftIntegral(S::JacobiWeight{<:Jacobi}, k)
101+
J=S.space
102+
@assert S.α 0
103+
@assert S.β J.b
104+
ConcreteLeftIntegral(S,k)
105+
end
106+
107+
function RightIntegral(S::JacobiWeight{<:Jacobi}, k)
108+
J=S.space
109+
@assert S.α J.a
110+
@assert S.β 0
111+
ConcreteRightIntegral(S,k)
112+
end
113+
114+
115+
116+
function LeftIntegral(S::JacobiWeight{<:Chebyshev},k)
117+
# convert to Jacobi
118+
Q=LeftIntegral(JacobiWeight(S.β,S.α,Jacobi(S.space)),k)
119+
LeftIntegralWrapper(Q*Conversion(S,domainspace(Q)),k,S,rangespace(Q))
120+
end
121+
122+
function RightIntegral(S::JacobiWeight{<:Chebyshev},k)
123+
# convert to Jacobi
124+
Q=RightIntegral(JacobiWeight(S.β,S.α,Jacobi(S.space)),k)
125+
RightIntegralWrapper(Q*Conversion(S,domainspace(Q)),k,S,rangespace(Q))
126+
end
127+
128+
for (TYP,WRAP) in ((:LeftIntegral,:LeftIntegralWrapper),
129+
(:RightIntegral,:RightIntegralWrapper))
130+
131+
@eval function $TYP(S::JacobiWeight{<:PolynomialSpace}, k)
132+
JS = JacobiWeight(S.β,S.α,Jacobi(S.space))
133+
IOP = $TYP(JS,k)
134+
$WRAP(IOP*Conversion(S,JS),k,S,rangespace(IOP))
135+
end
136+
end
137+
138+
139+
#DLMF18.17.9
140+
function rangespace(Q::ConcreteLeftIntegral{<:JacobiWeight{<:Jacobi{DD,RR},DD,RR}}) where {DD<:IntervalOrSegment,RR}
141+
μ=Q.order
142+
S=domainspace(Q)
143+
J=S.space
144+
if isapprox(S.β,-μ)
145+
Jacobi(J.b+μ,J.a-μ,domain(J))
146+
else
147+
JacobiWeight(S.β+μ,zero(S.β),Jacobi(J.b+μ,J.a-μ,domain(J)))
148+
end
149+
end
150+
151+
function rangespace(Q::ConcreteRightIntegral{<:JacobiWeight{<:Jacobi{DD,RR},DD,RR}}) where {DD<:IntervalOrSegment,RR}
152+
μ=Q.order
153+
S=domainspace(Q)
154+
J=S.space
155+
@assert S.α==J.a
156+
@assert S.β==0
157+
if isapprox(S.β,-μ)
158+
Jacobi(J.b-μ,J.a+μ,domain(J))
159+
else
160+
JacobiWeight(zero(S.α),S.α+μ,Jacobi(J.b-μ,J.a+μ,domain(J)))
161+
end
162+
end
163+
164+
for TYP in (:ConcreteLeftIntegral,:ConcreteRightIntegral)
165+
@eval bandwidths(Q::$TYP{<:JacobiWeight{<:Jacobi{DD,RR},DD,RR}}) where {DD<:IntervalOrSegment,RR} = (0,0)
166+
end
167+
168+
getindex(Q::ConcreteLeftIntegral{<:JacobiWeight{<:Jacobi{DD,RR},DD,RR},<:Any,T},k::Integer,j::Integer) where {DD<:IntervalOrSegment,RR,T} =
169+
convert(T,jacobi_frac_getindex(domain(Q),domainspace(Q).β,Q.order,k,j))::T
170+
171+
getindex(Q::ConcreteRightIntegral{<:JacobiWeight{<:Jacobi{DD,RR},DD,RR},<:Any,T},k::Integer,j::Integer) where {DD<:IntervalOrSegment,RR,T} =
172+
convert(T,jacobi_frac_getindex(domain(Q),domainspace(Q).α,Q.order,k,j))::T
173+
174+
function choosedomainspace(Q::LeftIntegral{UnsetSpace}, sp::JacobiWeight)
175+
@assert sp.β>0 && isapproxinteger(sp.α)
176+
177+
if isapprox(Q.order,sp.β)
178+
Legendre(domain(sp))
179+
else
180+
JacobiWeight(sp.β-Q.order,0.,Jacobi(sp.β-Q.order,0.,domain(sp)))
181+
end
182+
end
183+
184+
choosedomainspace(Q::LeftIntegral{UnsetSpace,T}, sp::PolynomialSpace) where {T} =
185+
JacobiWeight(-Q.order,zero(T),Jacobi(-Q.order,-Q.order,domain(sp)))
186+
187+
188+
189+
function choosedomainspace(Q::RightIntegral{UnsetSpace,T},sp::JacobiWeight) where T
190+
@assert sp.α>0 && isapproxinteger(sp.β)
191+
192+
if isapprox(Q.order,sp.α)
193+
Legendre(domain(sp))
194+
else
195+
JacobiWeight(zero(T),sp.α-Q.order,Jacobi(0.,sp.α-Q.order))
196+
end
197+
end
198+
choosedomainspace(Q::RightIntegral{UnsetSpace,T},sp::PolynomialSpace) where {T}=
199+
JacobiWeight(zero(T),-Q.order,Jacobi(-Q.order,-Q.order,domain(sp)))
200+
201+
202+
203+
204+
# Define Left/RightDerivative
205+
for (DTYP,QTYP,DWRAP,QWRAP) in ((:LeftDerivative,:LeftIntegral,:LeftDerivativeWrapper,:LeftIntegralWrapper),
206+
(:RightDerivative,:RightIntegral,:RightDerivativeWrapper,:RightIntegralWrapper))
207+
@eval begin
208+
function $DTYP(S::Space,k::Real)
209+
i=ceil(Int,k)
210+
r=i-k
211+
$DWRAP(i<0 ? $QTYP(S,-k) : Derivative(i)*$QTYP(S,r),k,S)
212+
end
213+
function $QTYP(S::SumSpace,k)
214+
t = map(s->$QTYP(s,k),components(S))
215+
IOP = InterlaceOperator_Diagonal(t,S)
216+
$QWRAP(IOP,k)
217+
end
218+
end
219+
end

0 commit comments

Comments
 (0)