# Chasing the power of optimal length increase

(c) 2021 Tom Röschinger. This work is licensed under a [Creative Commons Attribution License CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/). All code contained herein is licensed under an [MIT license](https://opensource.org/licenses/MIT).

***

```julia
using LinearAlgebra, Distributions, Plots, Polynomials, LinearAlgebra, Turing, Printf
# Custom package
using Jevo, Jedi

# Set plotting style
Jedi.default_gr!()
```

    ┌ Info: Precompiling Jedi [b681c197-c997-42fd-b5bb-d7d7839f617e]
    └ @ Base loading.jl:1278
    WARNING: using StatsBase.ecdf in module Jedi conflicts with an existing identifier.
    ┌ Warning: Package Jedi does not have Measures in its dependencies:
    │ - If you have Jedi checked out for development and have
    │   added Measures as a dependency but haven't updated your primary
    │   environment's manifest file, try `Pkg.resolve()`.
    │ - Otherwise you may need to report an issue with Jedi
    └ Loading Measures into Jedi from project dependency, future warnings for Jedi are suppressed.

    Plots.GRBackend()

```julia
@model function fit_exponent(x, y)
    sigma ~ truncated(Normal(0, 10^-6), 0, Inf)
    a ~ truncated(Normal(0, 1), 0, Inf)
    b ~ Normal(0, 1)
    _y = (x .* a) .+ b
     y ~ MvNormal(_y, sigma)
end
```

    fit_exponent (generic function with 1 method)

## 1. Full Gamma Dynamics

First, let's have a look at the full $\Gamma$ dynamics. Therefore, we use the Kimura substitution probability to compute a distribution. Let's write down the rates for a match turning into a mismatch, $u_+(\Gamma, l)$, and the rate for a mismatch turning into a match, $u_-(\Gamma, l)$,

\begin{align}
u_+(\Gamma) &= \left(1 - \frac{\Gamma}{\epsilon l}\right) \left[p(F(\Gamma + \epsilon, l) - F(\Gamma, l) +\frac{\kappa}{N}\right],\\
u_-(\Gamma) &= \frac{\Gamma}{\epsilon l}\frac{1}{1-n} \left[p(F(\Gamma - \epsilon, l) - F(\Gamma, l) +\frac{\kappa}{N}\right],
\end{align}

where $p(s)$ is the Kimura substitution probability. The prefactors determine the probability of a match/mismatch mutating, which depends on the current state of the population. The extra prefactor $\frac{1}{1-n}$ comes from the consideration that a mismatch can mutate to another mismatch, which is not detectable on the level of quantitative traits. A similar factor is absent from the rate turning a match into am mismatch, since every mutation on a match leads to a mismatch.

Then we use these rates to determine the probability distribution over the binding energies,

$$
Q(\Gamma, l) \propto \prod_{\Gamma^\prime=\epsilon}^\Gamma \frac{u_+(\Gamma-\epsilon, l)}{u_-(\Gamma, l)}.
$$

It might be more useful to compute the free fitness $\Psi$ instead, which is simply the log of the distribution,

$$
\Psi(\Gamma, l) \propto \sum_{\Gamma^\prime=\epsilon}^\Gamma \log\left[\frac{u_+(\Gamma-\epsilon, l)}{u_-(\Gamma, l)}\right].
$$

```julia
# Neutral Expectation
γ_0(n) = (n-1)/n

# Binding Threshold
γ_1(l, n, l_0) = γ_0(n) - l_0/l

# Binding probability
pb(γ, l, n, l_0, gap) = 1 / (1 + exp(gap * (l / l_0) * (γ - γ_1(l, n, l_0))))

# Fitness component for functional binding
F_b(γ, l, n, l_0, gap, f0) = f0 * pb(γ, l, n, l_0, gap)

# Fitness component of genomic constraint
F_c(l, l_0, fl) = - fl * l / l_0

# Total Fitness
F(γ, l, n, l_0, gap, f0, fl) = F_b(γ, l, n, l_0, gap, f0) + F_c(l, l_0, fl)

function kimura(s)
    if s^2 < 10^(-20)
        return 1
    elseif s < -10^7
        return 0
    else
        return s/(1 - exp(-s))
    end
end

# Substitution rate for trait changes
# (k, l) -> (k + 1, l)
up(γ, l, n, l_0, gap, f0, fl, κ) =  (1 - γ) * (kimura(F(γ + 1/l, l, n, l_0, gap, f0, fl)
        - F(γ, l, n, l_0, gap, f0, fl)) + κ )

# (k, l) -> (k - 1, l)
um(γ, l, n, l_0, gap, f0, fl, κ) = γ * (1 - (n-2)/(n-1)) * (kimura(F(γ - 1/l, l, n, l_0, gap, f0, fl)
        - F(γ, l, n, l_0, gap, f0, fl)) + κ )

# Free Fitness
function Ψ(l, n, l_0, gap, f0, fl, κ)
    # Start at neutral γ
    γ_i = floor(γ_0(n) * l) / l
    return collect(0:1/l:γ_i), push!(Float64[0], cumsum([log(up(γ - 1/l, l,  n, l_0, gap, f0, fl, κ) / um(γ, l,  n, l_0, gap, f0, fl, κ)) for γ in 1/l:1/l:γ_i])...)

end
```

    Ψ (generic function with 1 method)

Using the free fitness, we can also compute the resulting distribution.

```julia
# Probability distribution (from free Fitness)
function Q(l, n, l_0, gap, f0, fl, κ)
    x, y = Ψ(l, n, l_0, gap, f0, fl, κ)
    return x, exp.(y)
end

```

    Q (generic function with 1 method)

Let's make some plots. Therefore we first determine some parameters.

```julia
gap = 5
l_0 = 5
f0 = 40l_0
fl = 1l_0
n = 4;
```

First we look at the fitness landscape and the free fitness as a sanity check, to determine that we actually implemented them correctly.

```julia
x, y = Ψ(15, n, l_0, gap, f0, fl, 0)
f = [F(γ, 15, n, l_0, gap, f0, fl) for γ in x]
println(x[argmax(y)])
plot(x, (y .- minimum(y))/(maximum(y)-minimum(y)), label="Free Fitness")

plot!(x, (f .- minimum(f))/(maximum(f)-minimum(f)), color="orange", label="Fitness")
```

    0.13333333333333333

Looking good so far. Let's have a look at a couple at a distribution and how it changes with some non-equilibrium.

```julia
x1, y1 = Q(30, n, l_0, gap, f0, 0, 0)
x2, y2 = Q(30, n, l_0, gap, f0, 0, 20)
plot(x1, y1/sum(y1), title="Distributions at l=100", titlefontsize=12, label="κ = 0")
plot!(x2, y2/sum(y2), label="κ = 20")
```

We can nicely see how the distribution moves to less specificity and already gets a little mass at the neutral peak, which we have to consider later. Let's have a look at how the mean fitness looks for increasing length.

```julia
function mean_fitness(l, n, l_0, gap, f0, fl, κ)
    x, y = Q(l, n, l_0, gap, f0, fl, κ)
    y = y/sum(y)
    sum([F(γ, l, n, l_0, gap, f0, fl) for γ in x] .* y)
end

p_mf_0 = [mean_fitness(l, n, l_0, gap, f0, fl, 0) for l in 7:100]
p_mf_20 = [mean_fitness(l, n, l_0, gap, f0, fl, 20) for l in 7:100]
plot(7:100, p_mf_0, label="κ=0", title="Mean Fitness")
plot!(7:100, p_mf_20, label="κ=20")
```

As we expected, for increased non-equilibrium, it is not possible for some lengths to adapt. Now let's find the optimal length. Therefore we first compute some stuff. We start of with writing functions to compute the new intensive energy, where we have to consider the discreteness of the sequence, therefore the intensive energy changes for all types of length mutations (match/mismatch addition/removal). After computing the new intensive binding energy, we compute the selection coefficient of a length mutation at a given $\gamma$.

```julia
# (k,l) -> (k+1,l+1)
γ_pp(γ, l) = min((γ + 1/l)/(1 + 1/l), 1)

# (k,l) -> (k,l+1)
γ_pm(γ, l) = max(γ /(1 + 1/l), 0)

# (k,l) -> (k,l-1)
γ_mp(γ, l) = min(γ/(1 - 1/l), 1)

# (k,l) -> (k-1,l-1)
γ_mm(γ, l) = max((γ - 1/l)/(1 - 1/l), 0)

# selection coeffcients for length increase and decrease
# (k,l) -> (k+1,l+1)
s_pp(γ, l, n, l_0, gap, f0, fl) =
    F(γ_pp(γ, l), l + 1, n, l_0, gap, f0, fl) -
    F(γ, l, n, l_0, gap, f0, fl)

# (k,l) -> (k,l+1)
s_pm(γ, l, n, l_0, gap, f0, fl) =
    F(γ_pm(γ, l), l + 1, n, l_0, gap, f0, fl) -
    F(γ, l, n, l_0, gap, f0, fl)

# (k,l) -> (k-1,l-1)
s_mm(γ, l, n, l_0, gap, f0, fl) =
 F(γ_mm(γ, l), l - 1, n, l_0, gap, f0, fl) -
  F(γ, l, n, l_0, gap, f0, fl)

# (k,l) -> (k,l-1)
s_mp(γ, l, n, l_0, gap, f0, fl) =
 F(γ_mp(γ, l), l - 1, n, l_0, gap, f0, fl) -
  F(γ, l, n, l_0, gap, f0, fl)
```

    s_mp (generic function with 1 method)

Now that we can compute the selection coefficient, we compute the length substitution rates. For that we have to consider the difference of mutations that increase the length, where we add a random position, hence a match with probability $1/n$, and mutations where we decrease length, where the probability of removing a match depends on the intensive energy of the site, $(1-\gamma)$. The total length increase and decrease mutation rates are both averaged over the steady state distribution at that length, which comes from the assumption of separation of time scales.

```julia
function p_l_th(κ, n, l_0, gap, f0, fl, l_range=collect(40:200))
    vp = []
    vm = []
    for l in l_range
        x, y = Q(l, n, l_0, gap, f0, fl, κ)
        y = y/sum(y)
        s_mm_p = [s_pp(γ, l, n, l_0, gap, f0, fl) for γ in x]
        s_m_p = [s_pm(γ, l, n, l_0, gap, f0, fl) for γ in x]
        s_mm_m = [s_mm(γ, l, n, l_0, gap, f0, fl) for γ in x]
        s_m_m = [s_mp(γ, l, n, l_0, gap, f0, fl) for γ in x]
        v_mm_p = [(n-1)/n * kimura(s) for s in s_mm_p]
        v_m_p = [1/n * kimura(s) for s in s_m_p]
        v_mm_m = [ γ * kimura(s) for (s, γ) in zip(s_mm_m, x)]
        v_m_m = [(1 - γ)  * kimura(s) for (s, γ) in zip(s_m_m, x)]
        push!(vp, sum((v_m_p .+ v_mm_p) .* y))
        push!(vm, sum((v_mm_m .+ v_m_m) .* y))
    end
    return vp, vm, push!([0.01], (cumsum([log(vp[i]/vm[i+1]) for i in 1:length(vp)-1]).+0.01)...)
end
```

    p_l_th (generic function with 2 methods)

Now let's have a look at the length increase and decrease substitution rates and the resulting effective fitness.

```julia
vp, vm, p_l = p_l_th(0, n, l_0, gap, f0, fl, collect(7:100))
p1 = plot(7:100, vp, label="vp", legend=:topright, title="κ=0", xlabel="l")
plot!(p1, 7:100, vm, label="vm")
p2 = plot(7:100, p_l ./ maximum(p_l), label="Effective Fitness", legend=:bottomleft, title="Fitnesses (both scaled)", xlabel="l")
mf = [mean_fitness(l, n, l_0, gap, f0, fl, 0) for l in 7:100]
plot!(p2, 7:100, (mf .- mf[1]) ./ (maximum(mf)-mf[1]) , label="Mean Fitness")
plot([p1, p2]..., size=(700, 300))
```

We can nicely see how the effective fitness is shifted to higher lengths due to the asymmetry of length mutations. When we consider optimal lengths in non-equilibrium, we have to consider that for smaller lengths sites will not able to adapt at all, and therefore be non-functional. We want to exclude these non-functional sites for now. Hence we use a function to find the minimal length of functional sites.

```julia
function min_func_length(n, l_0, gap, f0, fl, κ, l_arr=collect(7:100))
    gamma_max_list = zeros(length(l_arr))
    for (i, l) in enumerate(l_arr)
        x, y = Q(l, n, l_0, gap, f0, fl, κ)
        gamma_max_list[i] = x[argmax(y)]
    end
    iterator = [[x, y] for (x, y) in zip(gamma_max_list, l_arr)]
    return findfirst( x -> x[1] < γ_1(x[2], n, l_0), iterator) + l_arr[1]-1
end

lmin_arr = [min_func_length(n, l_0, gap, f0, fl, κ) for κ in 0:20]
κ_arr = collect(0:20)

plot(
    κ_arr .+ 1,
    lmin_arr,
    xlabel="κ",
    ylabel="l_m",
    title="Minimal Functional Length",
    linewidth=2
)
```

This looks nicely linear. Now let's look at the length mutation rates and the effective fitness for high non-equilibrium.

```julia
lm = min_func_length(n, l_0, gap, f0, fl, 20, collect(7:100))
l_arr = collect(lm:100)
vp, vm, p_l = p_l_th(20, n, l_0, gap, f0, fl, l_arr)

p1 = plot(l_arr, vp, label="vp", legend=:topright, title="κ=20", xlabel="l")
plot!(p1, l_arr, vm, label="vm")
p2 = plot(l_arr, p_l ./ maximum(p_l), label="Effective Fitness", legend=:bottomleft, title="Both scaled", xlabel="l")
mf = [mean_fitness(l, n, l_0, gap, f0, fl, 20) for l in l_arr]
plot!(p2, l_arr, (mf .- mf[1]) ./ (maximum(mf)-mf[1]) , label="Mean Fitness")
plot([p1, p2]..., size=(700, 300))
```

Now we have all the tools to compute the optimal length as a function of non-equilibrium.

```julia
function optimal_length_full(n, l_0, gap, f0, fl, κ_arr=collect(0:20))

    l_opt_th = []
    for κ in κ_arr
        lm = min_func_length(n, l_0, gap, f0, fl, κ)
        l_arr = collect(lm:100)
        p_l = p_l_th(κ, n, l_0, gap, f0, fl, l_arr)[3]
        l_opt = argmax(p_l) + lm - 1
        push!(l_opt_th, l_opt)
    end
    return l_opt_th
end

function plot_opt_length_full(n, l_0, gap, f0, fl, κ_arr=collect(0:20))
    l_opt_lin = optimal_length_full(n, l_0, gap, f0, fl, κ_arr)

    p_lin = plot(
        κ_arr,
        l_opt_lin,
        xlabel="κ",
        ylabel="l_opt",
        title="f0=$(f0/l_0)l_0, fl=$(fl/l_0)l_0"
    )

    κ_arr_log = exp.(range(0, length=length(κ_arr), stop=log(κ_arr[end] + 1))) .- 1
    l_opt_log = optimal_length_full(n, l_0, gap, f0, fl, κ_arr_log)

    logx = log.(1 .+ κ_arr_log)
    logy = log.(l_opt_log)

    chn = sample(fit_exponent(logx[end-15:end], logy[end-15:end]), NUTS(0.75), 5_000)

    p_log = scatter(
        log.(κ_arr_log .+ 1),
        log.(l_opt_log),
        legend=:topleft,
        xlabel="log(1+κ)",
        ylabel="log(l_opt)"
    )

    plot!(
        p_log,
        log.(κ_arr_log .+ 1),
        log.((κ_arr_log .+ 1).^(mean(chn[:a]))) .+ mean(chn[:b]),
        linestyle=:dash,
        title=@sprintf "LogLog with slope %.3f" mean(chn[:a])
    )

    return plot([p_lin, p_log]..., size=(700, 300))
end
```

    plot_opt_length_full (generic function with 2 methods)

```julia
gap = 10
l_0 = 10
f0 = 40l_0
fl = 1l_0
n = 4;
```

```julia
plot_opt_length_full(n, l_0, gap, f0, fl, collect(0:20))
```

    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Info: Found initial step size
    │   ϵ = 7.62939453125e-7
    └ @ Turing.Inference /Users/tomroschinger/.julia/packages/Turing/O1Pn0/src/inference/hmc.jl:195
    Sampling: 100%|█████████████████████████████████████████| Time: 0:00:01

```julia
plot_opt_length_full(n, l_0, gap, 200l_0, 2l_0, collect(0:40))
```

    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Info: Found initial step size
    │   ϵ = 1.220703125e-5
    └ @ Turing.Inference /Users/tomroschinger/.julia/packages/Turing/O1Pn0/src/inference/hmc.jl:195
    Sampling: 100%|█████████████████████████████████████████| Time: 0:00:00

```julia
plot_opt_length_full(n, l_0, gap, 300l_0, 8l_0, collect(0:40))
```

    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Info: Found initial step size
    │   ϵ = 3.0517578125e-6
    └ @ Turing.Inference /Users/tomroschinger/.julia/packages/Turing/O1Pn0/src/inference/hmc.jl:195
    Sampling: 100%|█████████████████████████████████████████| Time: 0:00:00

# Only use the maximum of the energy distribution

Now we want to compare using the full distribution as we did above to simply using the maximum point of the distribution to compare. Therefore we first compute the maximum of the distribution.

```julia
function γ_star(l, n, l_0, gap, f0, fl, κ)
    x, y = Ψ(l, n, l_0, gap, f0, fl, κ)
    max_ind = argmax(y)
    if max_ind == length(x)
        return x[end]
    elseif max_ind == 1
        return x[1]
    else
        f = Polynomials.fit(x[max_ind-1:max_ind+1], y[max_ind-1:max_ind+1], 2)
        return -f[1]/2f[2]
    end
end
```

    γ_star (generic function with 1 method)

```julia
# (k,l) -> (k+1,l+1)
γ_pp(γ, l) = min((γ + 1/l)/(1 + 1/l), 1)

# (k,l) -> (k,l+1)
γ_pm(γ, l) = max(γ /(1 + 1/l), 0)

# (k,l) -> (k,l-1)
γ_mp(γ, l) = min(γ/(1 - 1/l), 1)

# (k,l) -> (k-1,l-1)
γ_mm(γ, l) = max((γ - 1/l)/(1 - 1/l), 0)

# selection coeffcients for length increase and decrease
# (k,l) -> (k+1,l+1)
s_pp(γ, l, n, l_0, gap, f0, fl) =
    F(γ_pp(γ, l), l + 1, n, l_0, gap, f0, fl) -
    F(γ, l, n, l_0, gap, f0, fl)

# (k,l) -> (k,l+1)
s_pm(γ, l, n, l_0, gap, f0, fl) =
    F(γ_pm(γ, l), l + 1, n, l_0, gap, f0, fl) -
    F(γ, l, n, l_0, gap, f0, fl)

# (k,l) -> (k-1,l-1)
s_mm(γ, l, n, l_0, gap, f0, fl) =
 F(γ_mm(γ, l), l - 1, n, l_0, gap, f0, fl) -
  F(γ, l, n, l_0, gap, f0, fl)

# (k,l) -> (k,l-1)
s_mp(γ, l, n, l_0, gap, f0, fl) =
 F(γ_mp(γ, l), l - 1, n, l_0, gap, f0, fl) -
  F(γ, l, n, l_0, gap, f0, fl)

# substitution rates of length increase and decrease
v_pp(γ, l, n, l_0, gap, f0, fl) = γ_0(n) * kimura(s_pp(γ, l, n, l_0, gap, f0, fl))

v_pm(γ, l, n, l_0, gap, f0, fl) = (1 - γ_0(n)) * kimura(s_pm(γ, l, n, l_0, gap, f0, fl))

v_plus(γ, l, n, l_0, gap, f0, fl) = v_pp(γ, l, n, l_0, gap, f0, fl) + v_pm(γ, l, n, l_0, gap, f0, fl)

v_plus_star(l, n, l_0, gap, f0, fl, κ) = v_plus(γ_star(l, n, l_0, gap, f0, fl, κ), l, n, l_0, gap, f0, fl)

v_mm(γ, l, n, l_0, gap, f0, fl) = γ * kimura(s_mm(γ, l, n, l_0, gap, f0, fl))

v_mp(γ, l, n, l_0, gap, f0, fl) = (1 - γ) * kimura(s_mp(γ, l, n, l_0, gap, f0, fl))

v_minus(γ, l, n, l_0, gap, f0, fl) = v_mm(γ, l, n, l_0, gap, f0, fl) + v_mp(γ, l, n, l_0, gap, f0, fl)

v_minus_star(l, n, l_0, gap, f0, fl, κ) = v_minus(γ_star(l, n, l_0, gap, f0, fl, κ), l, n, l_0, gap, f0, fl)

# Effective Fitness
F_eff(l, n, l_0, gap, f0, fl, κ, lmin) = sum([log(v_plus_star(l_, n, l_0, gap, f0, fl, κ)/
    v_minus_star(l_+1, n, l_0, gap, f0, fl, κ)) for l_  in lmin:l])

γ_star_list(n, l_0, gap, f0, fl, κ, l_max=200) = [l > 10 ? γ_star(l, n, l_0, gap, f0, fl, κ) : missing  for l in 1:l_max]

function l_star(n, l_0, gap, f0, fl, κ, l_max=200)
    gstarlist = γ_star_list(n, l_0, gap, f0, fl, κ, l_max)
    funct_pos_list = []
    for l in 1:l_max
        if (~ismissing(gstarlist[l])) && (gstarlist[l] < γ_1(l, n, l_0))
            push!(funct_pos_list, l)
        end
    end
    γ_fun_list = gstarlist[funct_pos_list]
    lm = funct_pos_list[1]
    f_list = zeros(l_max)

    f_list[lm+1:l_max] = cumsum([log(v_plus(gstarlist[i-1], i-1, n, l_0, gap, f0, fl)/
                v_minus(gstarlist[i], i, n, l_0, gap, f0, fl)) for i in lm+1:l_max])
    max_ind = argmax(f_list)

    fmax = f_list[max_ind]
    lst = max_ind
    return gstarlist[max_ind], γ_fun_list, f_list, fmax, lst, lm
end
```

    l_star (generic function with 2 methods)

```julia
function p_l_star(κ, n, l_0, gap, f0, fl, l_range=collect(20:250))
    vp = []
    vm = []
    for l in l_range
        γ = γ_star(l, n, l_0, gap, f0, fl, κ)
        s_mm_p = s_pp(γ, l, n, l_0, gap, f0, fl)
        s_m_p = s_pm(γ, l, n, l_0, gap, f0, fl)
        s_mm_m = s_mm(γ, l, n, l_0, gap, f0, fl)
        s_m_m = s_mp(γ, l, n, l_0, gap, f0, fl)
        v_mm_p = γ_0(n) * kimura(s_mm_p)
        v_m_p = (1 - γ_0(n)) * kimura(s_m_p)
        v_mm_m = γ * kimura(s_mm_m)
        v_m_m = (1 - γ)  * kimura(s_m_m)
        push!(vp, v_m_p + v_mm_p)
        push!(vm, v_mm_m .+ v_m_m)
    end
    return vp, vm, push!([0.01], (cumsum([log(vp[i-1]/vm[i]) for i in 2:length(vp)]).+0.01)...)
end
```

    p_l_star (generic function with 2 methods)

```julia
κ = 40
lm = min_func_length(n, l_0, gap, f0, fl, κ)
plot(lm:50, p_l_star(κ, n, l_0, gap, f0, fl, collect(lm:50))[3])
plot!(twinx(), lm:50, [F_eff(l, n, l_0, gap, f0, fl, κ, lm) for l in lm:50], color = "orange")
```

```julia
function optimal_length_star(n, l_0, gap, f0, fl, κ_arr=collect(0:20))
    l_opt_star = []
    for κ in κ_arr
        push!(l_opt_star, l_star(n, l_0, gap, f0, fl, κ)[end-1])
    end
    return l_opt_star
end

function plot_opt_length_star(n, l_0, gap, f0, fl, κ_arr=collect(0:20))
    l_opt_lin = optimal_length_star(n, l_0, gap, f0, fl, κ_arr)

    p_lin = plot(
        κ_arr,
        l_opt_lin,
        xlabel="κ",
        ylabel="l_opt",
        title="f0=$(f0/l_0)l_0, fl=$(fl/l_0)l_0"
    )

    κ_arr_log = exp.(range(0, length=length(κ_arr), stop=log(κ_arr[end] + 1))) .- 1
    l_opt_log = optimal_length_star(n, l_0, gap, f0, fl, κ_arr_log)

    logx = log.(1 .+ κ_arr_log)
    logy = log.(l_opt_log)

    chn = sample(fit_exponent(logx[end-15:end], logy[end-15:end]), NUTS(0.75), 5_000)

    p_log = scatter(
        log.(κ_arr_log .+ 1),
        log.(l_opt_log),
        legend=:topleft,
        xlabel="log(1+κ)",
        ylabel="log(l_opt)"
    )

    plot!(
        p_log,
        log.(κ_arr_log .+ 1),
        log.((κ_arr_log .+ 1).^(mean(chn[:a]))) .+ mean(chn[:b]),
        linestyle=:dash,
        title=@sprintf "LogLog with slope %.3f" mean(chn[:a])
    )

    return plot([p_lin, p_log]..., size=(900, 450))
end
```

    plot_opt_length_star (generic function with 2 methods)

```julia
plot_opt_length_star(n, l_0, gap, 40l_0, l_0, collect(0:40))
```

    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Info: Found initial step size
    │   ϵ = 1.9073486328125e-7
    └ @ Turing.Inference /Users/tomroschinger/.julia/packages/Turing/O1Pn0/src/inference/hmc.jl:195
    Sampling: 100%|█████████████████████████████████████████| Time: 0:00:01

```julia
plot_opt_length_star(n, l_0, gap, 200l_0, 2fl, collect(0:40))
```

    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Info: Found initial step size
    │   ϵ = 7.62939453125e-7
    └ @ Turing.Inference /Users/tomroschinger/.julia/packages/Turing/O1Pn0/src/inference/hmc.jl:195
    Sampling: 100%|█████████████████████████████████████████| Time: 0:00:01

```julia
plot_opt_length_star(n, l_0, gap, 300l_0, 3fl, collect(0:40))
```

    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Info: Found initial step size
    │   ϵ = 3.0517578125e-6
    └ @ Turing.Inference /Users/tomroschinger/.julia/packages/Turing/O1Pn0/src/inference/hmc.jl:195
    Sampling: 100%|█████████████████████████████████████████| Time: 0:00:00

## Gamma Star

```julia
κ_arr = collect(0:20)
κ_log = exp.(range(0, length=length(κ_arr), stop=log(κ_arr[end] + 1))) .- 1

p_lin = plot(
    κ_arr,
    [l_star(n, l_0, gap, f0, fl, κ)[1] for κ in κ_arr],
    xlabel="κ",
    ylabel="γ_star"
)
p_log = plot(
    log.(1 .+ κ_log),
    [log(l_star(n, l_0, gap, f0, fl, κ)[1]) for κ in κ_log],
    xlabel="log(1+κ)",
    ylabel="log(sstar)"
)

plot([p_lin, p_log]..., size=(700, 300))
```

## S_Star

```julia
sstar(l, n, l_0, gap, f0, fl, κ) = F(γ_star(l, n, l_0, gap, f0, fl, κ) - 1/l, l, n, l_0, gap, f0, fl) - F(γ_star(l, n, l_0, gap, f0, fl, κ), l, n, l_0, gap, f0, fl)

```

    sstar (generic function with 1 method)

```julia
function plot_sstar(n, l_0, gap, f0, fl, κ_arr=collect(0:30); return_plot=true)

    l_opt = optimal_length_star(n, l_0, gap, f0, fl, κ_arr)
    star = [sstar(l, n, l_0, gap, f0, fl, κ) for (l, κ) in zip(l_opt, κ_arr)]

    κ_log = exp.(range(0, length=length(κ_arr), stop=log(κ_arr[end] + 1))) .- 1
    star_log = [sstar(l, n, l_0, gap, f0, fl, κ) for (l, κ) in zip(l_opt, κ_log)]

    logx = log.(1 .+ κ_log)
    logy = log.(star_log)

    chn = sample(fit_exponent(logx[2:end], logy[2:end]),NUTS(0.65), 3_000)
    if return_plot
        p_lin = plot(
            κ_arr,
            star,
            xlabel="κ",
            ylabel="s_star",
            title="f0=$(f0/l_0)l_0, fl=$(fl/l_0)l_0"
        )
        p_log = plot(log.(1 .+ κ_log), log.(star_log))
        plot!(
            p_log,
            log.(1 .+ κ_log),
            log.((1 .+ κ_log) .^(mean(chn[:a]))) .+ mean(chn[:b]),
            linestyle=:dash,
            xlabel="log(1+κ)",
            ylabel="log(s_star)",
            title=@sprintf "LogLog with slope %.3f" mean(chn[:a])

        )

        return plot([p_lin, p_log]..., size=(900, 450))
    else
        return chn
    end
end
```

    plot_sstar (generic function with 3 methods)

```julia
s = []
for (f0, fl) in zip([40, 100, 200, 300], [1, 1.5, 2, 3])
    push!(s, mean(plot_sstar(n, l_0, gap, f0*l_0, fl*l_0, return_plot=false)[:a]))
end
println(s)
```

    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Info: Found initial step size
    │   ϵ = 1.52587890625e-6
    └ @ Turing.Inference /Users/tomroschinger/.julia/packages/Turing/O1Pn0/src/inference/hmc.jl:195
    Sampling: 100%|█████████████████████████████████████████| Time: 0:00:00
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Info: Found initial step size
    │   ϵ = 7.62939453125e-7
    └ @ Turing.Inference /Users/tomroschinger/.julia/packages/Turing/O1Pn0/src/inference/hmc.jl:195
    Sampling: 100%|█████████████████████████████████████████| Time: 0:00:00
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Info: Found initial step size
    │   ϵ = 7.62939453125e-7
    └ @ Turing.Inference /Users/tomroschinger/.julia/packages/Turing/O1Pn0/src/inference/hmc.jl:195
    Sampling: 100%|█████████████████████████████████████████| Time: 0:00:00
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Info: Found initial step size
    │   ϵ = 3.814697265625e-7
    └ @ Turing.Inference /Users/tomroschinger/.julia/packages/Turing/O1Pn0/src/inference/hmc.jl:195
    Sampling: 100%|█████████████████████████████████████████| Time: 0:00:00

    Any[0.9216546731289336, 0.909668423963915, 0.8974901504931337, 0.8909789233628159]

```julia
plot_sstar(n, l_0, gap, 200l_0, 2l_0)
```

    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Info: Found initial step size
    │   ϵ = 1.52587890625e-6
    └ @ Turing.Inference /Users/tomroschinger/.julia/packages/Turing/O1Pn0/src/inference/hmc.jl:195
    Sampling: 100%|█████████████████████████████████████████| Time: 0:00:00

```julia
plot_sstar(n, l_0, gap, 300l_0, 3l_0)
```

    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Warning: The current proposal will be rejected due to numerical error(s).
    │   isfinite.((θ, r, ℓπ, ℓκ)) = (true, false, false, false)
    └ @ AdvancedHMC /Users/tomroschinger/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:47
    ┌ Info: Found initial step size
    │   ϵ = 1.52587890625e-6
    └ @ Turing.Inference /Users/tomroschinger/.julia/packages/Turing/O1Pn0/src/inference/hmc.jl:195
    Sampling: 100%|█████████████████████████████████████████| Time: 0:00:00

```julia

```


# FFM232, Klassisk fysik och vektorfält - Föreläsningsanteckningar

 **[Christian Forssén](http://fy.chalmers.se/subatom/tsp/), Institutionen för fysik, Chalmers, Göteborg, Sverige**

Date: **Sep 9, 2016**

# 5. Indexnotation

Precis som vi har räkneregler för derivatorer, så kan vi härleda räkneregler för våra differentialoperatorer. Det är då viktigt att komma ihåg att fälten på de båda sidorna av likhetstecknet skall vara av samma typ, det vill säga om vi har ett skalärt fält till vänster om likhetstecknet skall vi ha ett skalärt fält till höger om likhetstecknet, och om vi har ett vektorfält till vänster om likhetstecknet skall också fältet till höger vara ett vektorfält.  På så sätt kan man resonera sig fram till några av räknereglerna.

## Gradient, divergens och rotation av en produkt av fält

För vanliga funktioner $f$ och $g$ gäller att

$$
\begin{equation}
  \frac{\mbox{d}}{\mbox{d}x}\left(fg\right) = \frac{\mbox{d}f}{\mbox{d}x}g
+ f\frac{\mbox{d}g}{\mbox{d}x}.
\end{equation}
$$

Om vi istället betraktar $\nabla (fg)$, där $f$ och $g$ är skalära fält, ser vi att det resulterande fältet skall vara ett vektorfält, och att vi måste derivera ett av fälten åt gången. Om vi tar gradienten av ett skalärt fält, så får vi ett vektorfält och om vi sedan multiplicerar med ytterligare ett skalärt fält, så har vi fortfarande ett vektorfält, alltså bör räknereglen

$$
\begin{equation}
  \nabla \left(fg\right) = f \nabla g + g\nabla f
\end{equation}
$$

gälla. På liknande sätt kan vi resonera oss fram till

$$
\begin{equation}
  \nabla \cdot \left(f\vec{u}\right) = \nabla f \cdot \vec{u} + f \nabla \cdot \vec{u},
\end{equation}
$$

och

$$
\begin{equation}
  \nabla \times \left(f\vec{u}\right) = \nabla f\times \vec{u} + f \nabla \times \vec{u}.
\end{equation}
$$

Mer komplexa samband är dock svårare att härleda. Detta gäller även kombinationer av flera vektoroperatorer. I princip kan man visa dem genom att skriva ut ekvationerna komponentvis, men en effektivare metod är att använda indexnotation. Indexnotationen är ett effektivt verktyg i stora delar av den teoretiska fysiken.

## Indexnotation

Vektorn $\vec{A}$ är densamma i alla koordinatsystem, Cartesiska såväl som kroklinjiga. I någon given bas kan dess komponenter skrivas ut: $\vec{A}=\sum_{i=1}^3A_i\vec{e}_i$.

Så när vi talar om vektorn $\vec{A}$ skall vi skriva $A_i$ vilket vi kan tolka som en lista över komponenterna, alltså $\{A_i\}_{i=1}^3$. Indexet $i$ kallas ett *fritt index*, eftersom det kan ta värdena $i=1,2,3$

### Produkter av vektorer

Skalärprodukten av två vektorer $\vec{A}$ och $\vec{B}$ är $\vec{A}\cdot\vec{B}=\sum_{i=1}^3A_iB_i$. För att göra notationen mer kompakt inför vi nu *Einsteins summationskonvention*, som säger att summation är underförstådd så snart ett index förekommer två gånger. Med dessa skrivregler har vi då

$$
\begin{equation}
\vec{A}\cdot\vec{B}=A_iB_i
\end{equation}
$$

[Comment 1: Att vi skriver lägre index har ingen betydelse, om man vill kan man t.ex. skriva $A_iB^i$. Först när man sysslar med vektorer/tensorer i icke-Cartesiska system behöver man göra åtskillnad på index uppe och nere. Detta gäller t.ex. i speciell relativitetsteori.]

Det här uttrycket för skalärprodukten gäller i godtyckligt antal dimensioner. Resultatet av skalärprodukten är förstås en skalär. Indexen $i$ ovan är *inte* fria index, utan summationsindex, eller kontraherade index.

### Exempel: matris-vektor-multiplikation

En matris representeras av sina matriselement (precis som enhetsmatrisen ovan). Det första indexet är rad- och det andra kolumnindex. Matris-vektor-multiplikationen $\mathbf{M} \vec{v}$ kan skrivas med indexnotation

$$
\begin{equation}
\left[ \mathbf{M} \vec{v} \right]_i = M_{ij} v_j
\end{equation}
$$

### Enhetsmatrisen

Vi har redan sett Kroneckers delta, $\delta_{ij}$, som definieras av

$$
\begin{equation}
\delta_{ij}=\left\{
\begin{matrix}
1,&i=j\cr
0,&i\neq j\cr
\end{matrix}
\right.
\end{equation}
$$

(notera att detta helt enkelt är matriselementen av enhetsmatrisen).

Betrakta uttrycket $\delta_{ij}A_j$. Här är indexet $j$ repeterat och därför ett summationsindex, och uttrycket skall utläsas $\sum_{j=1}^3\delta_{ij}A_j=A_i$, dvs. helt enkelt multiplikation av vektorn $\vec{A}$ med enhetsmatrisen.

### Exempel: matris-matris-multiplikation

Matrismultiplikation $\mathbf{M}\mathbf{N}=\mathbf{P}$ skrivs som $M_{ik}N_{kj}=P_{ij}$. Spåret av en matris, dvs. summan av diagonalelementen är $\mathrm{tr}\mathbf{M}=M_{ii}$.

### Kryssprodukt

Låt $\vec{A}\times\vec{B}=\vec{C}$. Komponentvis gäller $C_1=A_2B_3-A_3B_2$, och de andra komponenterna ges av cykliska permutationer av indexen. Vi inför nu objektet $\varepsilon_{ijk}$, som definieras av

$$
\begin{equation}
\varepsilon_{ijk}=\left\{
\begin{matrix}
\phantom{-}1,\quad\hfill&ijk\hbox{ jämn permutation av 123,}\hfill\cr
-1,\quad\hfill&ijk\hbox{ udda permutation av 123,}\hfill\cr
\phantom{-}0,\hfill&\hbox{annars, dvs. om minst två index tar samma
värde.}
\end{matrix}
\right.
\end{equation}
$$

$\varepsilon_{ijk}$ kallas "$\varepsilon$-tensorn", eller *Levi-Civita-tensorn*.

[Comment 2: Vi har inte riktigt definierat vad en tensor är ännu. Det kommer senare, och är inte speciellt dramatiskt. För tillfället kan vi bara tänka på det som ett objekt som har ett antal index, alltså en naturlig generalisering av vektor- och matrisbegreppen.]

Definitionen gör att $\varepsilon_{ijk}$ har egenskapen att den byter tecken om man byter plats på två index, vilka som helst. Man säger att den är fullständigt antisymmetrisk.

Eftersom $\varepsilon_{ijk}$ har tre index, kan vi kontrahera två av dem med index på vektorer, och alltså bilda $C_i=\varepsilon_{ijk}A_jB_k$. Med hjälp av definitionen kan vi räkna ut t.ex. $C_1$, och får resultatet $C_1=A_2B_3-A_3B_2$, dvs. samma som första komponenten av $\vec{A}\times\vec{B}$. Detsamma gäller de andra komponenterna. Kryssprodukten skrivs alltså

$$
\begin{equation}
[\vec{A}\times\vec{B}]_i=\varepsilon_{ijk}A_jB_k .
\end{equation}
$$

Kryssprodukten är specifik för tre dimensioner, just för att $\varepsilon$-tensorn har tre index i tre dimensioner. Motsvarande objekt i $D$ dimensioner har $D$ index: $\varepsilon_{i_1i_2\ldots i_D}$.

## Produkter av flera vektorer

Låt oss studera följande vektorprodukt

$$
\begin{equation}
  \vec{A} \times \left( \vec{B} \times \vec{C} \right)
\end{equation}
$$

vilket med indexnotation kan skrivas

$$
\begin{equation}
  \label{eq:ABC} \tag{1}
  \left[ \vec{A} \times \left( \vec{B} \times \vec{C} \right) \right]_i =
  \varepsilon_{ijk} A_j \varepsilon_{klm} B_l C_m = \varepsilon_{ijk} \varepsilon_{klm} A_j B_l C_m.
\end{equation}
$$

Låt oss först poängtera att vi kan byta plats på faktorerna som vi gjorde ovan. Eftersom dessa är reella tal gäller t.ex. att $A_j B_l = B_l A_j$ och motsvarande för $\varepsilon$-tensorerna.

Här dyker en produkt av två Levi-Cevita-tensorer upp. Låt oss se om sådana produkter kan förenklas

### Produkter av två $\varepsilon_{ijk}$

Först produkten med enbart två fria index

$$
\begin{equation}
  \varepsilon_{ikl} \varepsilon_{jkl} = 2 \delta_{ij}.
\end{equation}
$$

Detta inses ganska enkelt eftersom
* Produkten måste bli noll då $i \neq j$. T.ex. $i=1$ innebär att $kl$ måste vara 23 eller 32, och då måste även $j=1$ för att den andra tensorn skall vara nollskild.

* Med $i=j$ måste summan över $kl$ bli 2. Studera t.ex. $i=j=1$; de nollskilda termerna i summan blir $ikl=jkl \in [123,132]$, dvs

$$
\begin{equation}
	\sum_{k,l=1}^3 \varepsilon_{1kl} \varepsilon_{1kl} = \varepsilon_{123} \varepsilon_{123} + \varepsilon_{132} \varepsilon_{132} = 1 \cdot 1 + (-1) \cdot (-1) = 2
\end{equation}
$$

------------
Nu produkten med enbart ett kontraherat index

$$
\begin{equation}
  \label{eq:ijkklm} \tag{2}
  \varepsilon_{ijk} \varepsilon_{klm} = \left\{ \mathrm{Cyklisk~perm.} \right\} = \varepsilon_{ijk} \varepsilon_{lmk} = \delta_{il} \delta_{jm} - \delta_{im} \delta_{jl}.
\end{equation}
$$

Det inses lätt att $i \neq j$ och $l \neq m$. Vidare inses att paret $ij$ måste vara lika med $lm$ eller $ml$. Betrakta t.ex. $i,j \in [1,2]$. Då kommer enbart $k=3$ termen från summan att bidra och vi har följande möjligheter

$$
\begin{equation}
  \begin{array}{lll}
  	ijk & lmk & \mathrm{Resultat} \\
  	123 & 123 & = 1 \\
  	123 & 213 & = -1 \\
  	213 & 123 & = -1 \\
  	213 & 213 & = 1,
  \end{array}
\end{equation}
$$

vilket motsvarar exakt kombinationen av deltafunktioner i Ekv [(2)](#eq:ijkklm) ovan.
------------
Detta var precis den produkt som dök upp i Ekv [(1)](#eq:ABC) ovan. Vi fortsätter

$$
\begin{equation}
  \left[ \vec{A} \times \left( \vec{B} \times \vec{C} \right) \right]_i
  = \left( \delta_{il} \delta_{jm} - \delta_{im} \delta_{jl} \right) A_j B_l C_m \nonumber
\end{equation}
$$

$$
\begin{equation}
  = B_i A_m C_m - A_j B_j C_i = B_i \vec{A}\cdot\vec{C} - \vec{A}\cdot\vec{B} C_i
\end{equation}
$$

Här har vi bytt plats på $A_m B_i = B_i A_m$. Notera vidare att vi lika gärna kunde ha bytt t.ex. $m \to j$ i den första termen. Dessa blir ändå ett summationsindex och det spelar ingen roll om det heter $m$ eller $j$.

Till slut finner vi alltså likheten

$$
\begin{equation}
  \label{eq:ABCresultat} \tag{3}
  \vec{A} \times \left( \vec{B} \times \vec{C} \right) = \vec{B} (\vec{A}\cdot\vec{C}) - (\vec{A}\cdot\vec{B}) \vec{C}.
\end{equation}
$$

## Kombinationer med två vektoroperatorer

En viktig konsekvens av Ekv [(3)](#eq:ABCresultat) är

$$
\begin{equation}
  \nabla \times \left( \nabla \times \vec{F} \right) = \nabla \left( \nabla \cdot \vec{F} \right) - \nabla \cdot \nabla \vec{F},
\end{equation}
$$

vilket ger oss följande uttryck för Laplacianen

$$
\begin{equation}
  \Delta \vec{F} = \nabla \cdot \nabla \vec{F} = \nabla \left( \nabla \cdot \vec{F} \right) - \nabla \times \left( \nabla \times \vec{F} \right),
\end{equation}
$$

eller Laplace = grad div - rot rot.

Två viktiga samband, vilka dessutom är enkla att härleda, är

$$
\begin{equation}
\label{eq:ddf} \tag{4}
  \nabla \times \nabla f = 0
\end{equation}
$$

och

$$
\begin{equation}
\label{eq:ddf2} \tag{5}
  \nabla \cdot \left( \nabla \times \vec{F}\right) = 0.
\end{equation}
$$

Visa gärna dessa

### Bevis, Ekv [(4)](#eq:ddf)

$$
\begin{equation}
  \left[ \nabla \times \nabla f \right]_i = \varepsilon_{ijk} \partial_j \partial_k f
\end{equation}
$$

Till exempel för $i=1$

$$
\begin{equation}
  \begin{array}{llll}
  	ijk & \partial_j & \partial_k & \mathrm{faktor} \\
  	123 & 2 & 3 & +1 \\
  	132 & 3 & 2 & -1 \\
  \end{array}
\end{equation}
$$

vilket betyder att $\left[ \nabla \times \nabla f \right]_1 = \left( \partial_2\partial_3 - \partial_3\partial_2 \right) f = 0$.

### Bevis, Ekv [(5)](#eq:ddf2)

$$
\begin{equation}
  \left[ \nabla \cdot \left( \nabla \times \vec{F} \right) \right] = \partial_i \varepsilon_{ijk} \partial_j F_k = \varepsilon_{ijk} \partial_i \partial_j F_k
\end{equation}
$$

* En viktig poäng är att de sista två faktorerna *inte* får byta plats eftersom $\partial_j F_k \neq F_k \partial_j$.

* Däremot har vi att $\partial_i \partial_j F_k = \partial_j \partial_i F_k$, vilket betyder att dessa två faktorer kan byta plats.

Summan ovan har 27 termer, men enbart sex nollskilda

$ijk$	             term

   123      	    $\partial_1 \partial_2 F_3$

   231      	    $\partial_2 \partial_3 F_1$

   312      	    $\partial_3 \partial_1 F_2$

   132      	    $-\partial_1 \partial_3 F_2$

   213      	    $-\partial_2 \partial_1 F_3$

   321      	    $-\partial_3 \partial_2 F_1$

och eftersom dessa tar ut varandra parvis blir summan noll.