Skip to content

Commit 9fe3832

Browse files
authored
Improve type-inference in recursive Jacobi multiplication (#89)
* Improve type-inference in recursive Jacobi multiplication * half integer tests * Add inference test for HalfOddInt weights
1 parent 696e4a7 commit 9fe3832

File tree

4 files changed

+76
-10
lines changed

4 files changed

+76
-10
lines changed

Project.toml

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

55
[deps]
66
ApproxFunBase = "fbd15aa5-315a-5a7d-a8a4-24992e37be05"
77
ApproxFunOrthogonalPolynomials = "b70543e2-c0d9-56b8-a290-0d4d6d4de211"
8+
BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0"
89
DomainSets = "5b8099bc-c8ec-5219-889f-1d9e522a28bf"
910
HalfIntegers = "f0d1745a-41c9-11e9-1dd9-e5d34d218721"
1011
IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953"
@@ -25,6 +26,7 @@ ApproxFunBase = "0.8.56, 0.9.12"
2526
ApproxFunBaseTest = "0.1"
2627
ApproxFunOrthogonalPolynomials = "0.2.3, 0.3, 0.4, 0.5, 0.6"
2728
Aqua = "0.7"
29+
BlockBandedMatrices = "0.11, 0.12"
2830
DomainSets = "0.4, 0.5, 0.6"
2931
HalfIntegers = "1.5"
3032
IntervalSets = "0.5, 0.6, 0.7"

src/ApproxFunSingularities.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,16 @@ import ApproxFunBase: Fun, SumSpace, SubSpace, WeightSpace, NoSpace,
3131
dotu, components, promoterangespace, ∞,
3232
assert_integer, SpecialEvalPtType, isleftendpoint, isrightendpoint, evaluation_point,
3333
@calculus_operator, ConcreteConversion, InterlaceOperator_Diagonal, UnsetSpace,
34-
choosedomainspace, mean
34+
choosedomainspace, mean, bandwidthssum
3535

3636
import ApproxFunOrthogonalPolynomials: order
3737

3838
import IntervalSets: rightendpoint, leftendpoint, Domain
3939

4040
import DomainSets: ChebyshevInterval, boundary, dimension
4141

42+
using BlockBandedMatrices: blockbandwidths, subblockbandwidths
43+
4244
import Base: convert, getindex, *, /, ^,
4345
show, sum, cumsum, complex, sqrt, abs, in, first, last,
4446
union, isapprox, zeros, one, length, ones, exp, log

src/JacobiWeight.jl

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -422,12 +422,22 @@ function Multiplication(f::Fun{<:JacobiWeight{<:ConstantSpace,<:IntervalOrSegmen
422422
elseif isapproxinteger(Sf.β) && Sf.β 1 && S.b >0
423423
# decrement β and multiply again
424424
M1 = ConcreteMultiplication(f.coefficients[1]*jacobiweight(1,0,d),S)
425-
M1_out = Multiplication(jacobiweight(Sf.β-1,Sf.α,d), rangespace(M1)) * M1
425+
M1_ = Multiplication(jacobiweight(Sf.β-1,Sf.α,d), rangespace(M1).space)
426+
bw = bandwidths(M1) .+ bandwidths(M1_)
427+
bbw = blockbandwidths(M1) .+ blockbandwidths(M1_)
428+
sbbw = subblockbandwidths(M1) .+ subblockbandwidths(M1_)
429+
ts = (size(M1, 1), size(M1_, 2))
430+
M1_out = TimesOperator(Operator{eltype(M1)}[M1_, M1], bw, ts, bbw, sbbw)
426431
MultiplicationWrapper(f, M1_out, S)
427432
elseif isapproxinteger(Sf.α) && Sf.α 1 && S.a >0
428433
# decrement α and multiply again
429434
M2 = ConcreteMultiplication(f.coefficients[1]*jacobiweight(0,1,d),S)
430-
M2_out = Multiplication(jacobiweight(Sf.β,Sf.α-1,d), rangespace(M2)) * M2
435+
M2_ = Multiplication(jacobiweight(Sf.β,Sf.α-1,d), rangespace(M2).space)
436+
bw = bandwidths(M2) .+ bandwidths(M2_)
437+
bbw = blockbandwidths(M2) .+ blockbandwidths(M2_)
438+
sbbw = subblockbandwidths(M2) .+ subblockbandwidths(M2_)
439+
ts = (size(M2, 1), size(M2_, 2))
440+
M2_out = TimesOperator(Operator{eltype(M2)}[M2_, M2], bw, ts, bbw, sbbw)
431441
MultiplicationWrapper(f, M2_out, S)
432442
else
433443
# default JacobiWeight
@@ -444,15 +454,18 @@ Multiplication(f::Fun{<:JacobiWeight{<:ConstantSpace,<:IntervalOrSegmentDomain}}
444454
function rangespace(M::ConcreteMultiplication{<:
445455
JacobiWeight{<:ConstantSpace,<:IntervalOrSegmentDomain},<:Jacobi})
446456
S=domainspace(M)
447-
if space(M.f).β==1
457+
Sf = space(M.f)
458+
zeroT = zero(Sf.β)
459+
J = if Sf.β == 1
448460
# multiply by (1+x)
449461
Jacobi(S.b-1,S.a,domain(S))
450-
elseif space(M.f).α == 1
462+
elseif Sf.α == 1
451463
# multiply by (1-x)
452464
Jacobi(S.b,S.a-1,domain(S))
453465
else
454466
error("Not implemented")
455467
end
468+
JacobiWeight(zeroT, zeroT, J)
456469
end
457470

458471
bandwidths(::ConcreteMultiplication{<:

test/runtests.jl

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ module AFSTests
33
using ApproxFunBase
44
using ApproxFunBase: HeavisideSpace, PointSpace, ArraySpace, DiracSpace, PiecewiseSegment,
55
UnionDomain, resizedata!, CachedOperator, RaggedMatrix,
6-
Block, ∞, BandedBlockBandedMatrix, NoSpace
6+
Block, ∞, BandedBlockBandedMatrix, NoSpace, ConcreteMultiplication,
7+
MultiplicationWrapper
78
using ApproxFunBaseTest: testbandedoperator, testtransforms, testfunctional,
89
testbandedblockbandedoperator
910
using ApproxFunOrthogonalPolynomials
@@ -109,9 +110,57 @@ end
109110
xg = Fun(x->x*√(1-x^2), JacobiWeight(0.5, 0.5, Jacobi(1,1)))
110111
@test Multiplication(g) * Fun(NormalizedLegendre()) xg
111112

112-
f = Fun(x -> (1-x)^2, JacobiWeight(3,4,ConstantSpace(ChebyshevInterval())));
113-
S = @inferred (f -> domainspace(Multiplication(f, Jacobi(1,1))))(f)
114-
@test S == Jacobi(1,1)
113+
genf(β,α) = Fun(x -> (1+x)^β * (1-x)^α, JacobiWeight(β,α,ConstantSpace(ChebyshevInterval())));
114+
115+
f = genf(0,2)
116+
S = Jacobi(5,5)
117+
d = domain(S)
118+
# Multiplication(f, S) is inferred as a small Union
119+
# We enumerate the possible types
120+
T1 = typeof(Multiplication(genf(1,0), S)::ConcreteMultiplication)
121+
T2 = typeof(Multiplication(f, S)::MultiplicationWrapper)
122+
T3 = typeof(Multiplication(genf(1,0), Legendre())::MultiplicationWrapper)
123+
@inferred Union{T1,T2,T3} Multiplication(f, S)
124+
125+
dsp(f, S) = domainspace(Multiplication(f, S))
126+
rsp(f, S) = rangespace(Multiplication(f, S))
127+
ds = if VERSION >= v"1.9"
128+
@inferred dsp(f, S)
129+
else
130+
dsp(f, S)
131+
end
132+
@test ds == S
133+
@test rsp(f, S) == Jacobi(5,3)
134+
135+
f = genf(4,3)
136+
S = Jacobi(2,1)
137+
@test rsp(f, S) == JacobiWeight(2,2,Legendre())
138+
139+
f = genf(half(Odd(3)), half(Odd(3)))
140+
S = Jacobi(2,0)
141+
@test @inferred(((f,S) -> domainspace(@inferred Multiplication(f, S)))(f,S)) == S
142+
@test Multiplication(f, S) * Fun(S) Fun(x->x*(1-x^2)^(3/2), JacobiWeight(3/2, 3/2, S))
143+
144+
S = Jacobi(half(Odd(1)), half(Odd(3)))
145+
@test @inferred(domainspace(@inferred Multiplication(f,S))) == S
146+
147+
@testset for β in 0:5, α in 0:5
148+
f = genf(β, α)
149+
g = Fun(x->(1+x)^2 * (1+x)^β * (1-x)^α)
150+
@testset for b in 0:8, a in 0:8
151+
S = Jacobi(b,a)
152+
w = Fun(x->(1+x)^2, S)
153+
M = Multiplication(f, S)
154+
@test domainspace(M) == S
155+
if b >= β && a >= α
156+
@test rangespace(M) == Jacobi(b-β, a-α)
157+
end
158+
if b < β && a < α
159+
@test rangespace(M) == JacobiWeight-b, α-a, Legendre())
160+
end
161+
@test Multiplication(f) * w M * w g
162+
end
163+
end
115164
end
116165

117166
@testset "Derivative" begin

0 commit comments

Comments
 (0)