Skip to content

Commit 397b4be

Browse files
authored
Kronecker operator acting on LowRankFun/ProductFun (#242)
* multiply kronop with prodfun/lowrankfun * kron operator action on LowRankFun/ProductFun * specialize mul for constant second op * cast ProductFun to LowRankFun in getindex * fix space in kron with const 2nd op * views in ProductFun chop
1 parent c9a81db commit 397b4be

File tree

6 files changed

+64
-25
lines changed

6 files changed

+64
-25
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.23"
3+
version = "0.7.24"
44

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

src/Multivariate/Multivariate.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Fun(f::MultivariateFun,sp::Space) = Fun(Fun(f),sp)
4444

4545
Fun(f,d1::Domain,d2::Domain) = Fun(f,d1*d2)
4646

47-
coefficients(f::BivariateFun,sp::TensorSpace)=coefficients(f,sp[1],sp[2])
47+
coefficients(f::BivariateFun,sp::TensorSpace)=coefficients(f, factors(sp)...)
4848

4949

5050

src/Multivariate/ProductFun.jl

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,22 @@ true
6262
```
6363
"""
6464
function ProductFun(cfs::AbstractMatrix{T},sp::AbstractProductSpace{Tuple{S,V},DD};
65-
tol::Real=100eps(T),chopping::Bool=false) where {S<:UnivariateSpace,V<:UnivariateSpace,T<:Number,DD}
65+
tol::Real=100eps(T),chopping::Bool=false) where {S<:UnivariateSpace,V<:UnivariateSpace,T<:Number,DD}
6666
if chopping
67-
ncfs,kend=norm(cfs,Inf),size(cfs,2)
68-
if kend > 1 while isempty(chop(cfs[:,kend],ncfs*tol)) kend-=1 end end
69-
ret=VFun{S,T}[Fun(columnspace(sp,k),chop(cfs[:,k],ncfs*tol)) for k=1:max(kend,1)]
67+
ncfs, kend = norm(cfs,Inf), size(cfs,2)
68+
if kend > 1
69+
while kend > 0
70+
if all(iszero, @view(cfs[:, kend]))
71+
kend -= 1
72+
continue
73+
end
74+
if !isempty(chop(@view(cfs[:,kend]), ncfs*tol))
75+
break
76+
end
77+
kend-=1
78+
end
79+
end
80+
ret=VFun{S,T}[Fun(columnspace(sp,k),chop(@view(cfs[:,k]), ncfs*tol)) for k=1:max(kend,1)]
7081
ProductFun{S,V,typeof(sp),T}(ret,sp)
7182
else
7283
ret=VFun{S,T}[Fun(columnspace(sp,k),cfs[:,k]) for k=1:size(cfs,2)]
@@ -135,8 +146,8 @@ ProductFun(f::Function) = ProductFun(dynamic(f),ChebyshevInterval(),ChebyshevInt
135146

136147
## Conversion from other 2D Funs
137148

138-
ProductFun(f::LowRankFun) = ProductFun(coefficients(f),space(f,1),space(f,2))
139-
ProductFun(f::Fun{S}) where {S<:AbstractProductSpace} = ProductFun(coefficientmatrix(f),space(f))
149+
ProductFun(f::LowRankFun; kw...) = ProductFun(coefficients(f),space(f,1),space(f,2); kw...)
150+
ProductFun(f::Fun{S}; kw...) where {S<:AbstractProductSpace} = ProductFun(coefficientmatrix(f), space(f); kw...)
140151

141152
## Conversion to other ProductSpaces with the same coefficients
142153

src/PDE/KroneckerOperator.jl

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -426,21 +426,45 @@ end
426426
Base.getindex(A::KroneckerOperator, B::MultivariateFun) = A[Fun(B)]
427427
function Base.getindex(K::KroneckerOperator, f::LowRankFun)
428428
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))
429+
sum(zip(f.A, f.B)) do (A,B)
430+
op1[A] op2[B]
431+
end
437432
end
438-
for F in [:LowRankFun, :ProductFun, :MultivariateFun]
433+
Base.getindex(K::KroneckerOperator, B::ProductFun) = K[LowRankFun(B)]
434+
435+
for F in [:MultivariateFun, :ProductFun, :LowRankFun]
439436
for O in [:DerivativeWrapper, :DefiniteIntegralWrapper]
440437
@eval Base.getindex(K::$O{<:KroneckerOperator}, f::$F) = K.op[f]
441438
@eval (*)(A::$O{<:KroneckerOperator}, B::$F) = A.op * B
442-
@eval (*)(A::$F, B::$O{<:KroneckerOperator}) = Fun(A) * B.op
439+
@eval (*)(A::$F, B::$O{<:KroneckerOperator}) = A * B.op
443440
end
444-
@eval (*)(A::KroneckerOperator, B::$F) = A * Fun(B)
445-
@eval (*)(A::$F, B::KroneckerOperator) = Fun(A) * B
446441
end
442+
(*)(A::KroneckerOperator, B::MultivariateFun) = A * Fun(B)
443+
(*)(A::MultivariateFun, B::KroneckerOperator) = Fun(A) * B
444+
445+
(*)(ko::KroneckerOperator, pf::ProductFun) = ko * LowRankFun(pf)
446+
(*)(pf::ProductFun, ko::KroneckerOperator) = LowRankFun(pf) * ko
447+
448+
# if the second operator is a constant, we may scale the first operator,
449+
# and apply it on the coefficients
450+
function (*)(ko::KroneckerOperator{<:Operator, <:ConstantOperator}, pf::ProductFun)
451+
O1, O2 = ko.ops
452+
O12 = O2.λ * O1
453+
ProductFun(map(x -> O12*x, pf.coefficients), factors(pf.space)[2])
454+
end
455+
456+
function (*)(ko::KroneckerOperator, lrf::LowRankFun)
457+
O1, O2 = ko.ops
458+
sum(zip(lrf.A, lrf.B)) do (f1, f2)
459+
(O1*f1) (O2*f2)
460+
end
461+
end
462+
function (*)(lrf::LowRankFun, ko::KroneckerOperator)
463+
O1, O2 = ko.ops
464+
sum(zip(lrf.A, lrf.B)) do (f1, f2)
465+
(f1*O1) (f2*O2)
466+
end
467+
end
468+
469+
_mulop(P::Operator, ::BivariateSpace, B::ProductFun) = P * LowRankFun(B)
470+
(*)(P::PlusOperator, lrf::LowRankFun) = sum(op -> op*lrf, P.ops)

src/PDE/PDE.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,17 @@ function timedirichlet(d::Union{ProductDomain,TensorSpace})
4949
end
5050

5151

52-
53-
function *(B::Operator,f::ProductFun)
52+
# Operators on an univariate space may act on the second space of the ProductFun,
53+
# consistent with treating it as an expansion in the second space
54+
# We re-route through _mulop to distinguish between operators on UnivariateSpace and
55+
# those on BivariateSpace
56+
function _mulop(B::Operator, ::UnivariateSpace, f::ProductFun)
5457
if isafunctional(B)
5558
Fun(factor(space(f),2),map(c->Number(B*c),f.coefficients))
5659
else
5760
ProductFun(space(f),map(c->B*c,f.coefficients))
5861
end
5962
end
63+
*(B::Operator,f::ProductFun) = _mulop(B, domainspace(B), f)
6064

6165
*(f::ProductFun,B::Operator) = transpose(B*(transpose(f)))

src/Space.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -552,9 +552,9 @@ transform!(S::Space,cfs) = plan_transform!(S,cfs)*cfs
552552

553553
_coefficients!!(::Val{true}) = coefficients!
554554
_coefficients!!(::Val{false}) = coefficients
555-
_mul(P::CanonicalTransformPlan, ip, vals) = _coefficients!!(ip)(P.plan * vals, P.canonicalspace, P.space)
556-
_mul(P::ICanonicalTransformPlan, ip, cfs) = P.plan * _coefficients!!(ip)(cfs, P.space, P.canonicalspace)
557-
*(P::Union{CanonicalTransformPlan, ICanonicalTransformPlan}, vals::AbstractVector) = _mul(P, Val(inplace(P)), vals)
555+
_multransform(P::CanonicalTransformPlan, ip, vals) = _coefficients!!(ip)(P.plan * vals, P.canonicalspace, P.space)
556+
_multransform(P::ICanonicalTransformPlan, ip, cfs) = P.plan * _coefficients!!(ip)(cfs, P.space, P.canonicalspace)
557+
*(P::Union{CanonicalTransformPlan, ICanonicalTransformPlan}, vals::AbstractVector) = _multransform(P, Val(inplace(P)), vals)
558558

559559

560560
for OP in (:plan_transform,:plan_itransform,:plan_transform!,:plan_itransform!)

0 commit comments

Comments
 (0)