Approximating operators

As mentioned in Solving equations, the action of a linear operator on a spline can be approximated by projecting the operator into the space $\space{P}_{t,k}$: $\mat{L}\defd B^H\operator{L}B$. We can employ this for different kinds of operators; out-of-the-box, CompactBases.jl supports differential operators and diagonal operators:

Differential operators

In the ContinuumArrays framework, differential operators are represented by the Derivative operator, which operates in a domain (typically the first axis of an ContinuumArrays.QuasiArrays.AbstractQuasiMatrix, e.g. a ContinuumArrays.Basis such as BSpline):

julia> using CompactBases

julia> B = BSpline(LinearKnotSet(3, 0, 1, 3))
BSpline{Float64} basis with LinearKnotSet(Float64) of order k = 3 (parabolic) on 0.0..1.0 (3 intervals)

julia> D = Derivative(axes(B,1))
Derivative{Float64,IntervalSets.Interval{:closed,:closed,Float64}}(ContinuumArrays.QuasiArrays.Inclusion{Float64,IntervalSets.Interval{:closed,:closed,Float64}}(0.0..1.0))

The derivative operator can then be projected into the space generated by the knot set t by

julia> ∇ = B'D*B
5×5 BandedMatrix{Float64,Array{Float64,2},Base.OneTo{Int64}}:
 -0.5         0.416667      0.0833333      ⋅            ⋅
 -0.416667    2.07997e-17   0.375         0.0416667     ⋅
 -0.0833333  -0.375         7.84759e-17   0.375        0.0833333
   ⋅         -0.0416667    -0.375        -1.31839e-16  0.416667
   ⋅           ⋅           -0.0833333    -0.416667     0.5

Diagonal operators

Diagonal operators are operators that only depend on the coordinate; they are also called local operators. Typical examples are potentials, such as the Coulomb potential $V(x) = Q/x$, generated by a charge $Q$. This potential is not polynomial, i.e. we cannot compute its matrix elements exactly using Gauß–Legendre quadrature, but with high enough order and intelligent placement of the knots, we can get sufficient accuracy.

Diagonal operators are projected into the B-spline space using a QuasiDiagonal.

As as example of the importance of knot placement, we study the action of the Coulomb operator $\operator{V}(x) = -1/x$ on the function $f(x)=x^2\exp(-x)$; we know that the result should be $g(x)=\operator{V}(x)f(x)=-x\exp(-x)$:

julia> k = 7
7

julia> N = 31
31

julia> a,b = 0,70
(0, 70)

julia> coulomb(r) = -1/r
coulomb (generic function with 1 method)

julia> tlin = LinearKnotSet(k, a, b, N);

julia> texp = ExpKnotSet(k, -1.0, log10(b), N);

julia> Blin = BSpline(tlin,3)[:,2:end-1]
BSpline{Float64} basis with LinearKnotSet(Float64) of order k = 7 on 0.0..70.0 (31 intervals), restricted to basis functions 2..36 ⊂ 1..37

julia> Bexp = BSpline(texp,3)[:,2:end-1]
BSpline{Float64} basis with ExpKnotSet(Float64) of  on order k = 7 on 0,0.1..70.00000000000001 (31 intervals), restricted to basis functions 2..36 ⊂ 1..37

Then, for B=Blin and B=Bexp, we do the following:

x = axes(B, 1)
S = B'B
f = B \ (x.^2 .* exp.(-x))
V = B'*QuasiDiagonal(coulomb.(x))*B
g̃ = S \ V*f

and obtain two different approximations to $g(x)$, as shown in the following plot:

Coulomb operator