Skip to content

Commit 9f8af07

Browse files
authored
Kronecker operators on BivariateFuns (#229)
* kronecker operators on bivariate fun * remove unused methods * bugfix in getindex * version bump to v0.7.19
1 parent 78c242c commit 9f8af07

File tree

5 files changed

+100
-14
lines changed

5 files changed

+100
-14
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ApproxFunBase"
22
uuid = "fbd15aa5-315a-5a7d-a8a4-24992e37be05"
3-
version = "0.7.18"
3+
version = "0.7.19"
44

55
[deps]
66
AbstractFFTs = "621f4979-c628-5d54-868e-fcf4e3e8185c"

src/Multivariate/ProductFun.jl

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,29 @@
55

66
export ProductFun
77

8+
"""
9+
ProductFun(f, space::TensorSpace; [tol=eps()])
10+
11+
Represent a bivariate function `f(x,y)` as a univariate expansion over the second space,
12+
with the coefficients being functions in the first space.
13+
```math
14+
f\\left(x,y\\right)=\\sum_{i}f_{i}\\left(x\\right)b_{i}\\left(y\\right),
15+
```
16+
where ``b_{i}\\left(y\\right)`` represents the ``i``-th basis function in the space over ``y``.
17+
18+
# Examples
19+
```jldoctest
20+
julia> P = ProductFun((x,y)->x*y, Chebyshev() ⊗ Chebyshev());
21+
22+
julia> P(0.1, 0.2) ≈ 0.1 * 0.2
23+
true
24+
25+
julia> coefficients(P) # power only at the (1,1) Chebyshev mode
26+
2×2 Matrix{Float64}:
27+
0.0 0.0
28+
0.0 1.0
29+
```
30+
"""
831
struct ProductFun{S<:UnivariateSpace,V<:UnivariateSpace,SS<:AbstractProductSpace,T} <: BivariateFun{T}
932
coefficients::Vector{VFun{S,T}} # coefficients are in x
1033
space::SS
@@ -22,6 +45,22 @@ Base.size(f::ProductFun) = (size(f,1),size(f,2))
2245

2346
## Construction in an AbstractProductSpace via a Matrix of coefficients
2447

48+
"""
49+
ProductFun(coeffs::AbstractMatrix{T}, sp::AbstractProductSpace; [tol=100eps(T)], [chopping=false]) where {T<:Number}
50+
51+
Represent a bivariate function `f` in terms of the coefficient matrix `coeffs`,
52+
where the coefficients are obtained using a bivariate
53+
transform of the function `f` in the basis `sp`.
54+
55+
# Examples
56+
```jldoctest
57+
julia> P = ProductFun([0 0; 0 1], Chebyshev() ⊗ Chebyshev()) # corresponds to (x,y) -> x*y
58+
ProductFun on Chebyshev() ⊗ Chebyshev()
59+
60+
julia> P(0.1, 0.2) ≈ 0.1 * 0.2
61+
true
62+
```
63+
"""
2564
function ProductFun(cfs::AbstractMatrix{T},sp::AbstractProductSpace{Tuple{S,V},DD};
2665
tol::Real=100eps(T),chopping::Bool=false) where {S<:UnivariateSpace,V<:UnivariateSpace,T<:Number,DD}
2766
if chopping
@@ -36,8 +75,25 @@ function ProductFun(cfs::AbstractMatrix{T},sp::AbstractProductSpace{Tuple{S,V},D
3675
end
3776

3877
## Construction in a ProductSpace via a Vector of Funs
39-
40-
function ProductFun(M::AbstractVector{VFun{S,T}},dy::V) where {S<:UnivariateSpace,V<:UnivariateSpace,T<:Number}
78+
"""
79+
ProductFun(M::AbstractVector{<:Fun{<:UnivariateSpace}}, sp::UnivariateSpace)
80+
81+
Represent a bivariate function `f(x,y)` in terms of the univariate coefficient functions from `M`.
82+
The function `f` may be reconstructed as
83+
```math
84+
f\\left(x,y\\right)=\\sum_{i}M_{i}\\left(x\\right)b_{i}\\left(y\\right),
85+
```
86+
where ``b_{i}\\left(y\\right)`` represents the ``i``-th basis function for the space `sp`.
87+
88+
# Examples
89+
```jldoctest
90+
julia> P = ProductFun([zeros(Chebyshev()), Fun(Chebyshev())], Chebyshev()); # corresponds to (x,y)->x*y
91+
92+
julia> P(0.1, 0.2) ≈ 0.1 * 0.2
93+
true
94+
```
95+
"""
96+
function ProductFun(M::AbstractVector{VFun{S,T}}, dy::V) where {S<:UnivariateSpace,V<:UnivariateSpace,T<:Number}
4197
prodsp = ProductSpace(map(space, M), dy)
4298
ProductFun{S,V,typeof(prodsp),T}(copy(M), prodsp)
4399
end

src/Operators/Operator.jl

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -472,12 +472,13 @@ true
472472
```
473473
"""
474474
getindex(B::Operator,f::Fun) = B*Multiplication(domainspace(B),f)
475-
getindex(B::Operator,f::LowRankFun{S,M,SS,T}) where {S,M,SS,T} = mapreduce(i->f.A[i]*B[f.B[i]],+,1:rank(f))
476-
getindex(B::Operator{BT},f::ProductFun{S,V,SS,T}) where {BT,S,V,SS,T} =
477-
mapreduce(i->f.coefficients[i]*B[Fun(f.space[2],[zeros(promote_type(BT,T),i-1);
478-
one(promote_type(BT,T))])],
479-
+,1:length(f.coefficients))
480-
475+
getindex(B::Operator,f::LowRankFun) = mapreduce(((fAi,fBi),) -> fAi * B[fBi], +, zip(f.A, f.B))
476+
function getindex(B::Operator{BT}, f::ProductFun{S,V,SS,T}) where {BT,S,V,SS,T}
477+
TBF = promote_type(BT,T)
478+
sp2 = factors(f.space)[2]
479+
mapreduce(((ind, fi),)-> fi * B[Fun(sp2, [zeros(TBF,i-1); one(TBF)])], +,
480+
enumerate(f.coefficients))
481+
end
481482

482483

483484
# Convenience for wrapper ops

src/PDE/KroneckerOperator.jl

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,9 +353,9 @@ function BandedBlockBandedMatrix(S::SubOperator{T,KroneckerOperator{SS,V,DS,RS,
353353
A,B = KO.ops
354354

355355

356-
AA = strictconvert(BandedMatrix, view(A, Block(1):last(KR),Block(1):last(JR)))::BandedMatrix{eltype(S)}
356+
AA = strictconvert(BandedMatrix, view(A, Block(1):last(KR),Block(1):last(JR)))
357357
Al,Au = bandwidths(AA)
358-
BB = strictconvert(BandedMatrix, view(B, Block(1):last(KR),Block(1):last(JR)))::BandedMatrix{eltype(S)}
358+
BB = strictconvert(BandedMatrix, view(B, Block(1):last(KR),Block(1):last(JR)))
359359
Bl,Bu = bandwidths(BB)
360360
λ,μ = subblockbandwidths(ret)
361361

@@ -364,7 +364,7 @@ function BandedBlockBandedMatrix(S::SubOperator{T,KroneckerOperator{SS,V,DS,RS,
364364
Bs = view(ret, K, J)
365365
l = min(Al,Bu+n-m,λ)
366366
u = min(Au,Bl+m-n,μ)
367-
@inbounds for j=1:m, k=max(1,j-u):min(n,j+l)
367+
for j=1:m, k=max(1,j-u):min(n,j+l)
368368
a = AA[k,j]
369369
b = BB[n-k+1,m-j+1]
370370
c = a*b
@@ -422,3 +422,25 @@ function mul_coefficients(A::SubOperator{T,KKO,Tuple{UnitRange{Int},UnitRange{In
422422
M = P[KR,JR]
423423
M*pad(b, size(M,2))
424424
end
425+
426+
Base.getindex(A::KroneckerOperator, B::MultivariateFun) = A[Fun(B)]
427+
function Base.getindex(K::KroneckerOperator, f::LowRankFun)
428+
op1, op2 = K.ops
429+
mapreduce(((A,B),)-> op1[A] op2[B], +, zip(f.A, f.B))
430+
end
431+
function Base.getindex(K::KroneckerOperator, B::ProductFun)
432+
op1, op2 = K.ops
433+
S2 = factors(B.space)[2]
434+
T = cfstype(B)
435+
mapreduce(((ind, fi),)-> op1[fi] op2[Fun(S2, [zeros(T, ind-1); one(T)])], +,
436+
enumerate(B.coefficients))
437+
end
438+
for F in [:LowRankFun, :ProductFun, :MultivariateFun]
439+
for O in [:DerivativeWrapper, :DefiniteIntegralWrapper]
440+
@eval Base.getindex(K::$O{<:KroneckerOperator}, f::$F) = K.op[f]
441+
@eval (*)(A::KroneckerOperator, B::$F) = A * Fun(B)
442+
@eval (*)(A::$O{<:KroneckerOperator}, B::$F) = A.op * B
443+
@eval (*)(A::$F, B::KroneckerOperator) = Fun(A) * B
444+
@eval (*)(A::$F, B::$O{<:KroneckerOperator}) = Fun(A) * B.op
445+
end
446+
end

src/hacks.jl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,22 @@ Fun(f::Fun) = f # Fun of Fun should be like a conversion
1818
"""
1919
Fun(f)
2020
21-
Return `Fun(f, Chebyshev())`
21+
Return `Fun(f, space)` by choosing an appropriate `space` for the function.
22+
For univariate functions, `space` is chosen to be `Chebyshev()`, whereas for
23+
multivariate functions, it is a tensor product of `Chebyshev()` spaces.
2224
2325
# Examples
2426
```jldoctest
25-
julia> f = Fun(x->x^2)
27+
julia> f = Fun(x -> x^2)
2628
Fun(Chebyshev(), [0.5, 0.0, 0.5])
2729
2830
julia> f(0.1) == (0.1)^2
2931
true
32+
33+
julia> f = Fun((x,y) -> x + y);
34+
35+
julia> f(0.1, 0.2) ≈ 0.3
36+
true
3037
```
3138
"""
3239
function Fun(fin::Function)

0 commit comments

Comments
 (0)