# Inner products & norms

## Inner products

The inner product of two functions is simply computed as

julia> B = FiniteDifferences(10, 0.1)
Finite differences basis {Float64} on 0.0..1.1 with 10 points spaced by Δx = 0.1

julia> x = axes(B,1)
Inclusion(0.0..1.1)

julia> c = B \ sin.(2π*x)
10-element Array{Float64,1}:
0.5877852522924731
0.9510565162951535
0.9510565162951536
0.5877852522924732
1.2246467991473532e-16
-0.587785252292473
-0.9510565162951535
-0.9510565162951536
-0.5877852522924734
-2.4492935982947064e-16

julia> f = B*c
QuasiArrays.ApplyQuasiArray{Float64,1,typeof(*),Tuple{FiniteDifferences{Float64,Int64},Array{Float64,1}}}(*, (Finite differences basis {Float64} on 0.0..1.1 with 10 points spaced by Δx = 0.1, [0.5877852522924731, 0.9510565162951535, 0.9510565162951536, 0.5877852522924732, 1.2246467991473532e-16, -0.587785252292473, -0.9510565162951535, -0.9510565162951536, -0.5877852522924734, -2.4492935982947064e-16]))

julia> d = B \ cos.(2π*x)
10-element Array{Float64,1}:
0.8090169943749475
0.30901699437494745
-0.30901699437494734
-0.8090169943749473
-1.0
-0.8090169943749475
-0.30901699437494756
0.30901699437494723
0.8090169943749473
1.0

julia> g = B*d
QuasiArrays.ApplyQuasiArray{Float64,1,typeof(*),Tuple{FiniteDifferences{Float64,Int64},Array{Float64,1}}}(*, (Finite differences basis {Float64} on 0.0..1.1 with 10 points spaced by Δx = 0.1, [0.8090169943749475, 0.30901699437494745, -0.30901699437494734, -0.8090169943749473, -1.0, -0.8090169943749475, -0.30901699437494756, 0.30901699437494723, 0.8090169943749473, 1.0]))

julia> f'f
0.5000000000000001

julia> f'g
-3.0044051106072847e-17

julia> g'g
0.5

## Norms

Similarly, norms are easily computed as

julia> norm(f)
0.7071067811865476

julia> norm(g)
0.7071067811865476

For orthogonal bases, other $p$-norms are also available:

julia> norm(g,1)
0.647213595499958

julia> norm(g,Inf)
1.0

## Caveats for non-orthogonal bases

Also for B-splines, the inner products and norms can be computed as above:

julia> R = BSpline(LinearKnotSet(7, 0.0, 1.0, 3))[:,2:end-1]
BSpline{Float64} basis with LinearKnotSet(Float64) of order k = 7 on 0.0..1.0 (3 intervals), restricted to basis functions 2..8 ⊂ 1..9

julia> r = axes(R,1)
Inclusion(0.0..1.0)

julia> c = R \ sin.(2π*r)
7-element Array{Float64,1}:
0.35236622516315186
1.0329925571692269
1.6856805930016943
-5.528339670985388e-16
-1.6856805930016923
-1.0329925571692293
-0.35236622516315186

julia> f = R*c
Spline on BSpline{Float64} basis with LinearKnotSet(Float64) of order
k = 7 on 0.0..1.0 (3 intervals)

julia> f'f
0.4999507480992042

julia> norm(f)
0.7070719539758342

For unrestricted bases, the metric is stored in the B-spline basis object. Beware though, when working with Restricted bases, the metric needs to be recomputed every time an inner product is computed.

julia> @benchmark f'f
BenchmarkTools.Trial:
memory estimate:  928 bytes
allocs estimate:  25
--------------
minimum time:     5.112 μs (0.00% GC)
median time:      5.536 μs (0.00% GC)
mean time:        6.227 μs (2.44% GC)
maximum time:     1.539 ms (98.89% GC)
--------------
samples:          10000
evals/sample:     6

julia> @benchmark norm(f)
BenchmarkTools.Trial:
memory estimate:  944 bytes
allocs estimate:  26
--------------
minimum time:     5.163 μs (0.00% GC)
median time:      5.605 μs (0.00% GC)
mean time:        6.209 μs (2.26% GC)
maximum time:     1.415 ms (99.13% GC)
--------------
samples:          10000
evals/sample:     6

When working with non-orthogonal basis functions, such as B-splines, it is therefore advised to explicitly compute the metric once and use that for all inner products and norms:

julia> S = R'R
7×7 BandedMatrix{Float64,Array{Float64,2},Base.OneTo{Int64}}:
0.0368555    0.0285178   0.0102464    0.00267575  0.000472084  4.3428e-5   2.70996e-8
0.0285178    0.0492836   0.0347641    0.0176553   0.00640938   0.00142346  4.3428e-5
0.0102464    0.0347641   0.0402597    0.0319871   0.0180037    0.00640938  0.000472084
0.00267575   0.0176553   0.0319871    0.0380685   0.0319871    0.0176553   0.00267575
0.000472084  0.00640938  0.0180037    0.0319871   0.0402597    0.0347641   0.0102464
4.3428e-5    0.00142346  0.00640938   0.0176553   0.0347641    0.0492836   0.0285178
2.70996e-8   4.3428e-5   0.000472084  0.00267575  0.0102464    0.0285178   0.0368555

julia> @benchmark dot(c,S,c)
BenchmarkTools.Trial:
memory estimate:  16 bytes
allocs estimate:  1
--------------
minimum time:     80.383 ns (0.00% GC)
median time:      88.495 ns (0.00% GC)
mean time:        98.239 ns (1.42% GC)
maximum time:     6.183 μs (98.38% GC)
--------------
samples:          10000
evals/sample:     944