|
| 1 | +export Convolution |
| 2 | + |
| 3 | +""" |
| 4 | + Convolution(G) |
| 5 | +
|
| 6 | +Represents a convolution operator with function `G`. When applied to a function `f` it computes `∫_D G(x-y) f(y) dy for x ∈ D`. For now `D` is a `PeriodigSegment(a,b)` with `a<b∈R` and `space(G)` is either `Laurent(D)` or `Fourier(D)`. |
| 7 | +""" |
| 8 | + |
| 9 | +abstract type Convolution{S,T} <: Operator{T} end |
| 10 | + |
| 11 | +struct ConcreteConvolution{S<:Space,T} <: Convolution{S,T} |
| 12 | + G::Fun{S,T} |
| 13 | +end |
| 14 | + |
| 15 | +function Convolution(G::Fun{S,T}) where {S,T} |
| 16 | + @assert isfinite(arclength(domain(G))) |
| 17 | + ConcreteConvolution(G) |
| 18 | +end |
| 19 | +ApproxFunBase.domain(C::ConcreteConvolution) = ApproxFunBase.domain(C.G) |
| 20 | +ApproxFunBase.domainspace(C::ConcreteConvolution) = ApproxFunBase.space(C.G) |
| 21 | +ApproxFunBase.rangespace(C::ConcreteConvolution) = ApproxFunBase.space(C.G) |
| 22 | +ApproxFunBase.bandwidths(C::ConcreteConvolution) = error("Please implement convolution bandwidths on "*string(space(C.G))) |
| 23 | +getindex(C::ConcreteConvolution,k::Integer,j::Integer) = error("Please implement convolution getindex on "*string(space(C.G))) |
| 24 | + |
| 25 | +ApproxFunBase.bandwidths(C::ConcreteConvolution{Laurent{PeriodicSegment{R},T}}) where {R<:Real,T} = 0,0 |
| 26 | +ApproxFunBase.bandwidths(C::ConcreteConvolution{Fourier{PeriodicSegment{R},T}}) where {R<:Real,T} = 1,1 |
| 27 | + |
| 28 | +function getindex(C::ConcreteConvolution{Laurent{PeriodicSegment{R},T1},T2},k::Integer,j::Integer) where {R<:Real,T1,T2} |
| 29 | + fourier_index::Integer = if isodd(k) div(k-1,2) else -div(k,2) end |
| 30 | + if k == j && k ≤ ncoefficients(C.G) |
| 31 | + return (exp(-2pi*1im/arclength(domain(C.G))*fourier_index*first(domain(C.G)))*arclength(domain(C.G))*C.G.coefficients[k])::T2 |
| 32 | + else |
| 33 | + return zero(T2) |
| 34 | + end |
| 35 | +end |
| 36 | + |
| 37 | +function getindex(C::ConcreteConvolution{Fourier{PeriodicSegment{R},T1},T2},k::Integer,j::Integer) where {R<:Real,T1,T2} |
| 38 | + fourier_index::Integer = if isodd(k) div(k-1,2) else div(k,2) end |
| 39 | + if k<1 || j<1 || ncoefficients(C.G)==0 |
| 40 | + return zero(T2) |
| 41 | + elseif k == 1 |
| 42 | + if j==k |
| 43 | + return (arclength(domain(C.G))*C.G.coefficients[1])::T2 |
| 44 | + else |
| 45 | + return zero(T2) |
| 46 | + end |
| 47 | + elseif 2*fourier_index ≤ ncoefficients(C.G) |
| 48 | + Gs = if 2*fourier_index ≤ ncoefficients(C.G) C.G.coefficients[2*fourier_index] else zero(T2) end # sine coefficient |
| 49 | + Gc = if 2*fourier_index+1 ≤ ncoefficients(C.G) C.G.coefficients[2*fourier_index+1] else zero(T2) end # cosine coefficient |
| 50 | + phase = 2pi/arclength(domain(C.G))*fourier_index*first(domain(C.G)) |
| 51 | + if iseven(k) && j==k |
| 52 | + return (arclength(domain(C.G))*(Gc*cos(phase)-Gs*sin(phase))/2)::T2 |
| 53 | + elseif iseven(k) && j==k+1 |
| 54 | + return (arclength(domain(C.G))*(Gc*sin(phase)+Gs*cos(phase))/2)::T2 |
| 55 | + elseif isodd(k) && j==k |
| 56 | + return (arclength(domain(C.G))*(Gc*cos(phase)-Gs*sin(phase))/2)::T2 |
| 57 | + elseif isodd(k) && j==k-1 |
| 58 | + return (arclength(domain(C.G))*(-Gc*sin(phase)-Gs*cos(phase))/2)::T2 |
| 59 | + else |
| 60 | + return zero(T2) |
| 61 | + end |
| 62 | + else |
| 63 | + return zero(T2) |
| 64 | + end |
| 65 | +end |
| 66 | + |
0 commit comments