text:
####
#### Trajectory
####

@auto_hash_equals struct Trajectory{SS<:AbsVec,OO<:AbsVec,AA<:AbsVec,RR<:AbsVec,ST,OT}
    S::SS
    O::OO
    A::AA
    R::RR
    sT::ST
    oT::OT
    done::Bool
    @inline function Trajectory{SS,OO,AA,RR,ST,OT}(
        S::SS,
        O::OO,
        A::AA,
        R::RR,
        sT::ST,
        oT::OT,
        done::Bool,
    ) where {SS<:AbsVec,OO<:AbsVec,AA<:AbsVec,RR<:AbsVec,ST,OT}
        τ = new(S, O, A, R, sT, oT, done)
        checkrep(τ)
        return τ
    end
end

@inline function Trajectory(
    S::SS,
    O::OO,
    A::AA,
    R::RR,
    sT::ST,
    oT::OT,
    done,
) where {SS,OO,AA,RR,ST,OT}
    Trajectory{SS,OO,AA,RR,ST,OT}(S, O, A, R, sT, oT, done)
end

@inline function checkrep(τ::Trajectory)
    if !(length(τ.S) == length(τ.O) == length(τ.A) == length(τ.R))
        throw(DimensionMismatch("Lengths of S, O, A, and R don't match"))
    end
    return τ
end

Base.length(τ::Trajectory) = (checkrep(τ); length(τ.S))

####
#### TrajectoryBuffer
####

const VoA = AbstractVector{<:AbstractArray}
@auto_hash_equals struct TrajectoryBuffer{SS<:VoA,OO<:VoA,AA<:VoA,RR<:AbstractVector{<:Real}}
    S::SS
    O::OO
    A::AA
    R::RR
    sT::SS
    oT::OO
    done::Vector{Bool}
    offsets::Vector{Int}
    function TrajectoryBuffer(
        S::SS,
        O::OO,
        A::AA,
        R::RR,
        sT::SS,
        oT::OO,
        done::Vector{Bool},
        offsets::Vector{Int},
    ) where {SS<:VoA,OO<:VoA,AA<:VoA,RR<:AbstractVector{<:Real}}
        Base.require_one_based_indexing(S, O, A, R, sT, oT)
        B = new{SS,OO,AA,RR}(S, O, A, R, sT, oT, done, offsets)
        checkrep(B)
        return B
    end
end

function TrajectoryBuffer(
    env::AbstractEnvironment;
    dtype::Maybe{DataType} = nothing,
    sizehint::Integer = 1024,
)
    sizehint > 0 || argerror("sizehint must be > 0")
    sp = dtype === nothing ? spaces(env) : adapt(dtype, spaces(env))
    sizehint_traj = max(1, div(sizehint, 10)) # a heuristic
    TrajectoryBuffer(
        asvec(ElasticArray(undef, sp.statespace, sizehint)),
        asvec(ElasticArray(undef, sp.observationspace, sizehint)),
        asvec(ElasticArray(undef, sp.actionspace, sizehint)),
        Array(undef, sp.rewardspace, sizehint),
        asvec(ElasticArray(undef, sp.statespace, sizehint_traj)),
        asvec(ElasticArray(undef, sp.observationspace, sizehint_traj)),
        Vector{Bool}(undef, sizehint_traj),
        Int[0],
    )
end

asvec(A::AbstractArray{<:Any,L}) where {L} = SpecialArrays.slice(A, Val(L-1))

@noinline function checkrep(B::TrajectoryBuffer)
    if !(length(B.S) == length(B.O) == length(B.A) == length(B.R))
        throw(DimensionMismatch("Lengths of S, O, A, and R do not match"))
    end
    if !(length(B.sT) == length(B.oT) == length(B.done)) # TODO compare against offsets
        throw(DimensionMismatch("Lengths of sT, oT, and done do not match"))
    end
    length(B.S) < nsamples(B) && error("invalid dimensions")
    if !(B.offsets[1] == 0 && all(i -> B.offsets[i-1] < B.offsets[i], 2:ntrajectories(B)))
        throw(DimensionMismatch("Invalid offsets"))
    end
    ntrajectories(B) < 0 && throw(DomainError("length must be > 0"))
    return B
end

ntrajectories(B::TrajectoryBuffer) = length(B.offsets) - 1

nsamples(B::TrajectoryBuffer) = B.offsets[ntrajectories(B)+1]
@inline function nsamples(B::TrajectoryBuffer, i::Integer)
    @boundscheck checkbounds(Base.OneTo(ntrajectories(B)), i)
    B.offsets[i+1] - B.offsets[i]
end

Base.empty!(B::TrajectoryBuffer) = resize!(B.offsets, 1)

function truncate!(B::TrajectoryBuffer)
    nsamp = nsamples(B)
    ntraj = ntrajectories(B)
    resize!(B.S, nsamp)
    resize!(B.O, nsamp)
    resize!(B.A, nsamp)
    resize!(B.R, nsamp)
    resize!(B.sT, ntraj)
    resize!(B.oT, ntraj)
    resize!(B.done, ntraj)
    resize!(B.offsets, ntraj + 1)
    checkrep(B)
    return B
end

"""
    $(SIGNATURES)

Rollout the actions computed by `policy!` on `env`, starting at whatever state `env` is currently
in, for `Hmax` timesteps or until `isdone(st, ot, env)` returns `true` and store the resultant
trajectory in `B`. `policy!` should be a function of the form `policy!(at, ot)` which computes an
action given the current observation `ot` and stores it in `at`.

See also: [`TrajectoryBuffer`](@ref), [`rollout`](@ref), [`sample`](@ref), [`sample!`](@ref)
"""
function rollout!(policy!, B::TrajectoryBuffer, env::AbstractEnvironment, Hmax::Integer)
    _rollout!(policy!, B, env, convert(Int, Hmax))
    truncate!(B)
    return B
end

function rollout(policy!, env::AbstractEnvironment, Hmax::Integer)
    rollout!(policy!, TrajectoryBuffer(env, sizehint = Hmax), env, Hmax)
end

function _rollout!(
    @specialize(policy!),
    B::TrajectoryBuffer,
    env::AbstractEnvironment,
    Hmax::Int,
    stopcb = () -> false,
)
    Hmax > 0 || argerror("Hmax must be > 0")

    @unpack S, O, A, R = B

    # pre-allocate for one additional trajectory with a length of Hmax + 1.
    # "+1" because of the terminal state/observation
    _preallocate_traj!(B, Hmax + 1)
    offset = B.offsets[end]

    t::Int = 1
    done::Bool = false

    # get the initial state/observation
    st = S[offset+t]
    ot = O[offset+t]
    getstate!(st, env)
    getobservation!(ot, env)

    while true
        # Abandon the current rollout. Used internally for multithreaded sampling.
        stopcb() && return 0

        at = A[offset+t]
        getaction!(at, env) # Fill at with env's current action for convenience
        policy!(at, ot)
        R[offset+t] = getreward(st, at, ot, env)

        setaction!(env, at)
        step!(env)
        t += 1

        # Get the next state, which may be a terminal state.
        st = S[offset+t]
        ot = O[offset+t]
        getstate!(st, env)
        getobservation!(ot, env)

        done = isdone(st, ot, env)

        # Break *after* we've hit Hmax or isdone returns true. If isdone never returns true,
        # then this loop will run for Hmax + 1 iterations.
        (t > Hmax || done) && break
    end

    push!(B.offsets, B.offsets[end] + t - 1)
    B.sT[ntrajectories(B)] = S[offset+t]
    B.oT[ntrajectories(B)] = O[offset+t]
    B.done[ntrajectories(B)] = done

    return t - 1
end

function _preallocate_traj!(B::TrajectoryBuffer, H::Int)
    nsamp = nsamples(B) + H
    ntraj = ntrajectories(B) + 1
    if length(B.S) < nsamp
        l = nextpow(2, nsamp)
        resize!(B.S, l)
        resize!(B.O, l)
        resize!(B.A, l)
        resize!(B.R, l)
    end
    if length(B.offsets) < ntraj + 2
        l = nextpow(2, ntraj + 2)
        resize!(B.sT, l)
        resize!(B.oT, l)
        resize!(B.done, l)
    end
    checkrep(B)
    return B
end

function collate!(dest::TrajectoryBuffer, Bs::AbstractVector{<:TrajectoryBuffer}, n::Integer)
    n >= 0 || argerror("n must be ≥ 0")
    ns = isempty(Bs) ? 0 : sum(nsamples, Bs)
    n <= ns || argerror("n is greater than the number of available samples")

    @unpack S, O, A, R, sT, oT, done, offsets = dest

    if isempty(Bs) || ns == 0
        resize!(S, 0)
        resize!(O, 0)
        resize!(A, 0)
        resize!(R, 0)
        resize!(sT, 0)
        resize!(oT, 0)
        resize!(done, 0)
        resize!(offsets, 1)
        return dest
    end

    ntraj = s = 0
    for B in Bs, i in eachindex(B.offsets)[1:end-1]
        s += B.offsets[i+1] - B.offsets[i]
        ntraj += 1
        s >= n && break
    end

    resize!(S, n)
    resize!(O, n)
    resize!(A, n)
    resize!(R, n)
    resize!(sT, ntraj)
    resize!(oT, ntraj)
    resize!(done, ntraj)
    resize!(offsets, ntraj + 1)

    togo = n
    doffs_samp = doffs_traj = 1
    for B in Bs
        soffs_samp = 1
        for soffs_traj = eachindex(B.offsets)[1:end-1]
            len = B.offsets[soffs_traj+1] - B.offsets[soffs_traj]
            if togo < len
                copyto!(S, doffs_samp, B.S, soffs_samp, togo)
                copyto!(O, doffs_samp, B.O, soffs_samp, togo)
                copyto!(A, doffs_samp, B.A, soffs_samp, togo)
                copyto!(R, doffs_samp, B.R, soffs_samp, togo)
                sT[doffs_traj] = B.S[soffs_samp + togo]
                oT[doffs_traj] = B.O[soffs_samp + togo]
                done[doffs_traj] = false
                offsets[doffs_traj+1] = offsets[doffs_traj] + togo
                togo = 0
            else
                copyto!(S, doffs_samp, B.S, soffs_samp, len)
                copyto!(O, doffs_samp, B.O, soffs_samp, len)
                copyto!(A, doffs_samp, B.A, soffs_samp, len)
                copyto!(R, doffs_samp, B.R, soffs_samp, len)
                sT[doffs_traj] = B.sT[soffs_traj]
                oT[doffs_traj] = B.oT[soffs_traj]
                done[doffs_traj] = B.done[soffs_traj]
                offsets[doffs_traj+1] = offsets[doffs_traj] + len

                soffs_samp += len
                doffs_samp += len
                doffs_traj += 1
                togo -= len
            end

            if togo == 0
                checkrep(dest)
                return dest
            end
        end
    end

    # This shouldn't be reached
    internalerror()
end

function StructArrays.StructArray(B::TrajectoryBuffer)
    S = BatchedVector(B.S, B.offsets)
    O = BatchedVector(B.O, B.offsets)
    A = BatchedVector(B.A, B.offsets)
    R = BatchedVector(B.R, B.offsets)
    sT = B.sT
    oT = B.oT
    done = B.done
    T = Trajectory{eltype(S),eltype(O),eltype(A),eltype(R),eltype(sT),eltype(oT)}
    return StructArray{T}((S, O, A, R, sT, oT, done))
end


text:
if get(ARGS, 1, "Array") == "CuArray"
    using CUDA
    using CUDAKernels
    ArrayType = CUDA.CuArray
    CUDA.allowscalar(false)
    get_device() = CUDADevice()
else
    ArrayType = Array
    get_device() = CPU()
end

@show ArrayType

# Re-include test_helper so we can run
# this file on its own.
include("test_helper.jl")

using KernelAbstractions

# only grab array problems
filter!(x->x.x_init isa AbstractArray, problem_list)

@kernel function solve_kernel!(
    f,
    f′,
    MethodType,
    x_init, x_lower, x_upper,
    tol,
    dst::AbstractArray{FT, N},
) where {FT, N}
    i = @index(Group, Linear)
    @inbounds begin
        # Construct the method and solve the system.
        # Store the solution in `dst`
        method = get_method(MethodType, x_init[i], x_lower[i], x_upper[i], f′)
        sol = find_zero(f, method, CompactSolution(), tol)
        dst[i] = sol.root
    end
end

@testset "CPU/GPU kernel test" begin
    n_elem = problem_size()
    device = get_device()
    work_groups = (1,)
    ndrange = (n_elem,)

    for prob in problem_list
        FT = typeof(prob.x̃)
        x_init = prob.x_init
        x_lower = prob.x_lower
        x_upper = prob.x_upper
        for MethodType in (
                    SecantMethodType(),
                    RegulaFalsiMethodType(),
                    NewtonsMethodADType(),
                    NewtonsMethodType(),
                )
            for tol in get_tolerances(FT)
                a_dst = Array{FT}(undef, n_elem)
                d_dst = ArrayType(a_dst)
                kernel! = solve_kernel!(device, work_groups)
                event = kernel!(
                    prob.f,
                    prob.f′,
                    MethodType,
                    x_init,
                    x_lower,
                    x_upper,
                    tol,
                    d_dst;
                    ndrange = ndrange
                )
                wait(device, event)

                @test all(d_dst .≈ prob.x̃)
            end
        end
    end
end

ext: jl


text:
### A Pluto.jl notebook ###
# v0.15.1

using Markdown
using InteractiveUtils

# ╔═╡ 1fbdb6c6-4bf4-11eb-3aeb-9548bde2b1a5
begin
	using DataFrames
	using Empirikos
	using Plots
	using PGFPlotsX
	using LaTeXStrings
	using MosekTools
	using JuMP
	using Setfield
	using Random
end

# ╔═╡ 3cf2bafa-4bf4-11eb-3482-ff09ca17af71
md"""
# Identifying genes associated with prostate cancer

## Load packages and dataset
"""

# ╔═╡ 473d8a28-4bf4-11eb-0151-8b3f3d286eda
begin
	pgfplotsx()
	empty!(PGFPlotsX.CUSTOM_PREAMBLE)
	push!(PGFPlotsX.CUSTOM_PREAMBLE, raw"\usepackage{amssymb}")
	push!(PGFPlotsX.CUSTOM_PREAMBLE, raw"\newcommand{\PP}[2][]{\mathbb{P}_{#1}\left[#2\right]}")
	push!(PGFPlotsX.CUSTOM_PREAMBLE, raw"\newcommand{\EE}[2][]{\mathbb{E}_{#1}\left[#2\right]}")
end;

# ╔═╡ 17be2c0c-4bf5-11eb-25ca-cfe4e5fb5485
theme(:default;
      background_color_legend = :transparent,
      foreground_color_legend = :transparent,
      grid=nothing,
      frame=:box,
      legendfonthalign = :left,
      thickness_scaling=1.3)

# ╔═╡ acfc4fc0-4bf4-11eb-32dc-dfe1652ac006
Zs = Prostate.ebayes_samples();

# ╔═╡ f4bd73b8-4bf4-11eb-3678-655227b0895b
md"""
## Marginal distribution of z-scores

### DKW-F-Localization
"""

# ╔═╡ 0731218a-4bf5-11eb-10f4-81241477b265
dkw_floc = DvoretzkyKieferWolfowitz(0.05)

# ╔═╡ 0d36dbee-4bf5-11eb-3036-7bcf68579a46
fitted_dkw = fit(dkw_floc, Zs)

# ╔═╡ 246264dc-4bf5-11eb-2f9d-b5c7d137a9b3
dkw_plot = plot(fitted_dkw, label="DKW band",
     xlab=L"z", ylab=L"\widehat{F}_n(z)",  size=(380,280))

# ╔═╡ 4dd1f99a-4bf5-11eb-3691-9db09ab324df
# savefig(dkw_plot, "prostate_dkw_band.tikz")

# ╔═╡ 362effcc-4bf5-11eb-1d84-3133de3f4825
md"### KDE-F-Localization"

# ╔═╡ 5ad6b662-4bf5-11eb-24fb-d141933957ca
infty_floc = Empirikos.InfinityNormDensityBand(;a_min=-3.0,a_max=3.0,α=0.05)

# ╔═╡ 605a545e-4bf5-11eb-3020-6d9c53e39a8e
fitted_infty_floc = fit(infty_floc, Zs)

# ╔═╡ 69e87366-4bf5-11eb-3fbb-8f7bf325d366
prostate_kde_plot = begin
	prostate_marginal_plot = histogram([response(Z) for Z in Zs],
		  bins=50, normalize=true,
          label="Histogram", fillalpha=0.4, linealpha=0.4, fillcolor=:lightgray,
          size=(380,280), xlims=(-4.5,4.5))
	plot!(prostate_marginal_plot, fitted_infty_floc,
       	  label="KDE band", xlims=(-4.5,4.5),
          yguide=L"\widehat{f}_n(z)", xguide=L"z")
	plot!(prostate_marginal_plot, [-3.0;3.0], seriestype=:vline,
		  linestyle=:dot, label=nothing, color=:lightgrey)
end

# ╔═╡ 750e2af0-4bf6-11eb-3374-1f224647d4e5
# savefig("prostate_kde_band.tikz")

# ╔═╡ aa99cc74-4bf6-11eb-2e3f-81de213db00d
 md"## Confidence intervals"

# ╔═╡ df1513be-4bf6-11eb-1b1c-fd650fd994fe
quiet_mosek = optimizer_with_attributes(Mosek.Optimizer, "QUIET" => true)

# ╔═╡ c4bc3468-4bf4-11eb-1710-f7638d026b91
gcal_locmix = MixturePriorClass(Normal.(-3:0.05:3, 0.25))

# ╔═╡ bd7a5362-4bf4-11eb-1f2c-79ff3e915f89
gcal_scalemix = Empirikos.set_defaults(GaussianScaleMixtureClass(), Zs; hints = Dict(:grid_scaling => 1.1))

# ╔═╡ 9b6b8f8a-4bf6-11eb-002d-7fa04ddde0d3
discr = interval_discretizer(-3.0:0.005:3.0)

# ╔═╡ 68f0af78-8165-11eb-2a88-efd9f9743eec
discr.sorted_intervals[1]

# ╔═╡ ce945cca-4bf6-11eb-29bc-4b2514ae395d
floc_method_dkw_locmix = FLocalizationInterval(flocalization = dkw_floc,
                               convexclass = gcal_locmix, solver = quiet_mosek)

# ╔═╡ e9e81b9c-4bf6-11eb-1c3c-d56076f6858b
floc_method_kde_locmix = FLocalizationInterval(flocalization = infty_floc,
                               convexclass = gcal_locmix, solver = quiet_mosek)

# ╔═╡ 04c72ec6-4bf7-11eb-3265-5f69502b9f0b

amari_kde_locmix = Empirikos.AMARI(
						convexclass = gcal_locmix,
						flocalization = (@set infty_floc.α=0.01),
                        discretizer=discr,
                        solver=quiet_mosek, )

# ╔═╡ 31bd322c-4bf7-11eb-007c-d7583730cd8e
floc_method_dkw_scalemix = FLocalizationInterval(flocalization = dkw_floc,
                               convexclass = gcal_scalemix, solver = quiet_mosek)

# ╔═╡ 3d5b459c-4bf7-11eb-3825-6b75cc4099f3
floc_method_kde_scalemix = FLocalizationInterval(flocalization = infty_floc,
                               convexclass = gcal_scalemix, solver = quiet_mosek)

# ╔═╡ 474bdc10-4bf7-11eb-0099-cdf3150001a2
amari_kde_scalemix = Empirikos.AMARI(
						convexclass = gcal_scalemix,
						flocalization = (@set infty_floc.α=0.01),
                        discretizer=discr,
                        solver=quiet_mosek, )

# ╔═╡ 5fe96288-4bf7-11eb-1805-1f7f7815e035
ts= -3:0.2:3

# ╔═╡ 65d3b2de-4bf7-11eb-3ab5-a13a5b5556ef
postmean_targets = Empirikos.PosteriorMean.(StandardNormalSample.(ts))

# ╔═╡ 6ade8f74-4bf7-11eb-2b46-51436f6bf297
lfsrs = Empirikos.PosteriorProbability.(StandardNormalSample.(ts),
										Interval(0,nothing))

# ╔═╡ 7c0fd708-4bf7-11eb-12e0-45ecc7f9af7a
postmean_ci_dkw_locmix = confint.(floc_method_dkw_locmix, postmean_targets, Zs)

# ╔═╡ 85c63cc4-4bf7-11eb-2688-2b63ea65b2e7
postmean_ci_kde_locmix = confint.(floc_method_kde_locmix, postmean_targets, Zs)

# ╔═╡ 89a047c2-4bf7-11eb-3c79-15fe2fcdcb1c
postmean_ci_amari_locmix = confint.(amari_kde_locmix, postmean_targets, Zs)

# ╔═╡ a262fe94-4bf7-11eb-1153-6f76128cbcd0
postmean_locmix_plot = begin
	postmean_locmix_plot = plot(ts, postmean_ci_kde_locmix, label="Gauss-F-Loc",
		fillcolor=:darkorange, fillalpha=0.5, ylim=(-2.55,2.55),
        xguide = L"z", yguide=L"\EE{\mu \mid Z=z}",
        size=(380,280))
	plot!(postmean_locmix_plot, ts, postmean_ci_dkw_locmix, label="DKW-F-Loc",
		show_ribbon=false, alpha=0.9, color=:black)
	plot!(postmean_locmix_plot, ts, postmean_ci_amari_locmix, label="AMARI",
		show_ribbon=true, fillcolor=:blue, fillalpha=0.4)
	plot!(postmean_locmix_plot, [-3.0;3.0], [-3.0; 3.0], seriestype=:line,
		linestyle=:dot, label=nothing, color=:lightgrey)
end

# ╔═╡ 622669fa-4bf8-11eb-08fd-a3bd67230729
# savefig(postmean_locmix_plot, "prostate_locmix_postmean.tikz")

# ╔═╡ 6930b1ae-4bf8-11eb-23c7-e5be40b7a283
postmean_ci_dkw_scalemix = confint.(floc_method_dkw_scalemix, postmean_targets, Zs)

# ╔═╡ 6fba4f94-4bf8-11eb-2177-87f38a9b73d2
postmean_ci_kde_scalemix = confint.(floc_method_kde_scalemix, postmean_targets, Zs)

# ╔═╡ 7c308bb4-4bf8-11eb-249a-0f6d933a530c
postmean_ci_amari_scalemix = confint.(amari_kde_scalemix, postmean_targets, Zs)

# ╔═╡ 8abdac16-4bf8-11eb-3b0d-a73d7b28bb7c
postmean_scalemix_plot = begin
	postmean_scalemix_plot = plot(ts, postmean_ci_kde_scalemix,
		label="Gauss-F-Loc", fillcolor=:darkorange, fillalpha=0.5, ylim=(-2.55,2.55),
        xguide = L"z",
		yguide=L"\EE{\mu \mid Z=z}",
        size=(380,280))
	plot!(postmean_scalemix_plot, ts, postmean_ci_dkw_scalemix,
		label="DKW-F-Loc",show_ribbon=false, alpha=0.9, color=:black)
	plot!(postmean_scalemix_plot, ts, postmean_ci_amari_scalemix,
		label="AMARI",show_ribbon=true, fillcolor=:blue, fillalpha=0.4)
	plot!(postmean_scalemix_plot, [-3.0;3.0], [-3.0; 3.0], seriestype=:line,
		linestyle=:dot, label=nothing, color=:lightgrey)
end

# ╔═╡ eb851e8a-4bf8-11eb-353a-e5c394ae5294
# savefig(postmean_scalemix_plot, "prostate_scalemix_postmean.tikz")

# ╔═╡ 1e0db04c-4bf9-11eb-1bde-9dfa4f81f279
lfsr_ci_dkw_locmix = confint.(floc_method_dkw_locmix, lfsrs, Zs)

# ╔═╡ 2700eeda-4bf9-11eb-27ba-c5c6fe33980d
lfsr_ci_kde_locmix = confint.(floc_method_kde_locmix, lfsrs, Zs)

# ╔═╡ 2eba35aa-4bf9-11eb-1bf0-0be32d4bff85
lfsr_ci_amari_locmix = confint.(amari_kde_locmix, lfsrs, Zs)

# ╔═╡ a30dce02-4bfa-11eb-1197-5b69f20af457
lfsr_locmix_plot = begin
	lfsr_locmix_plot = plot([-3;3], [0.5; 0.5], seriestype=:line,
		linestyle=:dot, label=nothing, color=:lightgrey,
        xguide = L"z",
		yguide=L"\PP{\mu \geq 0 \mid Z=z}", size=(380,280))
	plot!(lfsr_locmix_plot, ts, lfsr_ci_kde_locmix,
		label="Gauss-F-Loc", fillcolor=:darkorange, fillalpha=0.5, ylim=(0,1))
	plot!(lfsr_locmix_plot, ts, lfsr_ci_dkw_locmix,
		label="DKW-F-Loc",show_ribbon=false, alpha=0.9, color=:black)
	plot!(lfsr_locmix_plot, ts, lfsr_ci_amari_locmix,
		label="AMARI",show_ribbon=true, fillcolor=:blue, fillalpha=0.4)
end

# ╔═╡ 716b8220-4bf9-11eb-1a28-33dbf08e138c
# savefig(lfsr_locmix_plot, "prostate_locmix_lfsr.tikz")

# ╔═╡ 9afa4b4a-4bf9-11eb-2a16-531b86e6b9a9
lfsr_ci_dkw_scalemix = confint.(floc_method_dkw_scalemix, lfsrs, Zs)

# ╔═╡ 9e06f2b8-4bf9-11eb-1bad-b5a1d26339ee
lfsr_ci_kde_scalemix = confint.(floc_method_kde_scalemix, lfsrs, Zs)

# ╔═╡ a1ba1e12-4bf9-11eb-00c9-496602f4eb5c
lfsr_ci_amari_scalemix = confint.(amari_kde_scalemix, lfsrs, Zs)

# ╔═╡ f2414706-4bfa-11eb-1654-9bdcc7418db8
lfsr_scalemix_plot = begin
	lfsr_scalemix_plot = plot([-3;3], [0.5; 0.5], seriestype=:line,
		linestyle=:dot, label=nothing, color=:lightgrey,
        xguide = L"z",
		yguide=L"\PP{\mu \geq 0 \mid Z=z}", size=(380,280))
	plot!(lfsr_scalemix_plot, ts, lfsr_ci_kde_scalemix,
		label="Gauss-F-Loc", fillcolor=:darkorange, fillalpha=0.5, ylim=(0,1))
	plot!(lfsr_scalemix_plot, ts, lfsr_ci_dkw_scalemix,
		label="DKW-F-Loc",show_ribbon=false, alpha=0.9, color=:black)
	plot!(lfsr_scalemix_plot, ts, lfsr_ci_amari_scalemix,
		label="AMARI",show_ribbon=true, fillcolor=:blue, fillalpha=0.4)
end

# ╔═╡ f7a59c42-4bfa-11eb-27df-cf611213fefc
# savefig(lfsr_scalemix_plot, "prostate_scalemix_lfsr.tikz")

# ╔═╡ 3e986c36-79a1-4ffd-9d2b-4bc96f2a5fa8
md"## Sensitivity Analysis and goodness-of-fit"

# ╔═╡ c6758a61-c32f-4ec7-8336-085f6dadb96d
Random.seed!(1)

# ╔═╡ 3950ca34-f8eb-4450-985f-fdb47a1b6f8b
n_half = ceil(Int64, nobs(Zs)/2)

# ╔═╡ e61af6d2-e4df-4c9a-bb2e-40e8e706f36d
train_idx = sample(1:nobs(Zs), n_half, replace=false);

# ╔═╡ 8a936d80-c61f-4d22-a1f1-c891d0063ee2
test_idx = setdiff(1:nobs(Zs), train_idx);

# ╔═╡ d0c37eca-4c5e-42ba-970a-4d1fe27d33ea
Zs_train = Zs[train_idx]

# ╔═╡ 5ef18ef6-0d4a-4846-a1ec-8dfcc4168588
Zs_test = Zs[test_idx]

# ╔═╡ 506eb209-b761-48a2-8a31-0fe8c98a9802
τs = [0.02; 0.1; 0.25; 0.5; 0.55]

# ╔═╡ 80f5d5de-0d75-4a6e-8143-8e3f3b48af43
gcal_np = DiscretePriorClass(-4:0.005:4)

# ╔═╡ fb6464e6-3a4d-4609-9b96-37edc2a6021f
npmle_fit = fit(NPMLE(convexclass=gcal_np, solver=Mosek.Optimizer), Zs_train)

# ╔═╡ c09e057e-24b2-4486-a497-e4908dcf2881
res_list  = Vector{Any}(undef, 5);

# ╔═╡ c5ae00f4-c078-4ece-9ebf-90ea8e5b724a
postmean_target = Empirikos.PosteriorMean(StandardNormalSample(2.0))

# ╔═╡ 6501119c-338c-4931-a09e-38b5b3f8a81d
lfsr_target = Empirikos.PosteriorProbability(StandardNormalSample(2.0),
                          Interval(0,nothing))

# ╔═╡ a1b52f7a-4a53-485f-b246-fe008322c6a4
for (i, τ) in enumerate(τs)

    gcal_loc = MixturePriorClass(Normal.(-3:0.002:3, τ))

    npmle_loc_fit = fit(NPMLE(convexclass=gcal_loc, solver=Mosek.Optimizer),
						Zs_test)

    e_value = exp(loglikelihood(Zs_test, npmle_fit.prior) -
		          loglikelihood(Zs_test, npmle_loc_fit.prior))

    floc_tmp = FLocalizationInterval(flocalization = fitted_infty_floc,
                convexclass = gcal_loc;
                solver = quiet_mosek)

    local floc_fit_lfsr
    local ci_lfsr
    local floc_fit_postmean
    local ci_postmean
    try
        floc_fit_lfsr = fit(floc_tmp, lfsr_target, Zs)
        ci_lfsr = confint(floc_fit_lfsr)

        floc_fit_postmean = fit(floc_tmp, postmean_target, Zs)
        ci_postmean = confint(floc_fit_postmean)
    catch
        floc_fit_lfsr = "error"
        ci_lfsr = "error"
        floc_fit_postmean = "error"
        ci_postmean = "error"
    end
    res_list[i] = (floc_fit_lfsr = floc_fit_lfsr, ci_lfsr = ci_lfsr,
                   floc_fit_postmean = floc_fit_postmean, ci_postmean = ci_postmean,
                   e_value=e_value)
end

# ╔═╡ 24b4a3d6-2e7d-4f84-bf84-6fe97b24e93a
DataFrame(τ = τs,
	      SLR = getproperty.(res_list, :e_value),
          Lfsr_CI = getproperty.(res_list, :ci_lfsr),
		  Postmean_CI = getproperty.(res_list, :ci_postmean))

# ╔═╡ 4c812df1-fc00-4f42-a50c-4d08ca5b576b
us = -3:0.01:3

# ╔═╡ 8925c810-b292-4dc6-ba4d-3e040d8b8689
_plots = [plot(us,
   [pdf.(res_list[j].floc_fit_lfsr.g1, us) pdf.(res_list[j].floc_fit_lfsr.g2, us)],
   title=L"\tau = %$(τs[j])", color = [:darkblue :purple],
   linealpha = [0.6 0.8], xguide=L"\mu", yguide=L"g(\mu)")
   for j in 1:4];

# ╔═╡ fdb0fc1a-2b8b-4d6c-b848-47d145308875
worst_case_plots = plot(_plots..., layout=(1,4),size=(900,200), legend=false)

# ╔═╡ 40d68d1a-f93f-45e6-8f0e-3c25af40c411
# savefig(worst_case_plots, "worst_case_priors.tikz")

# ╔═╡ 7fe7a76b-fe38-4019-b068-d471123d1c9a
postmean_ci_kde_locmix[findfirst(ts.==2.0)] #sanity check 1

# ╔═╡ 81fd9a91-35dc-48dc-bb79-f01ea110d952
lfsr_ci_kde_locmix[findfirst(ts.==2.0)] #sanity check 2

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Empirikos = "cab608d6-c565-4ea1-96d6-ce5441ba21b0"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
MosekTools = "1ec41992-ff65-5c91-ac43-2df89e9693a4"
PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46"

[compat]
DataFrames = "~1.2.2"
Empirikos = "~0.4.4"
JuMP = "~0.21.9"
LaTeXStrings = "~1.2.1"
MosekTools = "~0.9.4"
PGFPlotsX = "~1.3.2"
Plots = "~1.21.2"
Setfield = "~0.7.1"
"""

# ╔═╡ 00000000-0000-0000-0000-000000000002
PLUTO_MANIFEST_TOML_CONTENTS = """
# This file is machine-generated - editing it directly is not advised

[[AbstractFFTs]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "485ee0867925449198280d4af84bdb46a2a404d0"
uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c"
version = "1.0.1"

[[Adapt]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "3.3.1"

[[ArgCheck]]
git-tree-sha1 = "dedbbb2ddb876f899585c4ec4433265e3017215a"
uuid = "dce04be8-c92d-5529-be00-80e4d2c0e197"
version = "2.1.0"

[[ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"

[[ArrayInterface]]
deps = ["IfElse", "LinearAlgebra", "Requires", "SparseArrays", "Static"]
git-tree-sha1 = "85d03b60274807181bae7549bb22b2204b6e5a0e"
uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
version = "3.1.30"

[[Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"

[[AxisAlgorithms]]
deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"]
git-tree-sha1 = "a4d07a1c313392a77042855df46c5f534076fab9"
uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950"
version = "1.0.0"

[[Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[[BenchmarkTools]]
deps = ["JSON", "Logging", "Printf", "Statistics", "UUIDs"]
git-tree-sha1 = "42ac5e523869a84eac9669eaceed9e4aa0e1587b"
uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
version = "1.1.4"

[[Bzip2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c3598e525718abcc440f69cc6d5f60dda0a1b61e"
uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
version = "1.0.6+5"

[[CSV]]
deps = ["Dates", "Mmap", "Parsers", "PooledArrays", "SentinelArrays", "Tables", "Unicode"]
git-tree-sha1 = "b83aa3f513be680454437a0eee21001607e5d983"
uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
version = "0.8.5"

[[Cairo_jll]]
deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "e2f47f6d8337369411569fd45ae5753ca10394c6"
uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
version = "1.16.0+6"

[[Calculus]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad"
uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9"
version = "0.5.1"

[[ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "bdc0937269321858ab2a4f288486cb258b9a0af7"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "1.3.0"

[[CodecBzip2]]
deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"]
git-tree-sha1 = "2e62a725210ce3c3c2e1a3080190e7ca491f18d7"
uuid = "523fee87-0ab8-5b00-afb7-3ecf72e48cfd"
version = "0.7.2"

[[CodecZlib]]
deps = ["TranscodingStreams", "Zlib_jll"]
git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da"
uuid = "944b1d66-785c-5afd-91f1-9de20f533193"
version = "0.7.0"

[[ColorSchemes]]
deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"]
git-tree-sha1 = "9995eb3977fbf67b86d0a0a0508e83017ded03f2"
uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
version = "3.14.0"

[[ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.0"

[[Colors]]
deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40"
uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
version = "0.12.8"

[[CommonSubexpressions]]
deps = ["MacroTools", "Test"]
git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7"
uuid = "bbf7d656-a473-5ed7-a52c-81e309532950"
version = "0.3.0"

[[Compat]]
deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"]
git-tree-sha1 = "727e463cfebd0c7b999bbf3e9e7e16f254b94193"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.34.0"

[[CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"

[[ConstructionBase]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "f74e9d5388b8620b4cee35d4c5a618dd4dc547f4"
uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
version = "1.3.0"

[[Contour]]
deps = ["StaticArrays"]
git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7"
uuid = "d38c429a-6771-53c6-b99e-75d170b6e991"
version = "0.5.7"

[[Crayons]]
git-tree-sha1 = "3f71217b538d7aaee0b69ab47d9b7724ca8afa0d"
uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
version = "4.0.4"

[[DataAPI]]
git-tree-sha1 = "ee400abb2298bd13bfc3df1c412ed228061a2385"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.7.0"

[[DataFrames]]
deps = ["Compat", "DataAPI", "Future", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrettyTables", "Printf", "REPL", "Reexport", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"]
git-tree-sha1 = "d785f42445b63fc86caa08bb9a9351008be9b765"
uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
version = "1.2.2"

[[DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
git-tree-sha1 = "7d9d316f04214f7efdbb6398d545446e246eff02"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
version = "0.18.10"

[[DataValueInterfaces]]
git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
version = "1.0.0"

[[Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"

[[DefaultApplication]]
deps = ["InteractiveUtils"]
git-tree-sha1 = "fc2b7122761b22c87fec8bf2ea4dc4563d9f8c24"
uuid = "3f0dd361-4fe0-5fc6-8523-80b14ec94d85"
version = "1.0.0"

[[DelimitedFiles]]
deps = ["Mmap"]
uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"

[[DiffResults]]
deps = ["StaticArrays"]
git-tree-sha1 = "c18e98cba888c6c25d1c3b048e4b3380ca956805"
uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5"
version = "1.0.3"

[[DiffRules]]
deps = ["NaNMath", "Random", "SpecialFunctions"]
git-tree-sha1 = "3ed8fa7178a10d1cd0f1ca524f249ba6937490c0"
uuid = "b552c78f-8df3-52c6-915a-8e097449b14b"
version = "1.3.0"

[[Distributed]]
deps = ["Random", "Serialization", "Sockets"]
uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"

[[Distributions]]
deps = ["ChainRulesCore", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns"]
git-tree-sha1 = "c2dbc7e0495c3f956e4615b78d03c7aa10091d0c"
uuid = "31c24e10-a181-5473-b8eb-7969acd0382f"
version = "0.25.15"

[[DocStringExtensions]]
deps = ["LibGit2"]
git-tree-sha1 = "a32185f5428d3986f47c2ab78b1f216d5e6cc96f"
uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
version = "0.8.5"

[[Downloads]]
deps = ["ArgTools", "LibCURL", "NetworkOptions"]
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"

[[EarCut_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "92d8f9f208637e8d2d28c664051a00569c01493d"
uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5"
version = "2.1.5+1"

[[Empirikos]]
deps = ["CSV", "DataStructures", "Distributions", "Intervals", "JuMP", "KernelDensity", "LinearAlgebra", "LinearFractional", "MathOptInterface", "Optim", "ParameterJuMP", "QuadGK", "Random", "RecipesBase", "Reexport", "Setfield", "Statistics", "StatsBase", "UnPack"]
git-tree-sha1 = "6f38a107e365b57d2a8f7561dd6b8aca46a5f421"
uuid = "cab608d6-c565-4ea1-96d6-ce5441ba21b0"
version = "0.4.4"

[[Expat_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f"
uuid = "2e619515-83b5-522b-bb60-26c02a35a201"
version = "2.2.10+0"

[[ExprTools]]
git-tree-sha1 = "b7e3d17636b348f005f11040025ae8c6f645fe92"
uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
version = "0.1.6"

[[FFMPEG]]
deps = ["FFMPEG_jll"]
git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8"
uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
version = "0.4.1"

[[FFMPEG_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "LibVPX_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"]
git-tree-sha1 = "3cc57ad0a213808473eafef4845a74766242e05f"
uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5"
version = "4.3.1+4"

[[FFTW]]
deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"]
git-tree-sha1 = "f985af3b9f4e278b1d24434cbb546d6092fca661"
uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
version = "1.4.3"

[[FFTW_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "3676abafff7e4ff07bbd2c42b3d8201f31653dcc"
uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a"
version = "3.3.9+8"

[[FillArrays]]
deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"]
git-tree-sha1 = "7c365bdef6380b29cfc5caaf99688cd7489f9b87"
uuid = "1a297f60-69ca-5386-bcde-b61e274b549b"
version = "0.12.2"

[[FiniteDiff]]
deps = ["ArrayInterface", "LinearAlgebra", "Requires", "SparseArrays", "StaticArrays"]
git-tree-sha1 = "8b3c09b56acaf3c0e581c66638b85c8650ee9dca"
uuid = "6a86dc24-6348-571c-b903-95158fe2bd41"
version = "2.8.1"

[[FixedPointNumbers]]
deps = ["Statistics"]
git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
version = "0.8.4"

[[Fontconfig_jll]]
deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "35895cf184ceaab11fd778b4590144034a167a2f"
uuid = "a3f928ae-7b40-5064-980b-68af3947d34b"
version = "2.13.1+14"

[[Formatting]]
deps = ["Printf"]
git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8"
uuid = "59287772-0a20-5a39-b81b-1366585eb4c0"
version = "0.4.2"

[[ForwardDiff]]
deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "NaNMath", "Printf", "Random", "SpecialFunctions", "StaticArrays"]
git-tree-sha1 = "b5e930ac60b613ef3406da6d4f42c35d8dc51419"
uuid = "f6369f11-7733-5829-9624-2563aa707210"
version = "0.10.19"

[[FreeType2_jll]]
deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "cbd58c9deb1d304f5a245a0b7eb841a2560cfec6"
uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7"
version = "2.10.1+5"

[[FriBidi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91"
uuid = "559328eb-81f9-559d-9380-de523a88c83c"
version = "1.0.10+0"

[[Future]]
deps = ["Random"]
uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820"

[[GLFW_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"]
git-tree-sha1 = "dba1e8614e98949abfa60480b13653813d8f0157"
uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89"
version = "3.3.5+0"

[[GR]]
deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "Serialization", "Sockets", "Test", "UUIDs"]
git-tree-sha1 = "182da592436e287758ded5be6e32c406de3a2e47"
uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
version = "0.58.1"

[[GR_jll]]
deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "d59e8320c2747553788e4fc42231489cc602fa50"
uuid = "d2c73de3-f751-5644-a686-071e5b155ba9"
version = "0.58.1+0"

[[GeometryBasics]]
deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"]
git-tree-sha1 = "58bcdf5ebc057b085e58d95c138725628dd7453c"
uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
version = "0.4.1"

[[Gettext_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046"
uuid = "78b55507-aeef-58d4-861c-77aaff3498b1"
version = "0.21.0+0"

[[Glib_jll]]
deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "7bf67e9a481712b3dbe9cb3dac852dc4b1162e02"
uuid = "7746bdde-850d-59dc-9ae8-88ece973131d"
version = "2.68.3+0"

[[Grisu]]
git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2"
uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe"
version = "1.0.2"

[[HTTP]]
deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"]
git-tree-sha1 = "60ed5f1643927479f845b0135bb369b031b541fa"
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
version = "0.9.14"

[[IfElse]]
git-tree-sha1 = "28e837ff3e7a6c3cdb252ce49fb412c8eb3caeef"
uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
version = "0.1.0"

[[IniFile]]
deps = ["Test"]
git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8"
uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f"
version = "0.5.0"

[[IntelOpenMP_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d979e54b71da82f3a65b62553da4fc3d18c9004c"
uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0"
version = "2018.0.3+2"

[[InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

[[Interpolations]]
deps = ["AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"]
git-tree-sha1 = "61aa005707ea2cebf47c8d780da8dc9bc4e0c512"
uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
version = "0.13.4"

[[Intervals]]
deps = ["Dates", "Printf", "RecipesBase", "Serialization", "TimeZones"]
git-tree-sha1 = "323a38ed1952d30586d0fe03412cde9399d3618b"
uuid = "d8418881-c3e1-53bb-8760-2df7ec849ed5"
version = "1.5.0"

[[InvertedIndices]]
git-tree-sha1 = "bee5f1ef5bf65df56bdd2e40447590b272a5471f"
uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f"
version = "1.1.0"

[[IrrationalConstants]]
git-tree-sha1 = "f76424439413893a832026ca355fe273e93bce94"
uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
version = "0.1.0"

[[IterTools]]
git-tree-sha1 = "05110a2ab1fc5f932622ffea2a003221f4782c18"
uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
version = "1.3.0"

[[IteratorInterfaceExtensions]]
git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856"
uuid = "82899510-4779-5014-852e-03e436cf321d"
version = "1.0.0"

[[JLLWrappers]]
deps = ["Preferences"]
git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.3.0"

[[JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.2"

[[JSONSchema]]
deps = ["HTTP", "JSON", "ZipFile"]
git-tree-sha1 = "b84ab8139afde82c7c65ba2b792fe12e01dd7307"
uuid = "7d188eb4-7ad8-530c-ae41-71a32a6d4692"
version = "0.3.3"

[[JpegTurbo_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943"
uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8"
version = "2.1.0+0"

[[JuMP]]
deps = ["Calculus", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MathOptInterface", "MutableArithmetics", "NaNMath", "Printf", "Random", "SparseArrays", "SpecialFunctions", "Statistics"]
git-tree-sha1 = "4f0a771949bbe24bf70c89e8032c107ebe03f6ba"
uuid = "4076af6c-e467-56ae-b986-b466b2749572"
version = "0.21.9"

[[KernelDensity]]
deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"]
git-tree-sha1 = "591e8dc09ad18386189610acafb970032c519707"
uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b"
version = "0.6.3"

[[LAME_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c"
uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d"
version = "3.100.1+0"

[[LZO_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6"
uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac"
version = "2.10.1+0"

[[LaTeXStrings]]
git-tree-sha1 = "c7f1c695e06c01b95a67f0cd1d34994f3e7db104"
uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
version = "1.2.1"

[[Latexify]]
deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"]
git-tree-sha1 = "a4b12a1bd2ebade87891ab7e36fdbce582301a92"
uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
version = "0.15.6"

[[LazyArtifacts]]
deps = ["Artifacts", "Pkg"]
uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3"

[[LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"

[[LibCURL_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"

[[LibGit2]]
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"

[[LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"

[[LibVPX_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "12ee7e23fa4d18361e7c2cde8f8337d4c3101bc7"
uuid = "dd192d2f-8180-539f-9fb4-cc70b1dcf69a"
version = "1.10.0+0"

[[Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"

[[Libffi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "761a393aeccd6aa92ec3515e428c26bf99575b3b"
uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490"
version = "3.2.2+0"

[[Libgcrypt_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"]
git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae"
uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4"
version = "1.8.7+0"

[[Libglvnd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"]
git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf"
uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29"
version = "1.3.0+3"

[[Libgpg_error_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9"
uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8"
version = "1.42.0+0"

[[Libiconv_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778"
uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531"
version = "1.16.1+1"

[[Libmount_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73"
uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9"
version = "2.35.0+0"

[[Libtiff_jll]]
deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"]
git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9"
uuid = "89763e89-9b03-5906-acba-b20f662cd828"
version = "4.3.0+0"

[[Libuuid_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066"
uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700"
version = "2.36.0+0"

[[LineSearches]]
deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"]
git-tree-sha1 = "f27132e551e959b3667d8c93eae90973225032dd"
uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255"
version = "7.1.1"

[[LinearAlgebra]]
deps = ["Libdl"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

[[LinearFractional]]
deps = ["JuMP", "MacroTools", "MathOptInterface"]
git-tree-sha1 = "d6f7fc5da94fbc9b68a999eb4da32ef832e1d766"
uuid = "31851ddc-f9b7-5097-a470-69ef907d7682"
version = "0.7.4"

[[LogExpFunctions]]
deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"]
git-tree-sha1 = "3d682c07e6dd250ed082f883dc88aee7996bf2cc"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.3.0"

[[Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"

[[MKL_jll]]
deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg"]
git-tree-sha1 = "c253236b0ed414624b083e6b72bfe891fbd2c7af"
uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7"
version = "2021.1.1+1"

[[MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "0fb723cd8c45858c22169b2e42269e53271a6df7"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.7"

[[Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"

[[MathOptInterface]]
deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "JSON", "JSONSchema", "LinearAlgebra", "MutableArithmetics", "OrderedCollections", "SparseArrays", "Test", "Unicode"]
git-tree-sha1 = "575644e3c05b258250bb599e57cf73bbf1062901"
uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
version = "0.9.22"

[[MbedTLS]]
deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"]
git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe"
uuid = "739be429-bea8-5141-9913-cc70e7f3736d"
version = "1.0.3"

[[MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"

[[Measures]]
git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f"
uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
version = "0.3.1"

[[Missings]]
deps = ["DataAPI"]
git-tree-sha1 = "2ca267b08821e86c5ef4376cffed98a46c2cb205"
uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
version = "1.0.1"

[[Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[Mocking]]
deps = ["ExprTools"]
git-tree-sha1 = "748f6e1e4de814b101911e64cc12d83a6af66782"
uuid = "78c3b35d-d492-501b-9361-3d52fe80e533"
version = "0.7.2"

[[Mosek]]
deps = ["Libdl", "Pkg", "Printf", "SparseArrays", "WinReg"]
git-tree-sha1 = "883be630ab4a25991037c2a2079d7170a5a8908e"
uuid = "6405355b-0ac2-5fba-af84-adbd65488c0e"
version = "1.1.3"

[[MosekTools]]
deps = ["MathOptInterface", "Mosek", "Printf"]
git-tree-sha1 = "56f7c254a9d3769bda929e05f1db2d19d8aa3375"
uuid = "1ec41992-ff65-5c91-ac43-2df89e9693a4"
version = "0.9.4"

[[MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"

[[MutableArithmetics]]
deps = ["LinearAlgebra", "SparseArrays", "Test"]
git-tree-sha1 = "3927848ccebcc165952dc0d9ac9aa274a87bfe01"
uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0"
version = "0.2.20"

[[NLSolversBase]]
deps = ["DiffResults", "Distributed", "FiniteDiff", "ForwardDiff"]
git-tree-sha1 = "144bab5b1443545bc4e791536c9f1eacb4eed06a"
uuid = "d41bc354-129a-5804-8e4c-c37616107c6c"
version = "7.8.1"

[[NaNMath]]
git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb"
uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
version = "0.3.5"

[[NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"

[[OffsetArrays]]
deps = ["Adapt"]
git-tree-sha1 = "c870a0d713b51e4b49be6432eff0e26a4325afee"
uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
version = "1.10.6"

[[Ogg_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7937eda4681660b4d6aeeecc2f7e1c81c8ee4e2f"
uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051"
version = "1.3.5+0"

[[OpenSSL_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "15003dcb7d8db3c6c857fda14891a539a8f2705a"
uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
version = "1.1.10+0"

[[OpenSpecFun_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1"
uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e"
version = "0.5.5+0"

[[Optim]]
deps = ["Compat", "FillArrays", "LineSearches", "LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "PositiveFactorizations", "Printf", "SparseArrays", "StatsBase"]
git-tree-sha1 = "7863df65dbb2a0fa8f85fcaf0a41167640d2ebed"
uuid = "429524aa-4258-5aef-a3af-852621145aeb"
version = "1.4.1"

[[Opus_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720"
uuid = "91d4177d-7536-5919-b921-800302f37372"
version = "1.3.2+0"

[[OrderedCollections]]
git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.1"

[[PCRE_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488"
uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc"
version = "8.44.0+0"

[[PDMats]]
deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"]
git-tree-sha1 = "4dd403333bcf0909341cfe57ec115152f937d7d8"
uuid = "90014a1f-27ba-587c-ab20-58faa44d9150"
version = "0.11.1"

[[PGFPlotsX]]
deps = ["ArgCheck", "DataStructures", "Dates", "DefaultApplication", "DocStringExtensions", "MacroTools", "Parameters", "Requires", "Tables"]
git-tree-sha1 = "9c70cfd9f33384c7e9560f2918c4ef716e4ce652"
uuid = "8314cec4-20b6-5062-9cdb-752b83310925"
version = "1.3.2"

[[ParameterJuMP]]
deps = ["JuMP", "MathOptInterface", "MutableArithmetics", "SparseArrays"]
git-tree-sha1 = "a73cb3215747dc6d42a71efd760933c9209c3d2b"
uuid = "774612a8-9878-5177-865a-ca53ae2495f9"
version = "0.3.0"

[[Parameters]]
deps = ["OrderedCollections", "UnPack"]
git-tree-sha1 = "2276ac65f1e236e0a6ea70baff3f62ad4c625345"
uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a"
version = "0.12.2"

[[Parsers]]
deps = ["Dates"]
git-tree-sha1 = "bfd7d8c7fd87f04543810d9cbd3995972236ba1b"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "1.1.2"

[[Pixman_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29"
uuid = "30392449-352a-5448-841d-b1acce4e97dc"
version = "0.40.1+0"

[[Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

[[PlotThemes]]
deps = ["PlotUtils", "Requires", "Statistics"]
git-tree-sha1 = "a3a964ce9dc7898193536002a6dd892b1b5a6f1d"
uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
version = "2.0.1"

[[PlotUtils]]
deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"]
git-tree-sha1 = "9ff1c70190c1c30aebca35dc489f7411b256cd23"
uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043"
version = "1.0.13"

[[Plots]]
deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs"]
git-tree-sha1 = "9e1a400fb1f27b4146fe35dc1a22de6c793b8f20"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
version = "1.21.2"

[[PooledArrays]]
deps = ["DataAPI", "Future"]
git-tree-sha1 = "a193d6ad9c45ada72c14b731a318bedd3c2f00cf"
uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720"
version = "1.3.0"

[[PositiveFactorizations]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "17275485f373e6673f7e7f97051f703ed5b15b20"
uuid = "85a6dd25-e78a-55b7-8502-1745935b8125"
version = "0.2.4"

[[Preferences]]
deps = ["TOML"]
git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.2"

[[PrettyTables]]
deps = ["Crayons", "Formatting", "Markdown", "Reexport", "Tables"]
git-tree-sha1 = "0d1245a357cc61c8cd61934c07447aa569ff22e6"
uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
version = "1.1.0"

[[Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[[Qt5Base_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"]
git-tree-sha1 = "ad368663a5e20dbb8d6dc2fddeefe4dae0781ae8"
uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1"
version = "5.15.3+0"

[[QuadGK]]
deps = ["DataStructures", "LinearAlgebra"]
git-tree-sha1 = "12fbe86da16df6679be7521dfb39fbc861e1dc7b"
uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
version = "2.4.1"

[[REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[[Random]]
deps = ["Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[Ratios]]
deps = ["Requires"]
git-tree-sha1 = "7dff99fbc740e2f8228c6878e2aad6d7c2678098"
uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439"
version = "0.4.1"

[[RecipesBase]]
git-tree-sha1 = "44a75aa7a527910ee3d1751d1f0e4148698add9e"
uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
version = "1.1.2"

[[RecipesPipeline]]
deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"]
git-tree-sha1 = "d4491becdc53580c6dadb0f6249f90caae888554"
uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c"
version = "0.4.0"

[[Reexport]]
git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2"

[[Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.1.3"

[[Rmath]]
deps = ["Random", "Rmath_jll"]
git-tree-sha1 = "bf3188feca147ce108c76ad82c2792c57abe7b1f"
uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa"
version = "0.7.0"

[[Rmath_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "68db32dff12bb6127bac73c209881191bf0efbb7"
uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f"
version = "0.3.0+0"

[[SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"

[[Scratch]]
deps = ["Dates"]
git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda"
uuid = "6c6a2e73-6563-6170-7368-637461726353"
version = "1.1.0"

[[SentinelArrays]]
deps = ["Dates", "Random"]
git-tree-sha1 = "54f37736d8934a12a200edea2f9206b03bdf3159"
uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c"
version = "1.3.7"

[[Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"

[[Setfield]]
deps = ["ConstructionBase", "Future", "MacroTools", "Requires"]
git-tree-sha1 = "fca29e68c5062722b5b4435594c3d1ba557072a3"
uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46"
version = "0.7.1"

[[SharedArrays]]
deps = ["Distributed", "Mmap", "Random", "Serialization"]
uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383"

[[Showoff]]
deps = ["Dates", "Grisu"]
git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de"
uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
version = "1.0.3"

[[Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"

[[SortingAlgorithms]]
deps = ["DataStructures"]
git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508"
uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c"
version = "1.0.1"

[[SparseArrays]]
deps = ["LinearAlgebra", "Random"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[[SpecialFunctions]]
deps = ["ChainRulesCore", "LogExpFunctions", "OpenSpecFun_jll"]
git-tree-sha1 = "a322a9493e49c5f3a10b50df3aedaf1cdb3244b7"
uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
version = "1.6.1"

[[Static]]
deps = ["IfElse"]
git-tree-sha1 = "854b024a4a81b05c0792a4b45293b85db228bd27"
uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
version = "0.3.1"

[[StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "3240808c6d463ac46f1c1cd7638375cd22abbccb"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.2.12"

[[Statistics]]
deps = ["LinearAlgebra", "SparseArrays"]
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[[StatsAPI]]
git-tree-sha1 = "1958272568dc176a1d881acb797beb909c785510"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.0.0"

[[StatsBase]]
deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
git-tree-sha1 = "8cbbc098554648c84f79a463c9ff0fd277144b6c"
uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
version = "0.33.10"

[[StatsFuns]]
deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"]
git-tree-sha1 = "46d7ccc7104860c38b11966dd1f72ff042f382e4"
uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
version = "0.9.10"

[[StructArrays]]
deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"]
git-tree-sha1 = "1700b86ad59348c0f9f68ddc95117071f947072d"
uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a"
version = "0.6.1"

[[SuiteSparse]]
deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"]
uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"

[[TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"

[[TableTraits]]
deps = ["IteratorInterfaceExtensions"]
git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39"
uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
version = "1.0.1"

[[Tables]]
deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"]
git-tree-sha1 = "d0c690d37c73aeb5ca063056283fde5585a41710"
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
version = "1.5.0"

[[Tar]]
deps = ["ArgTools", "SHA"]
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"

[[Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[[TimeZones]]
deps = ["Dates", "Future", "LazyArtifacts", "Mocking", "Pkg", "Printf", "RecipesBase", "Serialization", "Unicode"]
git-tree-sha1 = "6c9040665b2da00d30143261aea22c7427aada1c"
uuid = "f269a46b-ccf7-5d73-abea-4c690281aa53"
version = "1.5.7"

[[TranscodingStreams]]
deps = ["Random", "Test"]
git-tree-sha1 = "216b95ea110b5972db65aa90f88d8d89dcb8851c"
uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
version = "0.9.6"

[[URIs]]
git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355"
uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
version = "1.3.0"

[[UUIDs]]
deps = ["Random", "SHA"]
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[[UnPack]]
git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b"
uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
version = "1.0.2"

[[Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[[Wayland_jll]]
deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23"
uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89"
version = "1.19.0+0"

[[Wayland_protocols_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll"]
git-tree-sha1 = "2839f1c1296940218e35df0bbb220f2a79686670"
uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91"
version = "1.18.0+4"

[[WinReg]]
deps = ["Test"]
git-tree-sha1 = "808380e0a0483e134081cc54150be4177959b5f4"
uuid = "1b915085-20d7-51cf-bf83-8f477d6f5128"
version = "0.3.1"

[[WoodburyMatrices]]
deps = ["LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "59e2ad8fd1591ea019a5259bd012d7aee15f995c"
uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6"
version = "0.5.3"

[[XML2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a"
uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a"
version = "2.9.12+0"

[[XSLT_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"]
git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a"
uuid = "aed1982a-8fda-507f-9586-7b0439959a61"
version = "1.1.34+0"

[[Xorg_libX11_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"]
git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527"
uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc"
version = "1.6.9+4"

[[Xorg_libXau_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e"
uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec"
version = "1.0.9+4"

[[Xorg_libXcursor_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd"
uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724"
version = "1.2.0+4"

[[Xorg_libXdmcp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4"
uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05"
version = "1.1.3+4"

[[Xorg_libXext_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3"
uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3"
version = "1.3.4+4"

[[Xorg_libXfixes_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4"
uuid = "d091e8ba-531a-589c-9de9-94069b037ed8"
version = "5.0.3+4"

[[Xorg_libXi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"]
git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246"
uuid = "a51aa0fd-4e3c-5386-b890-e753decda492"
version = "1.7.10+4"

[[Xorg_libXinerama_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"]
git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123"
uuid = "d1454406-59df-5ea1-beac-c340f2130bc3"
version = "1.1.4+4"

[[Xorg_libXrandr_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631"
uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484"
version = "1.5.2+4"

[[Xorg_libXrender_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96"
uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa"
version = "0.9.10+4"

[[Xorg_libpthread_stubs_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb"
uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74"
version = "0.1.0+3"

[[Xorg_libxcb_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"]
git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6"
uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b"
version = "1.13.0+3"

[[Xorg_libxkbfile_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2"
uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a"
version = "1.1.0+4"

[[Xorg_xcb_util_image_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97"
uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b"
version = "0.4.0+1"

[[Xorg_xcb_util_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"]
git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1"
uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5"
version = "0.4.0+1"

[[Xorg_xcb_util_keysyms_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00"
uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7"
version = "0.4.0+1"

[[Xorg_xcb_util_renderutil_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e"
uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e"
version = "0.3.9+1"

[[Xorg_xcb_util_wm_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67"
uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361"
version = "0.4.1+1"

[[Xorg_xkbcomp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"]
git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b"
uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4"
version = "1.4.2+4"

[[Xorg_xkeyboard_config_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"]
git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d"
uuid = "33bec58e-1273-512f-9401-5d533626f822"
version = "2.27.0+4"

[[Xorg_xtrans_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845"
uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10"
version = "1.4.0+3"

[[ZipFile]]
deps = ["Libdl", "Printf", "Zlib_jll"]
git-tree-sha1 = "c3a5637e27e914a7a445b8d0ad063d701931e9f7"
uuid = "a5390f91-8eb1-5f08-bee0-b1d1ffed6cea"
version = "0.9.3"

[[Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"

[[Zstd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6"
uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
version = "1.5.0+0"

[[libass_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "acc685bcf777b2202a904cdcb49ad34c2fa1880c"
uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0"
version = "0.14.0+4"

[[libfdk_aac_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7a5780a0d9c6864184b3a2eeeb833a0c871f00ab"
uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280"
version = "0.1.6+4"

[[libpng_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c"
uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f"
version = "1.6.38+0"

[[libvorbis_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"]
git-tree-sha1 = "c45f4e40e7aafe9d086379e5578947ec8b95a8fb"
uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a"
version = "1.3.7+0"

[[nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"

[[p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"

[[x264_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d713c1ce4deac133e3334ee12f4adff07f81778f"
uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a"
version = "2020.7.14+2"

[[x265_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "487da2f8f2f0c8ee0e83f39d13037d6bbf0a45ab"
uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76"
version = "3.0.0+3"

[[xkbcommon_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"]
git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6"
uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd"
version = "0.9.1+5"
"""

# ╔═╡ Cell order:
# ╟─3cf2bafa-4bf4-11eb-3482-ff09ca17af71
# ╠═1fbdb6c6-4bf4-11eb-3aeb-9548bde2b1a5
# ╠═473d8a28-4bf4-11eb-0151-8b3f3d286eda
# ╠═17be2c0c-4bf5-11eb-25ca-cfe4e5fb5485
# ╠═acfc4fc0-4bf4-11eb-32dc-dfe1652ac006
# ╟─f4bd73b8-4bf4-11eb-3678-655227b0895b
# ╠═0731218a-4bf5-11eb-10f4-81241477b265
# ╠═0d36dbee-4bf5-11eb-3036-7bcf68579a46
# ╠═246264dc-4bf5-11eb-2f9d-b5c7d137a9b3
# ╠═4dd1f99a-4bf5-11eb-3691-9db09ab324df
# ╟─362effcc-4bf5-11eb-1d84-3133de3f4825
# ╠═5ad6b662-4bf5-11eb-24fb-d141933957ca
# ╠═605a545e-4bf5-11eb-3020-6d9c53e39a8e
# ╠═69e87366-4bf5-11eb-3fbb-8f7bf325d366
# ╠═750e2af0-4bf6-11eb-3374-1f224647d4e5
# ╟─aa99cc74-4bf6-11eb-2e3f-81de213db00d
# ╠═df1513be-4bf6-11eb-1b1c-fd650fd994fe
# ╠═c4bc3468-4bf4-11eb-1710-f7638d026b91
# ╠═bd7a5362-4bf4-11eb-1f2c-79ff3e915f89
# ╠═9b6b8f8a-4bf6-11eb-002d-7fa04ddde0d3
# ╠═68f0af78-8165-11eb-2a88-efd9f9743eec
# ╠═ce945cca-4bf6-11eb-29bc-4b2514ae395d
# ╠═e9e81b9c-4bf6-11eb-1c3c-d56076f6858b
# ╠═04c72ec6-4bf7-11eb-3265-5f69502b9f0b
# ╠═31bd322c-4bf7-11eb-007c-d7583730cd8e
# ╠═3d5b459c-4bf7-11eb-3825-6b75cc4099f3
# ╠═474bdc10-4bf7-11eb-0099-cdf3150001a2
# ╠═5fe96288-4bf7-11eb-1805-1f7f7815e035
# ╠═65d3b2de-4bf7-11eb-3ab5-a13a5b5556ef
# ╠═6ade8f74-4bf7-11eb-2b46-51436f6bf297
# ╠═7c0fd708-4bf7-11eb-12e0-45ecc7f9af7a
# ╠═85c63cc4-4bf7-11eb-2688-2b63ea65b2e7
# ╠═89a047c2-4bf7-11eb-3c79-15fe2fcdcb1c
# ╠═a262fe94-4bf7-11eb-1153-6f76128cbcd0
# ╠═622669fa-4bf8-11eb-08fd-a3bd67230729
# ╠═6930b1ae-4bf8-11eb-23c7-e5be40b7a283
# ╠═6fba4f94-4bf8-11eb-2177-87f38a9b73d2
# ╠═7c308bb4-4bf8-11eb-249a-0f6d933a530c
# ╠═8abdac16-4bf8-11eb-3b0d-a73d7b28bb7c
# ╠═eb851e8a-4bf8-11eb-353a-e5c394ae5294
# ╠═1e0db04c-4bf9-11eb-1bde-9dfa4f81f279
# ╠═2700eeda-4bf9-11eb-27ba-c5c6fe33980d
# ╠═2eba35aa-4bf9-11eb-1bf0-0be32d4bff85
# ╠═a30dce02-4bfa-11eb-1197-5b69f20af457
# ╠═716b8220-4bf9-11eb-1a28-33dbf08e138c
# ╠═9afa4b4a-4bf9-11eb-2a16-531b86e6b9a9
# ╠═9e06f2b8-4bf9-11eb-1bad-b5a1d26339ee
# ╠═a1ba1e12-4bf9-11eb-00c9-496602f4eb5c
# ╠═f2414706-4bfa-11eb-1654-9bdcc7418db8
# ╠═f7a59c42-4bfa-11eb-27df-cf611213fefc
# ╟─3e986c36-79a1-4ffd-9d2b-4bc96f2a5fa8
# ╠═c6758a61-c32f-4ec7-8336-085f6dadb96d
# ╠═3950ca34-f8eb-4450-985f-fdb47a1b6f8b
# ╠═e61af6d2-e4df-4c9a-bb2e-40e8e706f36d
# ╠═8a936d80-c61f-4d22-a1f1-c891d0063ee2
# ╠═d0c37eca-4c5e-42ba-970a-4d1fe27d33ea
# ╠═5ef18ef6-0d4a-4846-a1ec-8dfcc4168588
# ╠═506eb209-b761-48a2-8a31-0fe8c98a9802
# ╠═80f5d5de-0d75-4a6e-8143-8e3f3b48af43
# ╠═fb6464e6-3a4d-4609-9b96-37edc2a6021f
# ╠═c09e057e-24b2-4486-a497-e4908dcf2881
# ╠═c5ae00f4-c078-4ece-9ebf-90ea8e5b724a
# ╠═6501119c-338c-4931-a09e-38b5b3f8a81d
# ╠═a1b52f7a-4a53-485f-b246-fe008322c6a4
# ╠═24b4a3d6-2e7d-4f84-bf84-6fe97b24e93a
# ╠═4c812df1-fc00-4f42-a50c-4d08ca5b576b
# ╠═8925c810-b292-4dc6-ba4d-3e040d8b8689
# ╠═fdb0fc1a-2b8b-4d6c-b848-47d145308875
# ╠═40d68d1a-f93f-45e6-8f0e-3c25af40c411
# ╠═7fe7a76b-fe38-4019-b068-d471123d1c9a
# ╠═81fd9a91-35dc-48dc-bb79-f01ea110d952
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


text:
using PyCall

py"""
import numpy
def get_phifj_solution_grad_tri(order, P1, Np, Nflux, elem_nfaces, V, Vf):

    correction_coeffs = numpy.zeros( shape=(Np, elem_nfaces*P1) )

    phifj_solution_r = numpy.zeros( shape=(Np, Nflux) )
    phifj_solution_s = numpy.zeros( shape=(Np, Nflux) )

    tmp = 1./numpy.sqrt(2)

    nhat = numpy.zeros(shape=(Nflux,2))
    nhat[0:P1, 0] =  0.0
    nhat[0:P1, 1] = -1.0

    nhat[P1:2*P1, :] = tmp

    nhat[2*P1:, 0] = -1
    nhat[2*P1:, 1] = 0.0

    #wgauss, rgauss = get_gauss_nodes(order)
    rgauss, wgauss = numpy.polynomial.legendre.leggauss(order+1)

    for m in range(Np):
        for face in range(3):
            modal_basis_along_face = Vf[ face*P1:(face+1)*P1, m ]
            correction_coeffs[m, face*P1:(face+1)*P1] = modal_basis_along_face*wgauss

    # correct the coefficients for face 2 with the Hypotenuse length
    correction_coeffs[:, P1:2*P1] *= numpy.sqrt(2)

    # Multiply the correction coefficients with the Dubiner basis
    # functions evaluated at the solution and flux points to get the
    # correction functions
    phifj_solution = V.dot(correction_coeffs)

    # multiply each row of the correction function with the
    # transformed element normals. These matrices will be used to
    # compute the gradients and flux divergence
    for m in range(Np):
        phifj_solution_r[m, :] = phifj_solution[m, :] * nhat[:, 0]
        phifj_solution_s[m, :] = phifj_solution[m, :] * nhat[:, 1]

    # stack the matrices
    phifj_grad = numpy.zeros( shape=(3*Np, Nflux) )
    phifj_grad[:Np,     :] = phifj_solution_r[:, :]
    phifj_grad[Np:2*Np, :] = phifj_solution_s[:, :]

    return correction_coeffs, phifj_solution, phifj_grad
"""


text:
module TestDistributedReduce

include("../preamble.jl")
using BangBang
using Distributed
using Logging: LogLevel
using StructArrays: StructVector
using Test: collect_test_logs

const ProgressLevel = LogLevel(-1)

@testset "dreduce" begin
    fname = gensym(:attach_pid)
    @everywhere $fname(x) = [(x, getpid())]
    fun = getproperty(Main, fname)

    pids = fetch.(map(id -> remotecall(getpid, id), workers()))
    xs0 = 1:10
    @testset "dreduce(..., $xslabel; $kwargs...)" for (xslabel, xs) in Any[
            # Input containers:
            ("$xs0", xs0),
            ("withprogress(xs; interval=0)", withprogress(xs0; interval = 0)),
        ],
        kwargs in Any[
            # Keyword arguments to `dreduce`:
            (),
            (basesize = 1,),
            (basesize = 1, threads_basesize = 1),
            (basesize = 4, threads_basesize = 2),
            (basesize = 4, threads_basesize = 2, simd = true),
        ]

        ys = dreduce(append!!, Map(fun), xs; init = Union{}[], kwargs...)
        @test first.(ys) == xs0
        @test Set(last.(ys)) == Set(pids)
    end
end

@testset "dcollect & dcopy" begin
    @test dcollect(Filter(iseven), 1:10, basesize = 2) == 2:2:10

    fname = gensym(:makerow)
    @everywhere $fname(x) = (a = x,)
    makerow = getproperty(Main, fname)
    @everywhere import StructArrays
    @test dcopy(Map(makerow), StructVector, 1:3, basesize = 2) == StructVector(a = 1:3)
end

@testset "TakeWhile" begin
    fname = gensym(:lessthan5)
    @everywhere $fname(x) = x < 5
    lessthan5 = getproperty(Main, fname)

    coll = 1:10
    @testset for basesize in 1:(length(coll)+1)
        @test dcollect(TakeWhile(lessthan5), coll; basesize = basesize) == 1:4
    end
end

@testset "basesize > 0" begin
    @test dcollect(Map(identity), [1]) == [1]
end

@testset "empty input" begin
    @test isempty(dcollect(Map(identity), []))
end

@testset "withprogress" begin
    xs = 1:10
    @testset "dreduce(..., withprogress(xs; interval=0); $kwargs...)" for kwargs in Any[
        # Keyword arguments to `dreduce`:
        (),
        (basesize = 4, threads_basesize = typemax(Int)),
        (basesize = 4, threads_basesize = 2),
        (basesize = 4, threads_basesize = 2, simd = true),
    ]
        logs, ans = collect_test_logs(min_level = ProgressLevel) do
            dreduce(+, Map(identity), withprogress(xs; interval = 0.0); kwargs...)
        end
        @test ans == sum(xs)
        @test length(logs) > 2
        @test logs[1].kwargs[:progress] === 0.0
        @test all(l.kwargs[:progress] isa Float64 for l in logs[2:end-1])
        @test logs[end].kwargs[:progress] === "done"
    end
end

end  # module


text:
mutable struct twist_t <: LCMType
    linear_velocity::vector_3d_t
    angular_velocity::vector_3d_t
end

@lcmtypesetup(twist_t)


text:
# attemptiing to take advantage of tkf's unmerged Zygote commit to fuse Fwd mode AD
# broadcasting into rev-mode AD:
# https://github.com/FluxML/Zygote.jl/pull/338
# https://github.com/tkf/Zygote.jl/commit/402cbc912866b6838941dc09b90bdb26aa69e33b
# https://github.com/tkf/ChainCutters.jl

#                        .-'''-.                               _..._
#                       '   _    \         _______          .-'_..._''.
#  /|                 /   /` '.   \        \  ___ `'.     .' .'      '.\
#  ||                .   |     \  '         ' |--.\  \   / .'
#  ||        .-,.--. |   '      |  '        | |    \  ' . '                                     .|
#  ||  __    |  .-. |\    \     / /  __     | |     |  '| |                 __                .' |_
#  ||/'__ '. | |  | | `.   ` ..' /.:--.'.   | |     |  || |              .:--.'.         _  .'     |
#  |:/`  '. '| |  | |    '-...-'`/ |   \ |  | |     ' .'. '             / |   \ |      .' |'--.  .-'
#  ||     | || |  '-             `" __ | |  | |___.' /'  \ '.          .`" __ | |     .   | / |  |
#  ||\    / '| |                  .'.''| | /_______.'/    '. `._____.-'/ .'.''| |   .'.'| |// |  |
#  |/\'..' / | |                 / /   | |_\_______|/       `-.______ / / /   | |_.'.'.-'  /  |  '.'
#  '  `'-'`  |_|                 \ \._,\ '/                          `  \ \._,\ '/.'   \_.'   |   /
#                                 `--'  `"                               `--'  `"             `'-'

# using Base.Broadcast
# using Base.Broadcast: Broadcasted, AbstractArrayStyle, broadcasted, materialize
# using NNlib
#
# @nograd Broadcast.combine_styles, Broadcast.result_style
#
# # There's a saying that debugging code is about twice as hard as writing it in
# # the first place. So if you're as clever as you can be when writing code, how
# # will you ever debug it?
#
# # AD faces a similar dilemma: if you write code that's as clever as the compiler
# # can handle, how will you ever differentiate it? Differentiating makes clever
# # code that bit more complex and the compiler gives up, usually resulting in
# # 100x worse performance.
#
# # Base's broadcasting is very cleverly written, and this makes differentiating
# # it... somewhat tricky.
#
# # Utilities
# # =========
#
# accum_sum(xs; dims = :) = reduce(accum, xs, dims = dims)
accum_sum(xs::Tuple; dims = :) = reduce(accum, xs)
#
# # Work around reducedim_init issue
# accum_sum(xs::Nothing; dims = :) = nothing
# accum_sum(xs::AbstractArray{Nothing}; dims = :) = nothing
# accum_sum(xs::AbstractArray{<:Number}; dims = :) = sum(xs, dims = dims)
# accum_sum(xs::Number; dims = :) = xs
#
# trim(x, Δ) = reshape(Δ, ntuple(i -> size(Δ, i), Val(ndims(x))))
#
# unbroadcast(x::AbstractArray, x̄) =
#   size(x) == size(x̄) ? x̄ :
#   length(x) == length(x̄) ? trim(x, x̄) :
#     trim(x, accum_sum(x̄, dims = ntuple(i -> size(x, i) == 1 ? i : ndims(x̄)+1, Val(ndims(x̄)))))
#
# unbroadcast(x::Union{Number,Ref}, x̄) = accum_sum(x̄)
#
unbroadcast(x::Union{AbstractArray, Tuple}, x̄::Nothing) = nothing
unbroadcast(x::NTuple{N}, x̄::NTuple{N}) where N = x̄
#
# # Split Reverse Mode
# # ==================
#
# # TODO: use DiffRules here. It's complicated a little by the fact that we need
# # to do CSE, then broadcast-ify the expression so that the closure captures the
# # right arrays.
#
# Numeric{T<:Number} = Union{T,AbstractArray{<:T}}
#
# @adjoint broadcasted(::typeof(+), xs::Numeric...) =
#   broadcast(+, xs...), ȳ -> (nothing, map(x -> unbroadcast(x, ȳ), xs)...)
#
# @adjoint broadcasted(::typeof(*), x::Numeric, y::Numeric) = x.*y,
#   z̄ -> (nothing, unbroadcast(x, z̄ .* conj.(y)), unbroadcast(y, z̄ .* conj.(x)))
#
# @adjoint function broadcasted(::typeof(/), x::Numeric, y::Numeric)
#   res = x ./ y
#   res, Δ -> (nothing, unbroadcast(x, Δ ./ y), unbroadcast(y, -Δ .* res ./ y))
# end
#
# @adjoint function broadcasted(::typeof(σ), x::Numeric)
#   y = σ.(x)
#   y, ȳ -> (nothing, ȳ .* conj.(y .* (1 .- y)))
# end
#
# @adjoint function broadcasted(::typeof(tanh), x::Numeric)
#   y = tanh.(x)
#   y, ȳ -> (nothing, ȳ .* conj.(1 .- y.^2))
# end
#
# @adjoint broadcasted(::typeof(conj), x::Numeric) =
#   conj.(x), z̄ -> (nothing, conj.(z̄))
#
# @adjoint broadcasted(::typeof(real), x::Numeric) =
#   real.(x), z̄ -> (nothing, real.(z̄))
#
# @adjoint broadcasted(::typeof(imag), x::Numeric) =
#   imag.(x), z̄ -> (nothing, im .* real.(z̄))
#
# # General Fallback
# # ================
#
# # The fused reverse mode implementation is the most general but currently has
# # poor performance. It works by flattening the broadcast and mapping the call to
# # `_pullback` over the input.
#
# # However, the core call
# # broadcast(_pullback, (cx,), f, args...)
# # is already 10x slower than a simple broadcast (presumably due to inlining
# # issues, or something similar) and the other operations needed take it to about
# # 100x overhead.
#
abstract type ArgPlaceholder end
struct FDiffable <: ArgPlaceholder end
struct NonFDiffable <: ArgPlaceholder end
struct ConstantArg <: ArgPlaceholder end

struct DualArg{P} <: ArgPlaceholder
  partials::P
end

struct FlatFunction{F, Args <: Tuple{Vararg{ArgPlaceholder}}} <: ArgPlaceholder
  f::F
  args::Args

  # This is to match the layout of `FlatFunction` to `Broadcasted` so
  # that the pullback would create the named tuple usable for
  # `Broadcasted`:
  axes::Nothing
end

FlatFunction(f, args) = FlatFunction(f, args, nothing)

@inline foldlargs(op, x) = x
@inline foldlargs(op, x1, x2, xs...) = foldlargs(op, op(x1, x2), xs...)

consume(::ArgPlaceholder, x, rest...) = x, rest
consume(d::DualArg, x, rest...) = Dual(x, d.partials), rest
@inline function consume(ff::FlatFunction, args0...)
  args, rest = foldlargs(((), args0), ff.args...) do (args, rest), g
    a, r = consume(g, rest...)
    ((args..., a), r)
  end
  return (ff.f(args...), rest)
end

@inline function (ff::FlatFunction)(args...)
  y, rest = consume(ff, args...)
  @assert length(rest) == 0
  return y
end

@inline isconstant(x) = isconstanttype(typeof(x))
@inline isconstanttype(::Type) = false
@inline isconstanttype(::Type{<:Union{
  # From `Broadcast.broadcastable`:
  Symbol,
  AbstractString,
  UndefInitializer,
  Nothing,
  RoundingMode,
  Missing,
  Val,
  Ptr,
  Regex,
  Type,
}}) = true

@inline ArgPlaceholder(x) =
  isconstant(x) ? ConstantArg() : NonFDiffable()
@inline ArgPlaceholder(::Union{Real, AbstractArray{<:Real}}) = FDiffable()
@inline ArgPlaceholder(bc::Broadcasted) =
  FlatFunction(bc.f, map(ArgPlaceholder, bc.args))

fdiffables(_) = 0
fdiffables(::FDiffable) = 1
@inline fdiffables(ff::FlatFunction) = sum(fdiffables, ff.args)

@inline fillpartials(ff::FlatFunction) = _fillpartials(Val(fdiffables(ff)), 1, ff)[1]

@inline function _fillpartials(npartials, i, ff::FlatFunction)
  args, i = foldlargs(((), i), ff.args...) do (args, i), x
    if x isa FlatFunction
      a, i = fillpartials(npartials, i, x)
      (args..., a), i
    elseif x isa FDiffable
      (args..., DualArg(ntuple(j -> i == j, npartials))), i + 1
    else
      (args..., x), i
    end
  end
  return FlatFunction(ff.f, args), i
end

isfdiffable(_) = false
isfdiffable(::FDiffable) = true
@inline isfdiffable(ff::FlatFunction) =
  all(isfdiffable, ff.args) && Base.issingletontype(typeof(ff.f))

# @generated inclen(::NTuple{N,Any}) where N = Val(N+1)

bcstyle(::Broadcasted{Style}) where Style = Style

flatargs(x) = (x,)
flatargs(bc::Broadcasted) = foldlargs((), bc.args...) do args, x
  (args..., flatargs(x)...)
end

@inline function back_materialize(bc::Broadcasted, ȳ, out, i=1)
  args, i = foldlargs(((), i), bc.args...) do (args, i), x
    if x isa Broadcasted
      a, i = back_materialize(x, ȳ, out, i)
      (args..., a), i
    elseif ArgPlaceholder(x) isa FDiffable
      (args..., unbroadcast(x, ((a, b) -> a*b.partials[i]).(ȳ, out))), i + 1
    else
      (args..., nothing), i
    end
  end
  return (f=nothing, args=args, axes=nothing), i
end

function unflatten(bc, dargs)
  dbc, rest = _unflatten(bc, dargs...)
  @assert length(rest) == 0
  return dbc
end
@inline _unflatten(_, d, rest...) = d, rest
@inline function _unflatten(bc::Broadcasted, dargs0...)
  dargs, rest = foldlargs(((), dargs0), bc.args...) do (dargs, rest), x
    a, r = _unflatten(x, rest...)
    ((dargs..., a), r)
  end
  return (f=nothing, args=dargs, axes=nothing), rest
end

# Avoid hitting special cases for `Adjoint` etc.
# _broadcast(f::F, x...) where F = materialize(broadcasted(f, x...))
#
# _get(x::Tuple, i) = x[i]
# _get(::Nothing, i) = nothing
# collapse_nothings(xs::Vector{Nothing}) = nothing
# collapse_nothings(xs) = xs

@adjoint function copy(bc::Broadcasted)
  ff0 = ArgPlaceholder(bc)
  if isfdiffable(ff0)
    ff = fillpartials(ff0)
    out = copy(Broadcasted{bcstyle(bc)}(ff, flatargs(bc), bc.axes))
    eltype(out) <: Dual || out <: Dual || return (out, _ -> nothing)
    y = map(x -> x.value, out)
    back(ȳ) = back_materialize(bc, ȳ, out)
    return y, back
  else
    y∂b = _broadcast((x...) -> _pullback(__context__, ff0, x...), flatargs(bc)...)
    y = map(x -> x[1], y∂b)
    ∂b = map(x -> x[2], y∂b)
    y, function (ȳ)
      dxs_zip = map((∂b, ȳ) -> ∂b(ȳ), ∂b, ȳ)
      fargs = flatargs(bc)
      len = inclen(fargs)
      dxs = collapse_nothings.(ntuple(i -> map(x -> _get(x, i), dxs_zip), len))
      dargs = map(unbroadcast, fargs, Base.tail(dxs))
      (accum(accum_sum(dxs[1]), unflatten(bc, dargs)),)
      # Note: relying on that `dxs[1]`, `ff0`, and `bc0` have same shape
    end
  end
end

@adjoint function broadcasted(::AbstractArrayStyle{0}, f, args...)
  len = inclen(args)
  y, ∂b = _broadcast((x...) -> _pullback(__context__, f, x...), args...)
  y, function (ȳ)
    dxs = ∂b(ȳ)
    (nothing, dxs...)
  end
end
#
# @adjoint! (b::typeof(broadcast))(f, args...) = _pullback(__context__, broadcasted, f, args...)
#
# # Forward Mode (mainly necessary for CUDA)
#
# import ForwardDiff
# using ForwardDiff: Dual
#
# dual(x, p) = x
# dual(x::Real, p) = Dual(x, p)
#
# dualtype(::Type{Dual{G,T,P}}) where {G,T,P} = T
# dualtype(T) = T
#
# function dual_function(f::F) where F
#   function (args::Vararg{Any,N}) where N
#     ds = map(args, ntuple(identity,Val(N))) do x, i
#       dual(x, ntuple(j -> i==j, Val(N)))
#     end
#     return f(ds...)
#   end
# end
#
# @inline function broadcast_forward(f, args::Vararg{Any,N}) where N
#   T = Broadcast.combine_eltypes(f, args)
#   out = dual_function(f).(args...)
#   eltype(out) <: Dual || return (out, _ -> nothing)
#   y = map(x -> x.value, out)
#   _back(ȳ, i) = unbroadcast(args[i], ((a, b) -> a*b.partials[i]).(ȳ, out))
#   back(ȳ) = ntuple(i -> _back(ȳ, i), N)
#   return y, back
# end
#
# @init @require CuArrays="3a865a2d-5b23-5a0f-bc46-62713ec82fae" begin
#   @adjoint function broadcasted(::Broadcast.ArrayStyle{CuArrays.CuArray}, f, args...)
#     y, back = broadcast_forward(f, args...)
#     y, ȳ -> (nothing, nothing, back(ȳ)...)
#   end
# end


text:
using Embeddings
using Test

using DataDeps

"""
    tempdatadeps(fun)

Run the function and delete all created datadeps afterwards
"""
function tempdatadeps(fun)
    tempdir = mktempdir()
    try
        @info "sending all datadeps to $tempdir"
        withenv("DATADEPS_LOAD_PATH"=>tempdir) do
            fun()
        end
    finally
        try
            @info "removing $tempdir"
            rm(tempdir, recursive=true, force=true)
        catch err
            @warn "Something went wrong with removing tempdir" tempdir exception=err
        end
    end
end

# uncomment the below to not use tempdatadeps (i.e. if not debugging)
# tempdatadeps(fun) = fun()

"""
@testset_nokeep_data

Use just like @testset,
but know that it deletes any downloaded data dependencies when it is done.
"""
macro testset_nokeep_data(name, expr)
    quote
        tempdatadeps() do
            println("Testing ", $name)
            @testset $name $expr
        end
    end |> esc
end

@testset_nokeep_data "Word2Vec" begin
    embs_full = load_embeddings(Word2Vec)

    @test size(embs_full.embeddings) == (300, length(embs_full.vocab))

    embs_mini = load_embeddings(Word2Vec; max_vocab_size=100)
    @test length(embs_mini.vocab)==100

    @test embs_mini.embeddings == embs_full.embeddings[:, 1:100]
    @test embs_mini.vocab == embs_full.vocab[1:100]

    @test "for" ∈ embs_mini.vocab

    embs_specific =  load_embeddings(Word2Vec; keep_words=Set(["red", "green", "blue"]))

    @test size(embs_specific.embeddings) == (300, 3)
    @test Set(embs_specific.vocab) == Set(["red", "green", "blue"])
end

@testset "GloVe" begin
    # just test one file from each of provided sets
    tests = ["glove.6B/glove.6B.50d.txt",
             #"glove.42B.300d/glove.42B.300d.txt",     # These files are too slow to download
             #"glove.840B.300d/glove.840B.300d.txt",   # They are not that big but are on a slow server
             #"glove.twitter.27B/glove.twitter.27B.25d.txt"
            ]

    # read dimensionality from name (e.g. glove.6B.300d.txt -> 300)
    dim(x) = parse(Int, match(r"\.([0-9]+)d\.", x).captures[1])

    for file in tests
        filename = split(file, Base.Filesystem.path_separator)[end]

        @testset_nokeep_data "$filename" begin
            @testset "Basic" begin
                glove = load_embeddings(GloVe{:en}, @datadep_str(file), max_vocab_size=1000)
                @test length(glove.vocab) == 1000
                @test size(glove.embeddings) == (dim(file), 1000)
                @test "for" ∈ glove.vocab
            end

            @testset "Specific" begin
                colors = ["red", "green", "blue"]
                glove_colors = load_embeddings(GloVe, @datadep_str(file), keep_words=colors)
                @test length(glove_colors.vocab) == 3
                @test size(glove_colors.embeddings) == (dim(file), 3)
                @test Set(glove_colors.vocab) == Set(colors)
            end
        end
    end

    @testset "Custom" begin
        # first 100 lines of official glove.6B.50d.txt
        custom_glove_file = joinpath(@__DIR__, "data", "custom.glove.txt")
        @testset "Basic" begin
            glove = load_embeddings(GloVe, custom_glove_file)
            @test length(glove.vocab) == 100
            @test size(glove.embeddings) == (50, 100)
            @test "the" ∈ glove.vocab
        end
        @testset "Specific" begin
            punct = [".", ","]
            glove_punct = load_embeddings(GloVe, custom_glove_file, keep_words=punct)
            @test length(glove_punct.vocab) == 2
            @test size(glove_punct.embeddings) == (50, 2)
            @test Set(glove_punct.vocab) == Set(punct)
        end
    end

    @testset "non-breaking-space" begin
        # https://github.com/JuliaText/Embeddings.jl/issues/24
        # This includes the text with nonbreaking space in the work
        custom_glove_file = joinpath(@__DIR__, "data", "nbsp.glove.txt")
        @testset "Basic" begin
            glove = load_embeddings(GloVe, custom_glove_file)
            @test ".\U00A0.\U00A0." ∈ glove.vocab
            @test size(glove.embeddings) == (300, 3)
        end
    end
end

@testset "FastText" begin
    @testset_nokeep_data "English 1" begin
        @testset "Basic" begin
            embs1 = load_embeddings(FastText_Text; max_vocab_size=100)
            @test length(embs1.vocab)==100
            @test size(embs1.embeddings) == (300, 100)
        end

        @testset "Specific" begin
            embs_specific =  load_embeddings(FastText_Text; keep_words=Set(["red", "green", "blue"]))
            @test size(embs_specific.embeddings) == (300, 3)
            @test Set(embs_specific.vocab) == Set(["red", "green", "blue"])
        end
    end

    @testset_nokeep_data "French" begin
        embs_fr = load_embeddings(FastText_Text{:fr}; max_vocab_size=100)
        @test length(embs_fr.vocab)==100
        @test size(embs_fr.embeddings) == (300, 100)
    end

    @testset_nokeep_data "English file number 2" begin
        embs_specific =  load_embeddings(FastText_Text, 2; keep_words=Set(["red", "green", "blue"]))
        @test size(embs_specific.embeddings) == (300, 3)
        @test Set(embs_specific.vocab) == Set(["red", "green", "blue"])
    end
end


text:
module TestMotifs
using Test
#include("../../src/EcologicalNetwork.jl")
using EcologicalNetworks
using LinearAlgebra

@test unipartitemotifs().S1.A == [false true false; false false true; false false false];

n = UnipartiteNetwork(zeros(Bool, (2, 2)))
m = unipartitemotifs().S1
@test length(find_motif(n, m)) ≈ 0.0

# Test with a single link
N = UnipartiteProbabilisticNetwork([0.2 0.8; 0.2 0.1])
m = UnipartiteNetwork([false true; false false])
@test expected_motif_count(find_motif(N,m))[1] ≈ 0.680

# Test with a perfect match
N = UnipartiteProbabilisticNetwork([0.0 1.0; 0.0 0.0])
m = UnipartiteNetwork([false true; false false])
@test expected_motif_count(find_motif(N,m)) == (1.0, 0.0)

# Test with a fork-like thing
diam = UnipartiteNetwork([0 1 0 0; 0 0 1 1; 0 0 0 0; 0 0 0 0].>0)
clin = UnipartiteNetwork([0 1 0; 0 0 1; 0 0 0].>0)
capp = UnipartiteNetwork([0 1 1; 0 0 0; 0 0 0].>0)
cdir = UnipartiteNetwork([0 0 1; 0 0 1; 0 0 0].>0)

@test length(find_motif(diam, clin)) == 2
@test length(find_motif(diam, capp)) == 1
@test length(find_motif(diam, cdir)) == 0

# Test with a diamond food web
diam = UnipartiteNetwork([0 1 1 0; 0 0 0 1; 0 0 0 1; 0 0 0 0].>0)
clin = UnipartiteNetwork([0 1 0; 0 0 1; 0 0 0].>0)
capp = UnipartiteNetwork([0 1 1; 0 0 0; 0 0 0].>0)
cdir = UnipartiteNetwork([0 0 1; 0 0 1; 0 0 0].>0)

@test length(find_motif(diam, clin)) == 2
@test length(find_motif(diam, capp)) == 1
@test length(find_motif(diam, cdir)) == 1

lfc = UnipartiteNetwork([0 1 0; 0 0 1; 0 0 0].>0)
wsl = UnipartiteNetwork([1 1 0; 0 0 1; 0 0 0].>0)

# This tests for the removal of the diagonal
@test length(find_motif(wsl, lfc)) == 1

lfc = UnipartiteNetwork([0 1 0; 0 0 1; 0 0 0].>0)
wsl = UnipartiteQuantitativeNetwork([1 0.5 0; 0 0 1.6; 0 0 0])

@test length(find_motif(wsl, lfc)) == 1

# Test with a diamond food web
diam = BipartiteNetwork([1 1 0; 1 1 1].>0)
tthr = BipartiteNetwork([1 0; 1 1].>0)
tfou = BipartiteNetwork([1 1; 1 1].>0)

@test length(find_motif(diam, tthr)) == 2
@test length(find_motif(diam, tfou)) == 1

# Test on a three-species network
B = UnipartiteNetwork([false true true; false false true; false false false])
@test length(find_motif(B, B)) == 1

BDN = BipartiteNetwork([false true true; false false true; false false false])
@test length(find_motif(BDN, BDN)) == 1.0

# Test on the same network, this time with a proba one
P = UnipartiteProbabilisticNetwork([0.0 1.0 1.0; 0.0 0.0 1.0; 0.0 0.0 0.0])
B = UnipartiteNetwork([false true true; false false true; false false false])
@test expected_motif_count(find_motif(P, B)) == (1.0, 0.0)

# Test with some variation
ovl = UnipartiteNetwork([false true true; false false true; false false false])
N = UnipartiteProbabilisticNetwork([0.0 1.0 0.8; 0.0 0.0 1.0; 0.0 0.0 0.0])
@test first(expected_motif_count(find_motif(N, ovl))) ≈ 0.8
fchain = UnipartiteNetwork([false true false; false false true; false false false])
@test first(expected_motif_count(find_motif(N, fchain))) ≈ 0.2

# Bipartite proba network
B = BipartiteProbabilisticNetwork(Matrix{Float64}(I, (3, 3)))
m = BipartiteNetwork(Matrix{Bool}(I, (3, 3)))
@test first(expected_motif_count(find_motif(B, m))) ≈ 1.0
@test last(expected_motif_count(find_motif(B, m))) ≈ 0.0

# Unipartite multiple motifs
X = [false true true true false; false false false true true; false false false false true;
    false false false false false; false false false false false]
N = UnipartiteNetwork(X, [:a, :b, :c, :d, :e])

@test length(find_motif(N, unipartitemotifs().S1)) == 2
@test length(find_motif(N, unipartitemotifs().S2)) == 1
@test length(find_motif(N, unipartitemotifs().S3)) == 0
@test length(find_motif(N, unipartitemotifs().S4)) == 1
@test length(find_motif(N, unipartitemotifs().S5)) == 3

# Diamond
N = UnipartiteNetwork([false true true false; false false false true;
    false false false true; false false false false], [:a, :b, :c, :d])

@test length(find_motif(N, unipartitemotifs().S1)) == 2
@test length(find_motif(N, unipartitemotifs().S2)) == 0
@test length(find_motif(N, unipartitemotifs().S3)) == 0
@test length(find_motif(N, unipartitemotifs().S4)) == 1
@test length(find_motif(N, unipartitemotifs().S5)) == 1

# Self motifs
for this_motif in unipartitemotifs()
    @test length(find_motif(this_motif, this_motif)) == 1
end

end


text:
struct RegistryMeta
    name::String
    uuid::String
    source_url::String
    latest_hash::Union{String, Nothing}
end
RegistryMeta(name, uuid, source_url) = RegistryMeta(name, uuid, source_url, nothing)

struct Package
    name::String
    uuid::String
    versions::Dict
    url::String
    registry_dir::String

    function Package(
        name::AbstractString,
        uuid::AbstractString,
        registry_dir::AbstractString;
        latest_versions_num::Union{Nothing,Integer} = nothing,
    )
        isdir(registry_dir) || error("Folder $registry_dir doesn't exist.")

        version_file = joinpath(registry_dir, "Versions.toml")
        isfile(version_file) ||
        error("$version_file doesn't exist: $registry_dir might be a broken registry folder.")

        versions_info = TOML.parsefile(version_file)
        if !isnothing(latest_versions_num)
            # only keep the latest `latest_versions_num` versions
            versions = sort!(collect(keys(versions_info)), rev = true, by = VersionNumber)
            versions = versions[1:min(length(versions), latest_versions_num)]
            versions_info = Dict(k => versions_info[k] for k in versions)
        end

        dep_file = joinpath(registry_dir, "Package.toml")
        isfile(dep_file) ||
        error("$dep_file doesn't exist: $registry_dir might be a broken registry folder.")
        pkg_info = TOML.parsefile(dep_file)

        url = pkg_info["repo"]
        new(name, uuid, versions_info, url, registry_dir)
    end
end

struct Artifact
    hash::String
end


text:
import AbstractAlgebra

function read_BIOMDs(nspecies)
    @info "Reading biomodels"
    systems = []
    for smth in readdir(abspath("benchmark/biomodels"))
        system = []

        @info "" smth
        !(occursin("BIOMD", smth)) && continue

        io = open(abspath("benchmark/biomodels/$smth/species_map.txt"), "r")
        vs = map(strip ∘ first, map(split, readlines(io)))
        close(io)
        # @info "variables" vs
        !(length(vs) in nspecies) && continue

        io = open(abspath("benchmark/biomodels/$smth/parameters.txt"), "r")
        params = readlines(io)
        params = map(p -> replace(p, "/"=>"//"), params)
        params = map(params) do p
            p = split(p, " = ")
            if occursin("//", p[2])
                n, d = split(p[2], "//")
                "$(p[1]) = BigInt($n)//BigInt($d)"
            else
                "$(p[1]) = BigInt($(p[2]))"
            end
        end
        close(io)

        io = open(abspath("benchmark/biomodels/$smth/odes.txt"), "r")
        odes = readlines(io)
        close(io)

        symvs = map(x -> Symbol(x), vs)
        expvs = Meta.parse(join(symvs, ","))
        R, xs = eval(:((R, $expvs) = AbstractAlgebra.PolynomialRing(AbstractAlgebra.QQ, $symvs)))

        for p in params
            p = eval(Meta.parse(p))
        end

        for ode in odes
            ode = replace(ode, "{"=>"","}"=>"", "/"=>"//",","=>" ")
            ode = strip(last(split(ode, "=")))
            poly = eval(Meta.parse(ode))
            push!(system, poly)
        end

        system = map(system) do f
            if f isa AbstractAlgebra.Generic.MPoly
                f
            elseif f isa AbstractAlgebra.Generic.Frac
                lc = AbstractAlgebra.leading_coefficient(denominator(f))
                AbstractAlgebra.map_coefficients(c -> c // lc, numerator(f))
            else
                R(f)
            end
        end
        system = filter(!iszero, system)
        push!(systems, (smth, map(R, system)))
    end

    @info "Loaded" length(systems)
    systems
end


text:
"m_1"
macro m_1(x)
end

"""m_2"""
macro m_2(x)
end

dummy_2() = ()


text:
#
# gram-tests.jl -
#
# Test Gram operator.
#
module TestingLazyAlgebraRules
using LazyAlgebra
using LazyAlgebra.Foundations
using Test

@testset "Gram operators" begin
    @test gram(Id) === Id
    rows = (3,4,)
    cols = (2,5,)
    T = Float32
    a = rand(T, rows..., cols...)
    A = GeneralMatrix(a)
    AtA = gram(A)
    @test isa(AtA, Gram)
    @test isa(A'*A, Gram)
    @test A'*A === AtA
    @test AtA' === AtA
    x = rand(T, cols)
    y = A'*(A*x)
    z = AtA*x
    @test z ≈ y
end

end # module