Skip to content

Commit a0c71e1

Browse files
authored
work on Rect transform (#133)
* work on Rect transform * DiagTrav pad * Make transform and evaluate Fast * add disk sum * Update Project.toml * tests pass * v0.4
1 parent f3abe8d commit a0c71e1

File tree

9 files changed

+175
-90
lines changed

9 files changed

+175
-90
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ jobs:
1010
fail-fast: false
1111
matrix:
1212
version:
13-
- '1'
13+
- '1.7'
14+
- '1'
1415
os:
1516
- ubuntu-latest
1617
- macOS-latest

Project.toml

Lines changed: 8 additions & 8 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.3"
3+
version = "0.4"
44

55
[deps]
66
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
@@ -28,20 +28,20 @@ ArrayLayouts = "0.8.6"
2828
BandedMatrices = "0.17"
2929
BlockArrays = "0.16.14"
3030
BlockBandedMatrices = "0.11.5"
31-
ClassicalOrthogonalPolynomials = "0.6"
32-
ContinuumArrays = "0.10.2, 0.11"
31+
ClassicalOrthogonalPolynomials = "0.6.9"
32+
ContinuumArrays = "0.11"
3333
DomainSets = "0.5"
34-
FastTransforms = "0.13, 0.14"
35-
FillArrays = "0.12, 0.13"
36-
HarmonicOrthogonalPolynomials = "0.2.7"
34+
FastTransforms = "0.14"
35+
FillArrays = "0.13"
36+
HarmonicOrthogonalPolynomials = "0.3"
3737
InfiniteArrays = "0.12"
3838
InfiniteLinearAlgebra = "0.6.6"
3939
LazyArrays = "0.22.10"
40-
LazyBandedMatrices = "0.8"
40+
LazyBandedMatrices = "0.8.4"
4141
QuasiArrays = "0.9"
4242
SpecialFunctions = "1, 2"
4343
StaticArrays = "1"
44-
julia = "1.6"
44+
julia = "1.7"
4545

4646
[extras]
4747
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"

src/MultivariateOrthogonalPolynomials.jl

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,20 @@ import Base.Broadcast: Broadcasted, broadcasted, DefaultArrayStyle
1111
import DomainSets: boundary
1212

1313
import QuasiArrays: LazyQuasiMatrix, LazyQuasiArrayStyle, domain
14-
import ContinuumArrays: @simplify, Weight, weight, grid, plotgrid, TransformFactorization, ExpansionLayout, plotvalues, unweighted
14+
import ContinuumArrays: @simplify, Weight, weight, grid, plotgrid, TransformFactorization, ExpansionLayout, plotvalues, unweighted, plan_grid_transform, checkpoints
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
20-
import LazyArrays: arguments, paddeddata, LazyArrayStyle, LazyLayout
21-
import LazyBandedMatrices: LazyBandedBlockBandedLayout, AbstractBandedBlockBandedLayout, AbstractLazyBandedBlockBandedLayout, _krontrav_axes
22-
import InfiniteArrays: InfiniteCardinal
20+
import LazyArrays: arguments, paddeddata, LazyArrayStyle, LazyLayout, PaddedLayout
21+
import LazyBandedMatrices: LazyBandedBlockBandedLayout, AbstractBandedBlockBandedLayout, AbstractLazyBandedBlockBandedLayout, _krontrav_axes, DiagTravLayout
22+
import InfiniteArrays: InfiniteCardinal, OneToInf
2323

24-
import ClassicalOrthogonalPolynomials: jacobimatrix, Weighted, orthogonalityweight, HalfWeighted, WeightedBasis
24+
import ClassicalOrthogonalPolynomials: jacobimatrix, Weighted, orthogonalityweight, HalfWeighted, WeightedBasis, pad, recurrencecoefficients, clenshaw
2525
import HarmonicOrthogonalPolynomials: BivariateOrthogonalPolynomial, MultivariateOrthogonalPolynomial, Plan,
26-
PartialDerivative, AngularMomentum, BlockOneTo, BlockRange1, interlace
26+
PartialDerivative, AngularMomentum, BlockOneTo, BlockRange1, interlace,
27+
MultivariateOPLayout
2728

2829
export MultivariateOrthogonalPolynomial, BivariateOrthogonalPolynomial,
2930
UnitTriangle, UnitDisk,

src/disk.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,3 +336,14 @@ function \(A::Zernike{T}, wB::Weighted{V,Zernike{V}}) where {T,V}
336336
@assert iszero(B.a)
337337
ModalInterlace{TV}((Normalized.(Jacobi{TV}.(A.b, A.a:∞)) .\ HalfWeighted{:a}.(Normalized.(Jacobi{TV}.(B.b, B.a:∞)))) .* convert(TV, 2)^(-c/2), (ℵ₀,ℵ₀), (2Int(B.b), 2Int(A.a+A.b)))
338338
end
339+
340+
341+
###
342+
# sum
343+
###
344+
345+
function Base._sum(P::Zernike{T}, dims) where T
346+
@assert dims == 1
347+
@assert P.a == P.b == 0
348+
Hcat(sqrt(convert(T, π)), Zeros{T}(1,∞))
349+
end

src/rect.jl

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ end
55
KronPolynomial{d,T}(a::Vararg{Any,d}) where {d,T} = KronPolynomial{d,T,typeof(a)}(a)
66
KronPolynomial{d}(a::Vararg{Any,d}) where d = KronPolynomial{d,mapreduce(eltype, promote_type, a)}(a...)
77
KronPolynomial(a::Vararg{Any,d}) where d = KronPolynomial{d}(a...)
8+
KronPolynomial{d,T}(a::AbstractVector) where {d,T} = KronPolynomial{d,T,typeof(a)}(a)
9+
KronPolynomial{d}(a::AbstractVector) where d = KronPolynomial{d,eltype(eltype(a))}(a)
10+
KronPolynomial(a::AbstractVector) = KronPolynomial{length(a)}(a)
811

912
const RectPolynomial{T, PP} = KronPolynomial{2, T, PP}
1013

@@ -17,8 +20,12 @@ function getindex(P::RectPolynomial{T}, xy::StaticVector{2}, Jj::BlockIndex{1}):
1720
a[x,J-j+1]b[y,j]
1821
end
1922
getindex(P::RectPolynomial, xy::StaticVector{2}, B::Block{1}) = [P[xy, B[j]] for j=1:Int(B)]
20-
getindex(P::RectPolynomial, xy::StaticVector{2}, JR::BlockOneTo) = mortar([P[xy,Block(J)] for J = 1:Int(JR[end])])
21-
23+
function getindex(P::RectPolynomial, xy::StaticVector{2}, JR::BlockOneTo)
24+
A,B = P.args
25+
x,y = xy
26+
N = size(JR,1)
27+
DiagTrav(A[x,OneTo(N)] .* B[y,OneTo(N)]')
28+
end
2229
@simplify function *(Dx::PartialDerivative{1}, P::RectPolynomial)
2330
A,B = P.args
2431
U,M = (Derivative(axes(A,1))*A).args
@@ -36,4 +43,44 @@ function \(P::RectPolynomial, Q::RectPolynomial)
3643
PA,PB = P.args
3744
QA,QB = Q.args
3845
KronTrav(PA\QA, PB\QB)
46+
end
47+
48+
struct ApplyPlan{T, F, Pl}
49+
f::F
50+
plan::Pl
51+
end
52+
53+
ApplyPlan(f, P) = ApplyPlan{eltype(P), typeof(f), typeof(P)}(f, P)
54+
55+
*(A::ApplyPlan, B::AbstractArray) = A.f(A.plan*B)
56+
57+
function checkpoints(P::RectPolynomial)
58+
x,y = checkpoints.(P.args)
59+
SVector.(x, y')
60+
end
61+
62+
function plan_grid_transform(P::KronPolynomial{d,<:Any,<:Fill}, B, dims=1:ndims(B)) where d
63+
@assert dims == 1
64+
65+
T = first(P.args)
66+
x, F = plan_grid_transform(T, Array{eltype(B)}(undef, Fill(blocksize(B,1),d)...))
67+
@assert d == 2
68+
= Vector(x)
69+
SVector.(x̃, x̃'), ApplyPlan(DiagTrav, F)
70+
end
71+
72+
pad(C::DiagTrav, ::BlockedUnitRange{RangeCumsum{Int,OneToInf{Int}}}) = DiagTrav(pad(C.array, ∞, ∞))
73+
74+
QuasiArrays.mul(A::BivariateOrthogonalPolynomial, b::DiagTrav) = ApplyQuasiArray(*, A, b)
75+
76+
function Base.unsafe_getindex(f::Mul{MultivariateOPLayout{2},<:DiagTravLayout{<:PaddedLayout}}, 𝐱::SVector)
77+
P,c = f.A, f.B
78+
A,B = P.args
79+
x,y = 𝐱
80+
clenshaw(clenshaw(paddeddata(c.array), recurrencecoefficients(A)..., x), recurrencecoefficients(B)..., y)
81+
end
82+
83+
Base.@propagate_inbounds function getindex(f::Mul{MultivariateOPLayout{2},<:DiagTravLayout{<:PaddedLayout}}, x::SVector, j...)
84+
@inbounds checkbounds(ApplyQuasiArray(*,f.A,f.B), x, j...)
85+
Base.unsafe_getindex(f, x, j...)
3986
end

src/triangle.jl

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -570,9 +570,8 @@ getindex(P::JacobiTriangle, xy::SVector{2}, JR::BlockOneTo) =
570570
###
571571

572572
function getindex(f::ApplyQuasiVector{T,typeof(*),<:Tuple{JacobiTriangle,AbstractVector}}, xy::SVector{2})::T where T
573-
P,c∞ = arguments(f)
574-
c = paddeddata(c∞)
575-
N = blocksize(c,1)
573+
P,c = arguments(f)
574+
N = Int(last(blockcolsupport(c,1)))
576575

577576
N == 1 && return c[1]
578577
X = jacobimatrix(Val(1), P)
@@ -596,7 +595,7 @@ function getindex(f::ApplyQuasiVector{T,typeof(*),<:Tuple{JacobiTriangle,Abstrac
596595
# this also resizes γ2
597596
lmul!(C', γ2)
598597
# Need to swap sign since it should have been -C
599-
γ2 .= (-).(γ2) .+ view(c,Block(n))
598+
γ2 .= (-).(γ2) .+ c[Block(n)]
600599
γ2,γ1 = γ1,γ2
601600
muladd!(one(T), B', γ2, one(T), γ1)
602601
xy_muladd!(xy, A', γ2, one(T), γ1)
@@ -652,24 +651,23 @@ function grid(Pn::SubQuasiArray{T,2,<:JacobiTriangle,<:Tuple{Inclusion,BlockSlic
652651
trigrid(maximum(jr.block))
653652
end
654653

655-
struct TriTransform{T}
654+
struct TriPlan{T}
656655
tri2cheb::FastTransforms.FTPlan{T,2,FastTransforms.TRIANGLE}
657656
grid2cheb::FastTransforms.FTPlan{T,2,FastTransforms.TRIANGLEANALYSIS}
658657
a::T
659658
b::T
660659
c::T
661660
end
662661

663-
TriTransform{T}(F::AbstractMatrix{T}, a, b, c) where T =
664-
TriTransform{T}(plan_tri2cheb(F, a, b, c), plan_tri_analysis(F), a, b, c)
662+
TriPlan{T}(F::AbstractMatrix{T}, a, b, c) where T =
663+
TriPlan{T}(plan_tri2cheb(F, a, b, c), plan_tri_analysis(F), a, b, c)
665664

666-
TriTransform{T}(N::Block{1}, a, b, c) where T = TriTransform{T}(Matrix{T}(undef, Int(N), Int(N)), a, b, c)
665+
TriPlan{T}(N::Block{1}, a, b, c) where T = TriPlan{T}(Matrix{T}(undef, Int(N), Int(N)), a, b, c)
667666

668-
*(T::TriTransform, F::AbstractMatrix) = DiagTrav(tridenormalize!(T.tri2cheb\(T.grid2cheb*F),T.a,T.b,T.c))
667+
*(T::TriPlan, F::AbstractMatrix) = DiagTrav(tridenormalize!(T.tri2cheb\(T.grid2cheb*F),T.a,T.b,T.c))
669668

670-
function factorize(V::SubQuasiArray{T,2,<:JacobiTriangle,<:Tuple{Inclusion,BlockSlice{BlockOneTo}}}) where T
671-
P = parent(V)
672-
_,jr = parentindices(V)
673-
N = maximum(jr.block)
674-
TransformFactorization(grid(V), TriTransform{T}(N, P.a, P.b, P.c))
669+
function plan_grid_transform(P::JacobiTriangle, arr::AbstractVector, dims=1:ndims(arr))
670+
T = promote_type(eltype(P), eltype(arr))
671+
N = findblock(axes(P,2), length(arr))
672+
grid(P[:,Block.(OneTo(Int(N)))]), TriPlan{T}(N, P.a, P.b, P.c)
675673
end

test/test_disk.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using MultivariateOrthogonalPolynomials, ClassicalOrthogonalPolynomials, StaticArrays, BlockArrays, BandedMatrices, FastTransforms, LinearAlgebra, RecipesBase, Test, SpecialFunctions, LazyArrays, InfiniteArrays
22
import MultivariateOrthogonalPolynomials: ModalTrav, grid, ZernikeTransform, ZernikeITransform, *, ModalInterlace
3-
import ClassicalOrthogonalPolynomials: HalfWeighted
3+
import ClassicalOrthogonalPolynomials: HalfWeighted, expand
44
import ForwardDiff: hessian
55

66
@testset "Disk" begin
@@ -560,4 +560,10 @@ end
560560
end
561561
end
562562
end
563+
564+
@testset "sum" begin
565+
P = Zernike()
566+
@test sum(expand(P, 𝐱 -> 1)) π
567+
@test sum(expand(P, 𝐱 -> ((x,y) = 𝐱; exp(x*cos(y))))) 3.4898933353782744
568+
end
563569
end

test/test_rect.jl

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,42 @@
1-
using MultivariateOrthogonalPolynomials, ClassicalOrthogonalPolynomials, StaticArrays, LinearAlgebra, Test
1+
using MultivariateOrthogonalPolynomials, ClassicalOrthogonalPolynomials, StaticArrays, LinearAlgebra, BlockArrays, FillArrays, Test
2+
import ClassicalOrthogonalPolynomials: expand
23

34
@testset "RectPolynomial" begin
45
@testset "Evaluation" begin
56
T = ChebyshevT()
67
= RectPolynomial(T, T)
7-
xy = SVector(0.1,0.2)
8-
@test T²[xy, Block(1)[1]] == T²[xy, 1]
9-
@test T²[xy, Block(1)] == T²[xy, Block.(1:1)]
10-
@test T²[xy, Block(2)] == [0.1,0.2]
11-
@test T²[xy, Block(3)] [cos(2*acos(0.1)), 0.1*0.2, cos(2*acos(0.2))]
8+
𝐱 = SVector(0.1,0.2)
9+
@test T²[𝐱, Block(1)[1]] == T²[𝐱, 1]
10+
@test T²[𝐱, Block(1)] == T²[𝐱, Block.(1:1)]
11+
@test T²[𝐱, Block(2)] == [0.1,0.2]
12+
@test T²[𝐱, Block(3)] [cos(2*acos(0.1)), 0.1*0.2, cos(2*acos(0.2))]
1213

1314
U = ChebyshevU()
1415
V = KronPolynomial(T, U)
15-
@test V[xy, Block(1)[1]] == V[xy, 1]
16-
@test V[xy, Block(1)] == V[xy, Block.(1:1)]
17-
@test V[xy, Block(2)] == [0.1,2*0.2]
18-
@test V[xy, Block(3)] [cos(2*acos(0.1)), 2*0.1*0.2, sin(3*acos(0.2))/sin(acos(0.2))]
16+
@test V[𝐱, Block(1)[1]] == V[𝐱, 1]
17+
@test V[𝐱, Block(1)] == V[𝐱, Block.(1:1)]
18+
@test V[𝐱, Block(2)] == [0.1,2*0.2]
19+
@test V[𝐱, Block(3)] [cos(2*acos(0.1)), 2*0.1*0.2, sin(3*acos(0.2))/sin(acos(0.2))]
20+
end
21+
22+
@testset "Transform" begin
23+
T = ChebyshevT()
24+
= RectPolynomial(Fill(T, 2))
25+
T²ₙ = T²[:,Block.(Base.OneTo(5))]
26+
𝐱 = axes(T²ₙ,1)
27+
x,y = first.(𝐱),last.(𝐱)
28+
@test T²ₙ \ one.(x) == [1; zeros(14)]
29+
\ x
30+
f = expand(T², 𝐱 -> ((x,y) = 𝐱; exp(x*cos(y-0.1))))
31+
@test f[SVector(0.1,0.2)] exp(0.1*cos(0.1))
32+
33+
U = ChebyshevU()
34+
= RectPolynomial(Fill(U, 2))
35+
36+
a,b = f.args
37+
f[SVector(0.1,0.2)]
38+
39+
a,b = T² , (T² \ broadcast(𝐱 -> ((x,y) = 𝐱; exp(x*cos(y))), 𝐱))
1940
end
2041

2142
@testset "Conversion" begin
@@ -33,8 +54,8 @@ using MultivariateOrthogonalPolynomials, ClassicalOrthogonalPolynomials, StaticA
3354
= RectPolynomial(T, T)
3455
= RectPolynomial(U, U)
3556
= RectPolynomial(C, C)
36-
xy = axes(T²,1)
37-
D_x,D_y = PartialDerivative{1}(xy),PartialDerivative{2}(xy)
57+
𝐱 = axes(T²,1)
58+
D_x,D_y = PartialDerivative{1}(𝐱),PartialDerivative{2}(𝐱)
3859
D_x*
3960
D_y*
4061
\D_x*
@@ -53,8 +74,8 @@ using MultivariateOrthogonalPolynomials, ClassicalOrthogonalPolynomials, StaticA
5374
= RectPolynomial(W, W)
5475
= RectPolynomial(P, P)
5576
= RectPolynomial(Q, Q)
56-
xy = axes(W²,1)
57-
D_x,D_y = PartialDerivative{1}(xy),PartialDerivative{2}(xy)
77+
𝐱 = axes(W²,1)
78+
D_x,D_y = PartialDerivative{1}(𝐱),PartialDerivative{2}(𝐱)
5879
Δ =\(D_x^2 + D_y^2)*
5980

6081
K = Block.(1:200); @time L = Δ[K,K]; @time qr(L);

0 commit comments

Comments
 (0)