Skip to content

Add support for kernels #149

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
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