Skip to content

Commit 5b4763f

Browse files
authored
Support 2D Clenshaw on rectangles (#196)
* Support 2D Clenshaw on rectangles * Update test_rect.jl * ClenshawKron implemented * Update Project.toml * Update Project.toml * overload broadcast for RectPoly * v0.8
1 parent 00b7a65 commit 5b4763f

File tree

5 files changed

+137
-17
lines changed

5 files changed

+137
-17
lines changed

Project.toml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "MultivariateOrthogonalPolynomials"
22
uuid = "4f6956fd-4f93-5457-9149-7bfc4b2ce06d"
3-
version = "0.7.2"
3+
version = "0.8"
44

55
[deps]
66
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
@@ -19,6 +19,7 @@ LazyArrays = "5078a376-72f3-5289-bfd5-ec5146d43c02"
1919
LazyBandedMatrices = "d7e5e226-e90b-4449-9968-0f923699bf6f"
2020
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
2121
QuasiArrays = "c4ea9172-b204-11e9-377d-29865faadc5c"
22+
RecurrenceRelationships = "807425ed-42ea-44d6-a357-6771516d7b2c"
2223
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
2324
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
2425
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
@@ -28,17 +29,18 @@ ArrayLayouts = "1.0.9"
2829
BandedMatrices = "1"
2930
BlockArrays = "1.0"
3031
BlockBandedMatrices = "0.13"
31-
ClassicalOrthogonalPolynomials = "0.14"
32+
ClassicalOrthogonalPolynomials = "0.14.1"
3233
ContinuumArrays = "0.18"
33-
DomainSets = "0.6, 0.7"
34-
FastTransforms = "0.16"
34+
DomainSets = "0.7"
35+
FastTransforms = "0.17"
3536
FillArrays = "1.0"
36-
HarmonicOrthogonalPolynomials = "0.6"
37+
HarmonicOrthogonalPolynomials = "0.6.3"
3738
InfiniteArrays = "0.15"
3839
InfiniteLinearAlgebra = "0.9"
3940
LazyArrays = "2.3.1"
40-
LazyBandedMatrices = "0.11"
41+
LazyBandedMatrices = "0.11.1"
4142
QuasiArrays = "0.11"
43+
RecurrenceRelationships = "0.2"
4244
SpecialFunctions = "1, 2"
4345
StaticArrays = "1"
4446
julia = "1.10"

src/MultivariateOrthogonalPolynomials.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,27 @@ using QuasiArrays: AbstractVector
44
using ClassicalOrthogonalPolynomials, FastTransforms, BlockBandedMatrices, BlockArrays, DomainSets,
55
QuasiArrays, StaticArrays, ContinuumArrays, InfiniteArrays, InfiniteLinearAlgebra,
66
LazyArrays, SpecialFunctions, LinearAlgebra, BandedMatrices, LazyBandedMatrices, ArrayLayouts,
7-
HarmonicOrthogonalPolynomials
7+
HarmonicOrthogonalPolynomials, RecurrenceRelationships
88

99
import Base: axes, in, ==, +, -, /, *, ^, \, copy, copyto!, OneTo, getindex, size, oneto, all, resize!, BroadcastStyle, similar, fill!, setindex!, convert, show, summary
1010
import Base.Broadcast: Broadcasted, broadcasted, DefaultArrayStyle
1111
import DomainSets: boundary, EuclideanDomain
1212

1313
import QuasiArrays: LazyQuasiMatrix, LazyQuasiArrayStyle, domain
14-
import ContinuumArrays: @simplify, Weight, weight, grid, plotgrid, TransformFactorization, ExpansionLayout, plotvalues, unweighted, plan_transform, checkpoints, transform_ldiv, AbstractBasisLayout, basis_axes, Inclusion, grammatrix, weaklaplacian
14+
import ContinuumArrays: @simplify, Weight, weight, grid, plotgrid, TransformFactorization, ExpansionLayout, plotvalues, unweighted, plan_transform, checkpoints, transform_ldiv, AbstractBasisLayout, basis_axes, Inclusion, grammatrix, weaklaplacian, layout_broadcasted
1515

1616
import ArrayLayouts: MemoryLayout, sublayout, sub_materialize
1717
import BlockArrays: block, blockindex, BlockSlice, viewblock, blockcolsupport, AbstractBlockStyle, BlockStyle
1818
import BlockBandedMatrices: _BandedBlockBandedMatrix, AbstractBandedBlockBandedMatrix, _BandedMatrix, blockbandwidths, subblockbandwidths
1919
import LinearAlgebra: factorize
2020
import LazyArrays: arguments, paddeddata, LazyArrayStyle, LazyLayout, PaddedLayout, applylayout, LazyMatrix, ApplyMatrix
21-
import LazyBandedMatrices: LazyBandedBlockBandedLayout, AbstractBandedBlockBandedLayout, AbstractLazyBandedBlockBandedLayout, _krontrav_axes, DiagTravLayout, invdiagtrav, ApplyBandedBlockBandedLayout
21+
import LazyBandedMatrices: LazyBandedBlockBandedLayout, AbstractBandedBlockBandedLayout, AbstractLazyBandedBlockBandedLayout, _krontrav_axes, DiagTravLayout, invdiagtrav, ApplyBandedBlockBandedLayout, krontrav
2222
import InfiniteArrays: InfiniteCardinal, OneToInf
2323

24-
import ClassicalOrthogonalPolynomials: jacobimatrix, Weighted, orthogonalityweight, HalfWeighted, WeightedBasis, pad, recurrencecoefficients, clenshaw, weightedgrammatrix
24+
import ClassicalOrthogonalPolynomials: jacobimatrix, Weighted, orthogonalityweight, HalfWeighted, WeightedBasis, pad, recurrencecoefficients, clenshaw, weightedgrammatrix, Clenshaw
2525
import HarmonicOrthogonalPolynomials: BivariateOrthogonalPolynomial, MultivariateOrthogonalPolynomial, Plan,
2626
PartialDerivative, AngularMomentum, BlockOneTo, BlockRange1, interlace,
27-
MultivariateOPLayout, MAX_PLOT_BLOCKS
27+
MultivariateOPLayout, AbstractMultivariateOPLayout, MAX_PLOT_BLOCKS
2828

2929
export MultivariateOrthogonalPolynomial, BivariateOrthogonalPolynomial,
3030
UnitTriangle, UnitDisk,
@@ -36,6 +36,7 @@ export MultivariateOrthogonalPolynomial, BivariateOrthogonalPolynomial,
3636
grammatrix, oneto
3737

3838
include("ModalInterlace.jl")
39+
include("clenshawkron.jl")
3940
include("rect.jl")
4041
include("disk.jl")
4142
include("rectdisk.jl")

src/clenshawkron.jl

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
2+
"""
3+
ClenshawKron(coefficientmatrix, (A₁,A₂), (B₁,B₂), (C₁,C₂), (X₁,X₂)))
4+
5+
represents the multiplication operator of a tensor product of two orthogonal polynomials. That is,
6+
if `f(x,y) = P(x)*F*Q(y)'` and `a(x,y) = R(x)*A*S(y)'` then
7+
8+
M = ClenshawKron(A, tuple.(recurrencecoefficients(R), recurrencecoefficients(S)), (jacobimatrix(P), jacobimatrix(Q))
9+
M * KronTrav(F)
10+
11+
Gives the coefficients of `a(x,y)*f(x,y)`.
12+
"""
13+
struct ClenshawKron{T, Coefs<:AbstractMatrix{T}, Rec<:NTuple{2,NTuple{3,AbstractVector}}, Jac<:NTuple{2,AbstractMatrix}} <: AbstractBandedBlockBandedMatrix{T}
14+
c::Coefs
15+
recurrencecoeffients::Rec
16+
X::Jac
17+
end
18+
19+
20+
copy(M::ClenshawKron) = M
21+
size(M::ClenshawKron) = (ℵ₀, ℵ₀)
22+
axes(M::ClenshawKron) = (blockedrange(oneto(∞)),blockedrange(oneto(∞)))
23+
blockbandwidths(M::ClenshawKron) = (size(M.c,1)-1,size(M.c,1)-1)
24+
subblockbandwidths(M::ClenshawKron) = (size(M.c,2)-1,size(M.c,2)-1)
25+
26+
struct ClenshawKronLayout <: AbstractLazyBandedBlockBandedLayout end
27+
MemoryLayout(::Type{<:ClenshawKron}) = ClenshawKronLayout()
28+
29+
function square_getindex(M::ClenshawKron, N::Block{1})
30+
# Consider P(x) = L^1_x \ 𝐞_0
31+
# So that if a(x,y) = P(x)*c*Q(y)' then we have
32+
# a(X,Y) = 𝐞_0' * inv(L^1_X') * c * Q(Y)'
33+
# So we first apply 1D clenshaw to each column
34+
35+
(A₁,B₁,C₁), (A₂,B₂,C₂) = M.recurrencecoeffients
36+
X,Y = M.X
37+
m,n = size(M.c)
38+
@assert m == n
39+
# Apply Clenshaw to each column
40+
g = (a,b,N) -> LazyBandedMatrices.krontrav(a[1:N,1:N], b[1:N,1:N])
41+
cols = [Clenshaw(M.c[1:m-j+1,j], A₁, B₁, C₁, X) for j=1:n]
42+
43+
M = m-2+Int(N) # over sample
44+
Q_Y = forwardrecurrence(n, A₂, B₂, C₂, Y[1:M,1:M])
45+
+(broadcast((a,b,N) -> LazyBandedMatrices.krontrav(a[1:N,1:N], b[1:N,1:N]), Q_Y, cols, Int(N))...)
46+
end
47+
48+
getindex(M::ClenshawKron, KR::BlockRange{1}, JR::BlockRange{1}) = square_getindex(M, max(maximum(KR), maximum(JR)))[KR,JR]
49+
getindex(M::ClenshawKron, K::Block{1}, J::Block{1}) = square_getindex(M, max(K, J))[K,J]
50+
getindex(M::ClenshawKron, Kk::BlockIndex{1}, Jj::BlockIndex{1}) = M[block(Kk), block(Jj)][blockindex(Kk), blockindex(Jj)]
51+
getindex(M::ClenshawKron, k::Int, j::Int) = M[findblockindex(axes(M,1),k), findblockindex(axes(M,2),j)]
52+
53+
Base.array_summary(io::IO, C::ClenshawKron{T}, inds) where T =
54+
print(io, Base.dims2string(length.(inds)), " ClenshawKron{$T} with $(size(C.c)) polynomial")
55+
56+
Base.summary(io::IO, C::ClenshawKron) = Base.array_summary(io, C, axes(C))

src/rect.jl

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ end
1818

1919
==(A::KronPolynomial, B::KronPolynomial) = length(A.args) == length(B.args) && all(map(==, A.args, B.args))
2020

21+
22+
struct KronOPLayout{d} <: AbstractMultivariateOPLayout{d} end
23+
MemoryLayout(::Type{<:KronPolynomial{d}}) where d = KronOPLayout{d}()
24+
2125
const RectPolynomial{T, PP} = KronPolynomial{2, T, PP}
2226

2327

@@ -71,7 +75,7 @@ end
7175
function \(P::RectPolynomial, Q::RectPolynomial)
7276
PA,PB = P.args
7377
QA,QB = Q.args
74-
KronTrav(PA\QA, PB\QB)
78+
krontrav(PA\QA, PB\QB)
7579
end
7680

7781
@simplify function *(Ac::QuasiAdjoint{<:Any,<:RectPolynomial}, B::RectPolynomial)
@@ -144,14 +148,14 @@ pad(C::DiagTrav, ::BlockedOneTo{Int,RangeCumsum{Int,OneToInf{Int}}}) = DiagTrav(
144148

145149
QuasiArrays.mul(A::BivariateOrthogonalPolynomial, b::DiagTrav) = ApplyQuasiArray(*, A, b)
146150

147-
function Base.unsafe_getindex(f::Mul{MultivariateOPLayout{2},<:DiagTravLayout{<:PaddedLayout}}, 𝐱::SVector)
151+
function Base.unsafe_getindex(f::Mul{KronOPLayout{2},<:DiagTravLayout{<:PaddedLayout}}, 𝐱::SVector)
148152
P,c = f.A, f.B
149153
A,B = P.args
150154
x,y = 𝐱
151-
clenshaw(clenshaw(paddeddata(c.array), recurrencecoefficients(A)..., x), recurrencecoefficients(B)..., y)
155+
clenshaw(vec(clenshaw(paddeddata(c.array), recurrencecoefficients(A)..., x; dims=1)), recurrencecoefficients(B)..., y)
152156
end
153157

154-
Base.@propagate_inbounds function getindex(f::Mul{MultivariateOPLayout{2},<:DiagTravLayout{<:PaddedLayout}}, x::SVector, j...)
158+
Base.@propagate_inbounds function getindex(f::Mul{KronOPLayout{2},<:DiagTravLayout{<:PaddedLayout}}, x::SVector, j...)
155159
@inbounds checkbounds(ApplyQuasiArray(*,f.A,f.B), x, j...)
156160
Base.unsafe_getindex(f, x, j...)
157161
end
@@ -171,3 +175,16 @@ function Base._sum(P::RectPolynomial, dims)
171175
@assert dims == 1
172176
KronTrav(sum.(P.args; dims=1)...)
173177
end
178+
179+
## multiplication
180+
181+
function layout_broadcasted(::Tuple{ExpansionLayout{KronOPLayout{2}},KronOPLayout{2}}, ::typeof(*), a, P)
182+
axes(a,1) == axes(P,1) || throw(DimensionMismatch())
183+
184+
A,B = basis(a).args
185+
T,U = P.args
186+
187+
C = paddeddata(invdiagtrav(coefficients(a)))
188+
189+
P * ClenshawKron(C, (recurrencecoefficients(A), recurrencecoefficients(B)), (jacobimatrix(T), jacobimatrix(U)))
190+
end

test/test_rect.jl

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
using MultivariateOrthogonalPolynomials, ClassicalOrthogonalPolynomials, StaticArrays, LinearAlgebra, BlockArrays, FillArrays, Base64, LazyBandedMatrices, Test
2-
using ClassicalOrthogonalPolynomials: expand
3-
using MultivariateOrthogonalPolynomials: weaklaplacian
2+
using ClassicalOrthogonalPolynomials: expand, coefficients, recurrencecoefficients
3+
using MultivariateOrthogonalPolynomials: weaklaplacian, ClenshawKron
44
using ContinuumArrays: plotgridvalues
5+
using Base: oneto
56

67
@testset "RectPolynomial" begin
78
@testset "Evaluation" begin
@@ -154,4 +155,47 @@ using ContinuumArrays: plotgridvalues
154155
Dₓ = KronTrav(D²,M)
155156
@test Dₓ[Block.(1:1),Block.(1:1)] == Dₓ[Block(1,1)]
156157
end
158+
159+
@testset "variable coefficients" begin
160+
T,U = ChebyshevT(), ChebyshevU()
161+
P = RectPolynomial(T, U)
162+
𝐱 = axes(P,1)
163+
x,y = first.(𝐱), last.(𝐱)
164+
X = P\(x .* P)
165+
Y = P\(y .* P)
166+
167+
@test X isa KronTrav
168+
@test Y isa KronTrav
169+
170+
a = (x,y) -> I + x + 2y + 3x^2 +4x*y + 5y^2
171+
𝐚 = expand(P,splat(a))
172+
173+
@testset "ClenshawKron" begin
174+
C = LazyBandedMatrices.paddeddata(LazyBandedMatrices.invdiagtrav(coefficients(𝐚)))
175+
176+
A = ClenshawKron(C, (recurrencecoefficients(T), recurrencecoefficients(U)), (jacobimatrix(T), jacobimatrix(U)))
177+
178+
@test copy(A) A
179+
@test size(A) == size(X)
180+
@test summary(A) == "ℵ₀×ℵ₀ ClenshawKron{Float64} with (3, 3) polynomial"
181+
182+
= a(X,Y)
183+
for (k,j) in ((Block.(oneto(5)),Block.(oneto(5))), Block.(oneto(5)),Block.(oneto(6)), (Block(2), Block(3)), (4,5),
184+
(Block(2)[2], Block(3)[3]), (Block(2)[2], Block(3)))
185+
@test A[k,j] Ã[k,j]
186+
end
187+
188+
@test A[Block(1,2)] Ã[Block(1,2)]
189+
@test A[Block(1,2)][1,2] Ã[Block(1,2)[1,2]]
190+
end
191+
192+
@test P \ (𝐚 .* P) isa ClenshawKron
193+
194+
@test (𝐚 .* 𝐚)[SVector(0.1,0.2)] 𝐚[SVector(0.1,0.2)]^2
195+
196+
𝐛 = expand(RectPolynomial(Legendre(),Ultraspherical(3/2)),splat((x,y) -> cos(x*sin(y))))
197+
@test (𝐛 .* 𝐚)[SVector(0.1,0.2)] 𝐚[SVector(0.1,0.2)]𝐛[SVector(0.1,0.2)]
198+
199+
𝐜 = expand(RectPolynomial(Legendre(),Jacobi(1,0)),splat((x,y) -> cos(x*sin(y))))
200+
end
157201
end

0 commit comments

Comments
 (0)