Skip to content
4 changes: 3 additions & 1 deletion src/MultivariateOrthogonalPolynomials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export MultivariateOrthogonalPolynomial, BivariateOrthogonalPolynomial,
DunklXuDisk, DunklXuDiskWeight, WeightedDunklXuDisk,
Zernike, ZernikeWeight, zerniker, zernikez,
PartialDerivative, Laplacian, AbsLaplacianPower, AngularMomentum,
RadialCoordinate, Weighted, Block, jacobimatrix, KronPolynomial, RectPolynomial,
RadialCoordinate, Weighted, Block, jacobimatrix, KronPolynomial, RectPolynomial, kernel,
grammatrix, oneto

include("ModalInterlace.jl")
Expand All @@ -41,5 +41,7 @@ include("disk.jl")
include("rectdisk.jl")
include("triangle.jl")

include("kernels.jl")


end # module
19 changes: 19 additions & 0 deletions src/kernels.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const Kernel{T,F,D1,V,D2} = BroadcastQuasiMatrix{T,F,Tuple{D1,QuasiAdjoint{V,Inclusion{V,D2}}}}

"""
kernel(f)

returns `K::AbstractQuasiMatrix` such that `K[x,y] == f[SVector(x,y)]`.
"""
function kernel(f::AbstractQuasiVector{<:Real})
P², c = f.args
P,Q = P².args
P * c.array * Q'
end

@simplify function *(K::Kernel, Q::OrthogonalPolynomial)
x,y = axes(K)
Px,Py = legendre(x),legendre(y)
kernel(expand(RectPolynomial(Px, Py), splat(K.f))) * Q
end

21 changes: 18 additions & 3 deletions src/rect.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ end
RectPolynomial(A,U) * KronTrav(M, Eye{eltype(M)}(∞))
end


function weaklaplacian(P::RectPolynomial)
A,B = P.args
Δ_A,Δ_B = weaklaplacian(A), weaklaplacian(B)
Expand All @@ -59,7 +60,7 @@ end
function \(P::RectPolynomial, Q::RectPolynomial)
PA,PB = P.args
QA,QB = Q.args
KronTrav(PA\QA, PB\QB)
KronTrav(PB\QB, PA\QA)
end

@simplify function *(Ac::QuasiAdjoint{<:Any,<:RectPolynomial}, B::RectPolynomial)
Expand All @@ -68,7 +69,11 @@ end
KronTrav(PA'QA, PB'QB)
end

"""
ApplyPlan(f, plan)

applies a plan and then the function f.
"""
struct ApplyPlan{T, F, Pl}
f::F
plan::Pl
Expand All @@ -78,7 +83,6 @@ ApplyPlan(f, P) = ApplyPlan{eltype(P), typeof(f), typeof(P)}(f, P)

*(A::ApplyPlan, B::AbstractArray) = A.f(A.plan*B)

basis_axes(d::Inclusion{<:Any,<:ProductDomain}, v) = KronPolynomial(map(d -> basis(Inclusion(d)),components(d.domain))...)

struct TensorPlan{T, Plans}
plans::Plans
Expand All @@ -98,6 +102,8 @@ function checkpoints(P::RectPolynomial)
SVector.(x, y')
end

basis_axes(d::Inclusion{<:Any,<:ProductDomain}, v) = KronPolynomial(map(d -> basis(Inclusion(d)),components(d.domain))...)

function plan_grid_transform(P::KronPolynomial{d,<:Any,<:Fill}, B::Tuple{Block{1}}, dims=1:1) where d
@assert dims == 1

Expand Down Expand Up @@ -149,4 +155,13 @@ function transform_ldiv(K::KronPolynomial{d,V,<:Fill{<:Legendre}}, f::Union{Abst
T = KronPolynomial{d}(Fill(ChebyshevT{V}(), size(K.args)...))
dat = (T \ f).array
DiagTrav(pad(FastTransforms.th_cheb2leg(paddeddata(dat)), axes(dat)...))
end
end


function Base.summary(io::IO, P::RectPolynomial)
A,B = P.args
summary(io, A)
print(io, " ⊗ ")
summary(io, B)
end

1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ include("test_modalinterlace.jl")
include("test_disk.jl")
include("test_rectdisk.jl")
include("test_triangle.jl")
include("test_kernels.jl")
# include("test_dirichlettriangle.jl")
37 changes: 37 additions & 0 deletions test/test_kernels.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using MultivariateOrthogonalPolynomials, ClassicalOrthogonalPolynomials, FillArrays, LazyBandedMatrices, BlockArrays, StaticArrays, Test
using BlockBandedMatrices: _BandedBlockBandedMatrix, _BlockBandedMatrix
using Base: oneto

@testset "Kernels" begin
@testset "Basic" begin
P = Legendre()
T = Chebyshev()
P² = RectPolynomial(Fill(P, 2))
T² = RectPolynomial(Fill(T, 2))

k = (x,y) -> exp(x*cos(y))
K = kernel(expand(P², splat(k)))
@test K[0.1,0.2] ≈ k(0.1,0.2)
@test (K * expand(P, exp))[0.1] ≈ (K*expand(T, exp))[0.1] ≈ 2.5521805183347417

K = kernel(expand(T², splat(k)))
@test (K * expand(P, exp))[0.1] ≈ (K*expand(T, exp))[0.1] ≈ 2.5521805183347417


x = axes(P,1)
@test (k.(x,x') * expand(P, exp))[0.1] ≈ (k.(x,x') *expand(T, exp))[0.1] ≈ 2.5521805183347417

y = Inclusion(2..3)
@test (k.(y, x') * expand(P, exp))[2.1] ≈ (k.(y, x') * expand(T, exp))[2.1] ≈ 13.80651898993351
end

@testset "Extension" begin
Ex = _BandedBlockBandedMatrix(Ones{Int}((oneto(1),unitblocks(oneto(∞)))), blockedrange(oneto(∞)), (0,0), (0,0))
# Ey = _BlockBandedMatrix(mortar(OneElement.(oneto(∞), oneto(∞))), oneto(∞), unitblocks(oneto(∞)), (0,0))

T = ChebyshevT()
T² = RectPolynomial(Fill(T,2))
u = T² * (Ex * transform(T, exp))
@test u[SVector(0.1,0.2)] ≈ exp(0.1)
end
end
18 changes: 18 additions & 0 deletions test/test_rect.jl
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,24 @@ using ContinuumArrays: plotgridvalues
@test (P²[:,Block.(1:100)] \ f) ≈ f.args[2][Block.(1:100)]
end

@testset "Weak Laplacian" begin
W = Weighted(Jacobi(1,1))
P = Legendre()
W² = RectPolynomial(Fill(W, 2))
P² = RectPolynomial(Fill(P, 2))
𝐱 = axes(P²,1)
D_x,D_y = PartialDerivative{1}(𝐱),PartialDerivative{2}(𝐱)
Δ = -((D_x * W²)'*(D_x * W²) + (D_y * W²)'*(D_y * W²))

f = expand(P² , 𝐱 -> ((x,y) = 𝐱; x^2 + y^2 - 2))

KR = Block.(Base.OneTo(100))
@time 𝐜 = Δ[KR,KR] \ (W²'*f)[KR];
@test W²[SVector(0.1,0.2),KR]'*𝐜 ≈ (1-0.1^2)*(1-0.2^2)/2

@test \(Δ, (W²'*f); tolerance=1E-15) ≈ [0.5; zeros(∞)]
end

@testset "Show" begin
@test stringmime("text/plain", KronPolynomial(Legendre(), Chebyshev())) == "Legendre() ⊗ ChebyshevT()"
@test stringmime("text/plain", KronPolynomial(Legendre(), Chebyshev(), Jacobi(1,1))) == "Legendre() ⊗ ChebyshevT() ⊗ Jacobi(1.0, 1.0)"
Expand Down