text:
"Type stored in `ChemEquation.tuples`."
const CompoundTuple{T} = Tuple{Compound, T}

fwd_arrows = ['>', '→', '↣', '↦', '⇾', '⟶', '⟼', '⥟', '⥟', '⇀', '⇁', '⇒', '⟾']
bwd_arrows = ['<', '←', '↢', '↤', '⇽', '⟵', '⟻', '⥚', '⥞', '↼', '↽', '⇐', '⟽']
double_arrows = ['↔', '⟷', '⇄', '⇆', '⇌', '⇋', '⇔', '⟺']
pure_rate_arrows = ['⇐', '⟽', '⇒', '⟾', '⇔', '⟺']
equal_signs = ['=', '≔', '⩴', '≕']
"""
Characters used to split a chemical equation into two sides.
Source: <https://github.com/SciML/Catalyst.jl/blob/master/src/reaction_network.jl#L56>
"""
const EQUALCHARS = vcat(fwd_arrows, bwd_arrows, double_arrows, pure_rate_arrows, equal_signs)

"Regex to split a chemical equation into compounds."
const PLUSREGEX = r"(?<!{)\+(?!})" # '+' not after '{' and not before '}'

"Stores chemical equation's compounds and their coefficients in a structured way."
struct ChemEquation{T<:Real}
    tuples::Vector{CompoundTuple{T}}
end

"""
Constructs a chemical equation from the given string.
If no `{Type}` is provided, it defaults to `Int`.

Parsing is insensitive to whitespace.
Any character in [`EQUALCHARS`](@ref) separates the equation into two sides,
while `+` separates the equation into compounds.

# Examples
```jldoctest
julia> ChemEquation("N2+O2⇌2NO")
N2 + O2 = 2 NO

julia> ChemEquation("CH3COOH + Na → H2 + CH3COONa")
C2H4O2 + Na = H2 + C2H3O2Na

julia> ChemEquation("⏣H + Cl2 = ⏣Cl + HCl")
⏣H + Cl2 = ⏣Cl + HCl

julia> ChemEquation{Rational}("1//2 H2 → H")
1//2 H2 = H

julia> ChemEquation{Float64}("0.5 H2 + 0.5 Cl2 = HCl")
0.5 H2 + 0.5 Cl2 = HCl
```
"""
ChemEquation{T}(str::AbstractString) where T<:Real = ChemEquation(_compoundtuples(str, T))

ChemEquation(str::AbstractString) = ChemEquation{Int}(str)

"Extracts compound tuples from equation's string."
function _compoundtuples(str::AbstractString, T::Type)
    strs = replace(str, [' ', '_'] => "") |>
        x -> split(x, EQUALCHARS) |>
        x -> split.(x, PLUSREGEX)
    splitindex = length(strs[1])
    strs = [strs[1]; strs[2]]
    tuples = Vector{CompoundTuple{T}}(undef, length(strs))

    for (i, compound) ∈ enumerate(strs)
        k = 1
        if isdigit(compound[1]) # begins with a digit
            charindex = findfirst(r"\(?(\p{L}|\p{S})", compound)[1]
            k, compound = compound[1:charindex-1], compound[charindex:end]
            k = Meta.parse(k) |> eval
        end
        if i > splitindex
            k *= -1
        end
        tuples[i] = (Compound(compound), k)
    end

    return tuples
end

"""
Constructs a chemical equation with `ce"str"` syntax, instead of `ChemEquation(str)`.

# Examples
```jldoctest
julia> ce"H2 + O2 → H2O"
H2 + O2 = H2O
```
"""
macro ce_str(str) ChemEquation(str) end

"""
Checks whether two equations are chemically equal.

# Examples
```jldoctest
julia> ce"H2 + O2 = H2O" == ce"O2 + H2 → H2O"
true
```
"""
function Base.:(==)(equation_1::ChemEquation, equation_2::ChemEquation)
    f = x -> sort(x[1].tuples)
    return sort(equation_1.tuples, by = f) == sort(equation_2.tuples, by = f)
end

"""
Creates a string to represent the chemical equation.

All compounds are displayed with [`Base.string(::Compound)`](@ref),
in the order in which they were originally given,
with coefficients equal to 1 not displayed.
`'='` and `'+'` are used as separators, with spaces inserted for easier reading.

# Examples
```jldoctest
julia> string(ce"Cr2O7{2-} + H{+} + {-} = Cr{3+} + H2O")
"Cr2O7{-2} + H{+} + e = Cr{+3} + H2O"
```
"""
function Base.string(equation::ChemEquation)
    left = String[]
    right = String[]
    for (compound, k) ∈ equation.tuples
        str = ""
        if k ∉ (-1, 1)
            str *= string(abs(k)) * " "
        end
        str *= string(compound)
        if k > 0
            push!(left, str)
        else
            push!(right, str)
        end
    end
    left = join(left, " + ")
    right = join(right, " + ")
    return join([left, right], " = ")
end

"Displays the chemical equation using [`Base.string(::Compound)`](@ref)."
function Base.show(io::IO, equation::ChemEquation)
    print(io, string(equation))
end

"Returns chemical equation's compounds in a list."
function compounds(equation::ChemEquation)
    return first.(equation.tuples) |> unique
end

"""
Returns chemical equation's unique elements.

# Examples
```jldoctest
julia> elements(ce"2 H2 + O2 → 2 H2O")
2-element Array{String,1}:
 "H"
 "O"
```
"""
function elements(equation::ChemEquation)
    vect::Vector{String} = vcat(elements.(compounds(equation))...) |> unique
    return vect
end

"True if chemical equation has at least one compound with nonzero charge."
function hascharge(equation::ChemEquation)
    return any(hascharge, compounds(equation))
end


text:
export pmap_shm_create, setup_shm, unlink_shm, ShmCfg

using Base.FS

# Below constants have been checked for Ubuntu.
const PROT_READ  = 0x01
const PROT_WRITE = 0x02
const MAP_SHARED = 0x01

type ShmCfg
    sname::Symbol
    stype::Type
    sdims::Union(Tuple, Int)
end

function pmap_shm_create(map_list, shmpfx="")
    unlink_shm(map_list, shmpfx)
    for i in 1:nprocs()
        remotecall_fetch(i, setup_shm, map_list, shmpfx)
    end
end

free_shmem(map_list::ShmCfg, shmpfx) = unlink_shm([map_list], shmpfx)
free_shmem(map_list::Symbol, shmpfx) = unlink_shm([map_list], shmpfx)
free_shmem(map_list, shmpfx) = unlink_shm(map_list, shmpfx)

get_shmem_name(shmpfx, sname) = "/julia_" * shmpfx * "_" * string(sname)

# if map_global is false, adds it to the task_local_storage
function setup_shm(map_list, shmpfx="", map_global=false)
    if !isa(shmpfx, String) shmpfx = "" end
    if isa(map_list, ShmCfg)
        map_list = [map_list]
    end
    for e in map_list
        sname = e.sname
        stype = e.stype
        sdims = e.sdims

        if isa(sdims, Tuple)
            dims = prod(sdims)
        else
            dims = sdims
        end

        numb = dims * sizeof(stype)

        fd_mem = ccall(:shm_open, Int, (Ptr{Uint8}, Int, Int), get_shmem_name(shmpfx, sname), JL_O_CREAT | JL_O_RDWR, S_IRUSR | S_IWUSR)
        if !(fd_mem > 0) error("shm_open() failed") end

        if(1 == myid())
            rc = ccall(:ftruncate, Int, (Int, Int), fd_mem, numb)
    #        println(string(myid()) * "@ftruncate, rc : " * string(rc) * ", fd_mem : " * string(fd_mem))
            if !(rc == 0)
               ec = errno()
               error("ftruncate() failed : $ec")
            end
        end

        x = ccall(:mmap, Ptr{Void}, (Ptr{Void}, Int, Int32, Int32, Int32, FileOffset), C_NULL, numb, PROT_READ | PROT_WRITE, MAP_SHARED, fd_mem, 0)
#        println(string(myid()) * "@mmap, x : " * string(x) * ", fd_mem : " * string(fd_mem)* ", numb : " * string(numb))
        if (x == C_NULL) error("mmap() failed") end

        if (map_global)
#            println("global " * string(sname) * " ===> " * string(x))
            eval(:(global $sname; $sname = pointer_to_array(pointer($stype, $x), $sdims)))
        else
#            println("tls " * string(sname) * " ===> " * string(x))
            task_local_storage(sname, pointer_to_array(pointer(stype, x), sdims))
        end

        ccall(:close, Int, (Int, ), fd_mem)
    end
end

function unlink_shm(map_list, shmpfx="")
    if !isa(shmpfx, String) shmpfx = "" end
    if isa(map_list, ShmCfg) map_list = [map_list] end
    for e in map_list
        v_n = isa(e, ShmCfg) ? e.sname : e
        ccall(:shm_unlink, Int, (Ptr{Uint8}, ), get_shmem_name(shmpfx, v_n))
    end
end

ext: jl


text:
"""
    center!(X::AbstractMatrix, [μ::AbstractVector]; [obsdim], [operate_on]) -> μ

Shift the values in `X` along `obsdim` by the corresponding
values in `μ`. This means it shifts each feature across all
observations. The optional parameter `operate_on` can be used to
limit the operation to specific "features".

# Arguments

- `μ`: Vector describing the translation. Defaults to `mean(X, 2)`.

- `obsdim`: Specify which axis corresponds to observations.
  Defaults to `obsdim = 2`, which implies that each column of the
  matrix is an observation.

- `operate_on`: Specify the indices of "features", which
  depending on `pobsdim` are either the columns or rows, to be
  centered. Defaults to all columns/rows. For example
  `operate_on = [1,3]` will perform centering on the rows with
  index 1 and 3 (if `obsdim = 2`).

# Examples

```@jldoctests
julia> using MLPreprocessing

julia> X = [1. 2. 3.; 101. 103. 105.]
2×3 Array{Float64,2}:
   1.0    2.0    3.0
 101.0  103.0  105.0

julia> mu = center!(X)
2-element Array{Float64,1}:
   2.0
 103.0

julia> X
2×3 Array{Float64,2}:
 -1.0  0.0  1.0
 -2.0  0.0  2.0

julia> x = [2., 102.]
2-element Array{Float64,1}:
   2.0
 102.0

julia> center!(x, mu); x
2-element Array{Float64,1}:
  0.0
 -1.0

julia> X = [1. 2. 3.; 101. 103. 105.]'
3×2 Array{Float64,2}:
 1.0  101.0
 2.0  103.0
 3.0  105.0

julia> mu = center!(X, obsdim=1, operate_on=[2])
1-element Array{Float64,1}:
 103.0

julia> X
3×2 Array{Float64,2}:
 1.0  -2.0
 2.0   0.0
 3.0   2.0
```
"""
function center!(X::AbstractMatrix;
                 obsdim = LearnBase.default_obsdim(X),
                 operate_on = default_scaleselection(X, convert(ObsDimension, obsdim)))
    center!(X, convert(ObsDimension, obsdim), operate_on)
end

function center!(X::AbstractMatrix,
                 obsdim::ObsDimension;
                 operate_on = default_scaleselection(X, obsdim))
    center!(X, obsdim, operate_on)
end

function center!(X::AbstractMatrix,
                 obsdim::ObsDim.Last,
                 operate_on::AbstractVector)
    center!(X, ObsDim.Constant{2}(), operate_on)
end

function center!(X::AbstractMatrix,
                 obsdim::ObsDim.Constant{M},
                 operate_on::AbstractVector) where {M}
    μ = vec(mean(X; dims=M))[operate_on]
    center!(X, μ, obsdim, operate_on)
end

function center!(X::AbstractMatrix,
                 μ::AbstractVector;
                 obsdim = LearnBase.default_obsdim(X),
                 operate_on = default_scaleselection(X, convert(ObsDimension, obsdim)))
    center!(X, μ, convert(ObsDimension, obsdim), operate_on)
end

function center!(X::AbstractMatrix,
                 μ::AbstractVector,
                 obsdim::ObsDimension;
                 operate_on = default_scaleselection(X, obsdim))
    center!(X, μ, obsdim, operate_on)
end

function center!(X::AbstractMatrix,
                 μ::AbstractVector,
                 obsdim::ObsDim.Last,
                 operate_on)
    center!(X, μ, ObsDim.Constant{2}(), operate_on)
end

function center!(X::AbstractMatrix,
                 μ::AbstractVector,
                 ::ObsDim.Constant{1},
                 operate_on)
    @assert length(μ) == length(operate_on)
    nObs, nVars = size(X)
    for (i, iVar) in enumerate(operate_on)
        for iObs in 1:nObs
            X[iObs, iVar] = X[iObs, iVar] - μ[i]
        end
    end
    μ
end

function center!(X::AbstractMatrix,
                 μ::AbstractVector,
                 ::ObsDim.Constant{2},
                 operate_on)
    @assert length(μ) == length(operate_on)
    nVars, nObs = size(X)
    for iObs in 1:nObs
        for (i, iVar) in enumerate(operate_on)
            X[iVar, iObs] = X[iVar, iObs] - μ[i]
        end
    end
    μ
end

# --------------------------------------------------------------------

function center!(x::AbstractVector, μ = mean(x); operate_on = default_scaleselection(x))
    center!(x, μ, operate_on)
end

function center!(x::AbstractVector,
                 μ::Number,
                 operate_on::AbstractVector)
    for iVar in operate_on
        x[iVar] = x[iVar] - μ
    end
    μ
end

function center!(x::AbstractVector,
                 μ::AbstractVector,
                 operate_on::AbstractVector)
    @assert length(μ) == length(operate_on)
    for (i, iVar) in enumerate(operate_on)
        x[iVar] = x[iVar] - μ[i]
    end
    μ
end

# --------------------------------------------------------------------

"""
    center!(df::AbstractDataFrame, [μ]; [operate_on]) -> μ

Shift the values in each column of `df` by the corresponding
values in `μ`.

This means it shifts each feature across all observations. The
optional parameter `operate_on` can be used to limit the
operation to specific columns of the data frame. Note that
columns containing missing or non-numeric values are skipped.

# Arguments

- `μ`: Vector or value describing the translation. Defaults to
  `mean(X, 2)`

- `operate_on`: Vector of symbols that specify the indices of
  columns to be centered. Defaults to all columns.

# Examples

```@jldoctest
julia> using MLPreprocessing, DataFrames

julia> df = DataFrame(A=collect(5:-1:1).*0.1, B=collect(1:5), C=[string("foo", x) for x in 1:5])
5×3 DataFrames.DataFrame
│ Row │ A   │ B │ C    │
├─────┼─────┼───┼──────┤
│ 1   │ 0.5 │ 1 │ foo1 │
│ 2   │ 0.4 │ 2 │ foo2 │
│ 3   │ 0.3 │ 3 │ foo3 │
│ 4   │ 0.2 │ 4 │ foo4 │
│ 5   │ 0.1 │ 5 │ foo5 │

julia> μ = center!(df, operate_on = [:A, :B])
2-element Array{Float64,1}:
 0.3
 3.0

julia> df
5×3 DataFrames.DataFrame
│ Row │ A    │ B    │ C    │
├─────┼──────┼──────┼──────┤
│ 1   │ 0.2  │ -2.0 │ foo1 │
│ 2   │ 0.1  │ -1.0 │ foo2 │
│ 3   │ 0.0  │ 0.0  │ foo3 │
│ 4   │ -0.1 │ 1.0  │ foo4 │
│ 5   │ -0.2 │ 2.0  │ foo5 │
```
"""
function center!(D::AbstractDataFrame; operate_on=default_scaleselection(D))
    center!(D, operate_on)
end

function center!(D::AbstractDataFrame, operate_on::AbstractVector{Symbol})
    μ_vec = Float64[]
    for colname in operate_on
        if eltype(@view D[colname]) <: Union{Real, Missing}
            μ = mean(@view D[colname])
            if ismissing(μ)
                @warn("Skipping \"$colname\" because it contains missing values")
                continue
            end
            center!(D, μ, colname)
            push!(μ_vec, μ)
        else
            @warn("Skipping \"$colname\" because data is not of type T <: Real.")
        end
    end
    μ_vec
end

function center!(D::AbstractDataFrame, μ::AbstractVector; operate_on=default_scaleselection(D))
    center!(D, μ, operate_on)
end

function center!(D::AbstractDataFrame, μ::AbstractVector, operate_on::AbstractVector{Symbol})
    for (icol, colname) in enumerate(operate_on)
        if eltype(@view D[colname]) <: Union{Real, Missing}
            center!(D, μ[icol], colname)
        else
            @warn("Skipping \"$colname\" because data is not of type T <: Real.")
        end
    end
    μ
end

function center!(D::AbstractDataFrame, μ::Real, colname::Symbol)
    if any(ismissing, @view D[colname])
        @warn("Skipping \"$colname\" because it contains missing values")
    else
        newcol::Vector{Float64} = convert(Vector{Float64}, D[colname])
        center!(newcol, μ)
        D[colname] = newcol
    end
    μ
end


text:
"""
    apply_subparsers(filename, subparsers)

Applies subparses to each line of the file.
`subparsers` should be a `Vector{Pair{String,Function}}`,
or similar ordered mapping from a line prefix, to a closure for how to parse that line.
This function does not return anything, instead the subparser closures (functions),
should mutate the state in the environment they are defined.
"""
function apply_subparsers(filename, subparsers)
    for line in eachline(filename)
        try
            found = false
            for (prefix, subparse) in subparsers
                if startswith(line, prefix)
                    found=true
                    subparse(line)
                    break
                end
            end
            @assert(found, "No parser for \"$line\"")
        catch ee
            warn("Error parsing \"$line\". $ee")
            rethrow()
        end
    end
    return nothing
end

"""
    ignore(line)

Ignore lines while using subparsers.
"""
function ignore(line)
    nothing
end


text:
# A convenient singleton type, mainly for the timescales below
struct Unit <: Integer; end
const unit = Unit()
Base.show(io::IO, ::Unit) = print(io, "one")

@inline Base.:-(::Unit) = -1
@inline Base.:+(::Unit, ::Unit) = 2

@inline Base.:*(::Unit, ::Unit) = unit
@inline Base.:*(::Unit, x::Number) = x
@inline Base.:*(x::Number, ::Unit) = x
@inline Base.:/(::Unit, ::Unit) = unit
@inline Base.:/(::Unit, x::Number) = 1 / x
@inline Base.:/(x::Number, ::Unit) = x
@inline Base.://(::Unit, ::Unit) = unit
@inline Base.://(::Unit, x::Number) = 1 // x
@inline Base.://(x::Number, ::Unit) = x

Base.promote_rule(::Type{Unit}, ::Type{I}) where {I <: Number} = I
Base.convert(::Type{T}, ::Unit) where {T} = one(T)
Base.convert(::Type{Rational{T}}, ::Unit) where {T<:Integer} = one(Rational{T})
Base.one(::Type{Unit}) = Unit()

# Another convenient singleton type, good for subtracting epochs
struct ZeroUnit <: Integer; end
const zerounit = ZeroUnit()
Base.show(io::IO, ::ZeroUnit) = print(io, "zero")

@inline Base.:+(::ZeroUnit, ::ZeroUnit) = zerounit
@inline Base.:+(::ZeroUnit, x::Number) = x
@inline Base.:+(x::Number, ::ZeroUnit) = x
@inline Base.:-(::ZeroUnit, ::ZeroUnit) = zerounit
@inline Base.:-(::ZeroUnit, x::Number) = -x
@inline Base.:-(x::Number, ::ZeroUnit) = x

@inline Base.:*(::ZeroUnit, ::ZeroUnit) = zerounit
@inline Base.:*(::ZeroUnit, x::Number) = zerounit
@inline Base.:*(x::Number, ::ZeroUnit) = zerounit
@inline Base.:/(::ZeroUnit, x::Number) = zerounit
@inline Base.://(::ZeroUnit, x::Number) = zerounit
@inline Base.div(::ZeroUnit, x::Number) = zerounit
@inline Base.rem(::ZeroUnit, x::Number) = zerounit

Base.promote_rule(::Type{ZeroUnit}, ::Type{I}) where {I <: Number} = I
Base.convert(::Type{T}, ::ZeroUnit) where {T} = zero(T)
Base.convert(::Type{Rational{T}}, ::ZeroUnit) where {T<:Integer} = zero(Rational{T})
Base.zero(::Type{ZeroUnit}) = ZeroUnit()

# Mixed types...
@inline Base.:-(::Unit, ::Unit) = zerounit

@inline Base.:*(::ZeroUnit, ::Unit) = zerounit
@inline Base.:*(::Unit, x::ZeroUnit) = zerounit
@inline Base.:/(::ZeroUnit, x::Unit) = zerounit
@inline Base.://(::ZeroUnit, x::Unit) = zerounit

@inline Base.:rem(::Unit, ::Unit) = zerounit
@inline Base.:div(::ZeroUnit, ::Unit) = zerounit
@inline Base.:rem(::ZeroUnit, ::Unit) = zerounit

Base.promote_rule(::Type{ZeroUnit}, ::Type{Unit}) = Int


text:
using Tinker, Base.Test, TestImages, GtkReactive

# make sure init_image runs
ctx = Tinker.init_image(testimage("cameraman.tif"); name="Testing")
Reactive.run_till_now()
Tinker.set_mode_all(Tinker.rectangle_mode)

# Test zoom functions
test_zr = ZoomRegion((1:100, 1:200))
sig_zr = Signal(test_zr)
push!(sig_zr, Tinker.zoom_percent(1.8, test_zr))
Reactive.run_till_now()
@test test_zr.fullview == value(sig_zr).fullview
@test test_zr.currentview != value(sig_zr).currentview
push!(sig_zr, Tinker.zoom_percent(1.0, test_zr))
Reactive.run_till_now()
@test test_zr == value(sig_zr)
@test XY(100, 50) == Tinker.find_center(test_zr)
# Test zoom tracking
test_ctx = Tinker.ImageContext()
test_ctx.zr = sig_zr
Tinker.zoom_to(test_ctx, 2.3)
Reactive.run_till_now()
@test Tinker.zpercents[Tinker.next_zoom(test_ctx)] == 2.5
@test Tinker.zpercents[Tinker.prev_zoom(test_ctx)] == 2.0
Tinker.zoom_to(test_ctx, 2.0)
Reactive.run_till_now()
@test Tinker.zpercents[Tinker.next_zoom(test_ctx)] == 2.5
@test Tinker.zpercents[Tinker.prev_zoom(test_ctx)] == 1.5
Tinker.zoom_to(test_ctx, 1.2)
Reactive.run_till_now()
@test Tinker.zpercents[Tinker.next_zoom(test_ctx)] == 1.5
@test Tinker.zpercents[Tinker.prev_zoom(test_ctx)] == 1.0

# Test Rectangle constructors
r1 = Tinker.Rectangle(XY(5.0, 56.8), XY(23.4, 10.0))
r2 = Tinker.Rectangle(5.0, 10.0, 18.4, 46.8)
@test r1 == r2

# Test get_view
img = ctx.image
@test img == Tinker.get_view(img, 1, 1, size(img,2), size(img,1))
@test img == Tinker.get_view(img, -50, -50, size(img,2)+20, size(img,1))
@test view(img, Int(floor(size(img,1)/4)):Int(floor(size(img,1)/2)),
           Int(floor(size(img,2)/4)):Int(floor(size(img,2)/2))) ==
    Tinker.get_view(img,size(img,2)/4,size(img,1)/4,size(img,2)/2,size(img,1)/2)

# Test ispolygon
@test !Tinker.ispolygon([XY(1,2),XY(1,2)])
@test !Tinker.ispolygon([XY(1,2),XY(1,2),XY(1,2),XY(1,2)])
@test !Tinker.ispolygon([XY(1,2),XY(3,4),XY(1,2)])
@test Tinker.ispolygon([XY(1,2),XY(5,6),XY(38,42),XY(1,2)])
@test !Tinker.ispolygon([XY(1,2),XY(5,6),XY(38,42),XY(2,2)])
@test Tinker.ispolygon([XY(4,4),XY(5,5),XY(6,7), XY(4,20),XY(9,9),XY(4,4)])
@test !Tinker.ispolygon([XY(1,2),XY(5,6),XY(38,42),XY(1,2),XY(4,4)])

# Test is_point
@test Tinker.near_vertex(XY(5.4,2.8),[XY(4,4),XY(5,5),XY(6,7), XY(4,20),XY(9,9),XY(4,4)],5.0) == 1
@test Tinker.near_vertex(XY(-4,-9),[XY(4,4),XY(5,5),XY(6,7), XY(4,20),XY(9,9),XY(4,4)],5.0) == -1

## SELECTION_ACTIONS.jl
# Test two_point_rect & two_point_rh
rect1 = Tinker.two_point_rect(XY(8.9,0),XY(2,12.3))
recth1 = Tinker.two_point_rh(XY(8.9,0),XY(2,12.3))
@test rect1[1] == recth1[1]
@test rect1[2] == recth1[3]
@test rect1[3] == recth1[5]
@test rect1[4] == recth1[7]
@test rect1[1].y == recth1[2].y
@test rect1[2].x == recth1[4].x
@test rect1[3].y == recth1[6].y
@test rect1[4].x == recth1[8].x

# Test near_point
p1,p2,p3,p4,p5 = XY(0,0),XY(0.1,-0.1),XY(5.0, 5.0),XY(6,0),XY(0,6) # test pts
@test Tinker.near_point(p1, p2, 5.0) # very close
@test Tinker.near_point(p1, p3, 5.0) # limit of tolerance
@test !Tinker.near_point(p1, p3, 2.5) # not within tolerance
@test !Tinker.near_point(p1, p4, 5.0) # x false, y true
@test !Tinker.near_point(p1, p5, 5.0) # y true, x false
@test Tinker.near_point(p1, p1, 2.0) # same point

# Test near_vertex
p = [XY(0,0), XY(3,5), XY(7,4), XY(6,2), XY(0,0)] # test array
@test Tinker.near_vertex(p1, p, 5.0) == 1 # identical point
@test Tinker.near_vertex(p2, p, 0.1) == 1 # limit of tolerance
@test Tinker.near_vertex(p3, p, 2.0) == 2
@test Tinker.near_vertex(p4, p, 4.9) == 3
@test Tinker.near_vertex(p4, p, 2.0) == 4
@test Tinker.near_vertex(p5, p, 2.9) == -1 # false

# Test get_p1
rh = Tinker.two_point_rh(XY(1,1),XY(5.6,7.8))
@test Tinker.get_p1(1, rh) == rh[5]
@test Tinker.get_p1(3, rh) == rh[7]
@test Tinker.get_p1(5, rh) == rh[1]
@test Tinker.get_p1(7, rh) == rh[3]
@test Tinker.get_p1(2, rh) == rh[5]
@test Tinker.get_p1(4, rh) == rh[1]
@test Tinker.get_p1(6, rh) == rh[1]
@test Tinker.get_p1(8, rh) == rh[5]
@test isnan(Tinker.get_p1(9,rh).x)

# Test get_p2
@test Tinker.get_p2(1, rh, p3) == p3
@test Tinker.get_p2(3, rh, p3) == p3
@test Tinker.get_p2(5, rh, p3) == p3
@test Tinker.get_p2(7, rh, p5) == p5
@test Tinker.get_p2(2, rh, p3) == XY(rh[1].x,p3.y)
@test Tinker.get_p2(4, rh, p3) == XY(p3.x,rh[5].y)
@test Tinker.get_p2(6, rh, p3) == XY(rh[5].x,p3.y)
@test Tinker.get_p2(8, rh, p3) == XY(p3.x,rh[1].y)
@test isnan(Tinker.get_p2(9,rh,p3).x)

# Test init_selection_actions
sa = Tinker.init_selection_actions(ctx)
@test value(sa["enabled"]) == false
@test value(sa["mode"]) == Tinker.rectangle_mode


text:
using Test
using AutoPreallocation
using AutoPreallocation: AllocationRecord, record_alloc!

@testset "isequal and hash" begin
    record1 = AllocationRecord()
    record_alloc!(record1, ones(3,7))
    record_alloc!(record1, zeros(40))

    record2 = AllocationRecord()
    record_alloc!(record2, zeros(3,7))
    record_alloc!(record2, ones(40))

    @test record1 == record2
    @test isequal(record1, record2)
    @test hash(record1) === hash(record2)

    @test record1 != AllocationRecord()
    @test !isequal(record1, AllocationRecord())
end

@testset "show" begin
    record = AllocationRecord()
    record_alloc!(record, ones(3,7))
    record_alloc!(record, zeros(40))

    @test repr(record) == "AutoPreallocation.AllocationRecord(\n" *
        "    [Array{Float64,2}(undef, (3, 7)), Array{Float64,1}(undef, (40,))],\n" *
        "    [(3, 7), (40,)]\n" *
        ")"

    # Check canon requirement of a good repr:
    @test eval(Meta.parse(repr(record))) == record
end


text:
using Pkg
Pkg.activate("C:/users/boltg/.julia/enviroments/doc_writing")

using Documenter, InteractionNetworkModels

makedocs(
    sitename="My Documentation",
    format = Documenter.HTML(prettyurls = false),
    pages=["index.md", "model_sampling.md", "examples.md"] )


text:
"""

# Method stan_summary

Display cmdstan summary

### Method
```julia
stan_summary(
  model::StanModel,
  file::String;
  CmdStanDir=CMDSTAN_HOME
)
```
### Required arguments
```julia
* `model::Stanmodel             : Stanmodel
* `file::String`                : Name of file with samples
```

### Optional arguments
```julia
* CmdStanDir=CMDSTAN_HOME       : cmdstan directory for stansummary program
```

### Related help
```julia
?Stan.stan                      : Execute a StanModel
```
"""
function stan_summary(model::Stanmodel, file::String;
  CmdStanDir=CMDSTAN_HOME)
  try
    pstring = joinpath("$(CmdStanDir)", "bin", "stansummary")
    csvfile = "$(model.name)_summary.csv"
    isfile(csvfile) && rm(csvfile)
    cmd = setenv(`$(pstring) -c $(csvfile) $(file)`, ENV; dir=model.tmpdir)
    resfile = open(cmd; read=true)
    println("Setting $(model.printsummary)")
    model.printsummary && print(read(resfile, String))
  catch e
    println(e)
  end
end

"""

# Method stan_summary

Display cmdstan summary

### Method
```julia
stan_summary(
  model::Stanmodel
  filecmd::Cmd;
  CmdStanDir=CMDSTAN_HOME
)
```
### Required arguments
```julia
* `model::Stanmodel`            : Stanmodel
* `filecmd::Cmd`                : Run command containing names of sample files
```

### Optional arguments
```julia
* CmdStanDir=CMDSTAN_HOME       : cmdstan directory for stansummary program
```

### Related help
```julia
?Stan.stan                      : Create a StanModel
```
"""
function stan_summary(model::Stanmodel, filecmd::Cmd;
    CmdStanDir=CMDSTAN_HOME)
  try
    pstring = joinpath("$(CmdStanDir)", "bin", "stansummary")
    csvfile = "$(model.name)_summary.csv"
    isfile(csvfile) && rm(csvfile)
    cmd = setenv(`$(pstring) -c $(csvfile) $(filecmd)`, ENV; dir=model.tmpdir)
    if model.printsummary
      resfile = open(cmd; read=true)
      print(read(resfile, String))
    else
      run(pipeline(cmd, stdout="out.txt"))
    end
  catch e
    println(e)
    println("Stan.jl caught above exception in Stan's 'stansummary' program.")
    println("This is a usually caused by the setting:")
    println("  Sample(save_warmup=true, thin=n)")
    println("in the call to stanmodel() with n > 1.")
    println()
  end
end


text:
module MyTestRepo

# Write your package code here.

# Write your package code here.
struct Taylor
    coefffs::Vector{Complex}
end

evaluate(x::Taylor,z::Complex) = sum(x.coefffs[i]*z^(i-1) for i=1:length(X.coefffs))

export Taylor
export evaluate

end

max_stars_repo_name: Potatoasad/MyTestRepo

max_issues_repo_name: Potatoasad/MyTestRepo

max_forks_repo_name: Potatoasad/MyTestRepo


text:
@testset "Test factorial function" begin
    @test_throws DomainError factorial(-1)
    @test factorial(3) == 6
end


text:
@inline (purse::MetaAbstractPurse)(xs...) = value(purse)(xs...)

# Unary operators
for op in [
    :(Base.complex),
    :(Base.float),
    # Elements
    :(Base.one),
    :(Base.oneunit),
    :(Base.zero),
    # Basic math operations
    :(Base.:(==)),
    :(Base.:*),
    :(Base.:+),
    :(Base.:-),
    :(Base.:/),
    :(Base.:\),
    :(Base.:^),
    :(Base.cbrt),
    :(Base.conj),
    :(Base.exp),
    :(Base.inv),
    :(Base.isapprox),
    :(Base.isless),
    :(Base.log),
    :(Base.max),
    :(Base.min),
    :(Base.sqrt),
    # Trigonomotry
    :(Base.acos),
    :(Base.acosh),
    :(Base.acot),
    :(Base.acoth),
    :(Base.acsc),
    :(Base.acsch),
    :(Base.asec),
    :(Base.asech),
    :(Base.asin),
    :(Base.asinh),
    :(Base.atan),
    :(Base.atanh),
    :(Base.cos),
    :(Base.cosh),
    :(Base.cot),
    :(Base.coth),
    :(Base.csc),
    :(Base.csch),
    :(Base.sec),
    :(Base.sech),
    :(Base.sin),
    :(Base.sinh),
    :(Base.tan),
    :(Base.tanh),
    # Iterator operations
    :(Base.broadcastable),
    :(Base.firstindex),
    :(Base.getindex),
    :(Base.iterate),
    :(Base.keys),
    :(Base.lastindex),
    :(Base.length),
    :(Base.pairs),
    :(Base.size),
    :(Base.values),
    # Linear algebra operations
    :(Base.adjoint),
    :(Base.transpose),
]
    @eval @inline $op(x::MetaAbstractPurse, ys...) = $op(value(x), map(value, ys)...)
    @eval @inline $op(x, y::MetaAbstractPurse, zs...) = $op(x, value(y), map(value, zs)...)
    @eval @inline function $op(x::MetaAbstractPurse, y::MetaAbstractPurse, zs...)
        return $op(value(x), value(y), map(value, zs)...)
    end
end

# We specifically do not define behaviour for `Base.setindex!` or other mutating functions,
# since they may invalidate the cache.
function Base.setindex!(::MetaAbstractPurse, ::Any, inds...)
    error("calling a mutating function with a purse is currently unsupported")
end


text:
#=
Example 2: LQ Ramsey model with discrete exogenous process.

@author : Spencer Lyon <spencer.lyon@nyu.edu>

@date: 2014-08-21

References
----------

Simple port of the file examples/lqramsey_discrete.py

http://quant-econ.net/lqramsey.html

=#
include("lqramsey.jl")

# Parameters
bet = 1 / 1.05
P = [0.8 0.2 0.0
     0.0 0.5 0.5
     0.0 0.0 1.0]

# Possible states of the world
# Each column is a state of the world. The rows are [g d b s 1]
x_vals = [0.5 0.5 0.25
          0.0 0.0 0.0
          2.2 2.2 2.2
          0.0 0.0 0.0
          1.0 1.0 1.0]
Sg = [1.0 0.0 0.0 0.0 0.0]
Sd = [0.0 1.0 0.0 0.0 0.0]
Sb = [0.0 0.0 1.0 0.0 0.0]
Ss = [0.0 0.0 0.0 1.0 0.0]
discrete = true
proc = DiscreteStochProcess(P, x_vals)

econ = Economy(bet, Sg, Sd, Sb, Ss, discrete, proc)
T = 15

path = compute_paths(econ, T)

gen_fig_1(path)

max_stars_repo_name: mwhchen/quantecon

max_issues_repo_name: mwhchen/quantecon

max_forks_repo_name: mwhchen/quantecon


text:
projected_pos = PVTSolution(
    ECEF([4.0187039543983485e6, 427061.6186769258, 4.9183106756403595e6]),
    -2.133206220402679e7,
    2.346849505593898)

@testset "Testing calc_PVT" begin
    user = calc_PVT(satellite_states)
    @test user.pos ≈ projected_pos.pos
    @test user.receiver_time_correction ≈ projected_pos.receiver_time_correction
    @test user.GDOP ≈ projected_pos.GDOP

    out = false
    try
        calc_PVT(satellite_states[1:3])
    catch e
        if typeof(e) == PositionVelocityTime.SmallData
            out = true
        end
    end
    @test out == true

    svs_bad = deepcopy(satellite_states)
    svs_bad[1].decoder_state.subframes_decoded = [0,0,0,0,0]
    svs_bad[2].decoder_state.subframes_decoded = [0,0,0,0,0]

    out = false
    try
        calc_PVT(svs_bad)
    catch e
        if typeof(e) == PositionVelocityTime.SmallData
            out = true
        end
    end
    @test out == true
end


text:
#' Eddy Covariance Data of AT-Neu (Neustift)
#'
#' Halfhourly eddy covariance Data of the site AT-Neu,
#'              a mountain meadow in Austria.
#'              (\url{http://sites_fluxdata_org/AT-Neu}).
#'              Data are from July 2010.
#'
#' @format A data frame with 1488 observations and 31 columns:
#'  \describe
#'    - year: year of measurement
#'    - month: month of measurement
#'    - doy: day of year
#'    - hour: hour (0 - 23.5)
#'    - Tair: Air temperature (degC) [TA_F]
#'    - Tair_qc: Quality control of `Tair` [TA_F_QC]
#'    - PPFD: Photosynthetic photon flux density (umol m-2 s-1) [PPFD_IN]
#'    - PPFD_qc: Quality control of `PPFD` [PPFD_IN_QC]
#'    - VPD: Vapor pressure deficit (kPa) [VPD_F]
#'    - VPD_qc: Quality control of `VPD` [VPD_F_QC]
#'    - pressure: Atmospheric pressure (kPa) [PA_F]
#'    - precip: precipitation (mm) [P_F]
#'    - precip_qc: Quality control of `precip` [P_F_QC]
#'    - ustar: friction velocity (m s-1) [USTAR]
#'    - wind: horizontal wind velocity (m s-1) [WS_F]
#'    - wind_qc: Quality control of `wind` [WS_F_QC]
#'    - Ca: CO2 concentration (ppm) [CO2_F_MDS]
#'    - Ca_qc: Quality control of `Ca` [CO2_F_MDS_QC]
#'    - LW_up: upward longwave radiation (W m-2) [LW_OUT]
#'    - Rn: Net radiation (W m-2) [NETRAD]
#'    - LE: Latent heat flux (W m-2) [LE_F_MDS]
#'    - LE_qc: Quality control of `LE` [LE_F_MDS_QC]
#'    - H: Sensible heat flux (W m-2) [H_F_MDS]
#'    - H_qc: Quality control of `H` [H_F_MDS_QC]
#'    - G: Ground heat flux (W m-2) [G_F_MDS]
#'    - G_qc: Quality control of `G` [G_F_MDS_QC]
#'    - NEE: Net ecosystem exchange (umol m-2 s-1) [NEE_VUT_USTAR50]
#'    - NEE_qc: Quality control of `NEE` [NEE_VUT_USTAR50_QC]
#'    - GPP: Gross primary productivity from nighttime partitioning (umol m-2 s-1) [GPP_NT_VUT_USTAR50]
#'    - GPP_qc: Quality control of `GPP` [NEE_VUT_USTAR50_QC]
#'    - Reco: Ecosystem respiration from nighttime partitioning (umol m-2 s-1) [RECO_NT_VUT_USTAR50]
#'  }
#'
#' # Note
#' The original variable names as provided by the FLUXNET2015 dataset are
#'       given in squared brackets. Note that variable units have been converted
#'       in some cases (e.g. VPD from hPa to kPa).
#'
#' @source original data were downloaded from
#'         \url{https://fluxnet_fluxdata_org/} (accessed 09 November 2016)
"AT_Neu_Jul_2010"

#' Eddy Covariance Data of DE-Tha (Tharandt)
#'
#' Halfhourly eddy covariance Data of the site DE-Tha,
#'              a spruce forest in Eastern Germany
#'              (\url{http://sites_fluxdata_org/DE-Tha}).
#'              Data are from June 2014.
#'
#' @format A data frame with 1440 observations and 32 columns:
#'  \describe
#'    - year: year of measurement
#'    - month: month of measurement
#'    - doy: day of year
#'    - hour: hour (0 - 23.5)
#'    - Tair: Air temperature (degC) [TA_F]
#'    - Tair_qc: Quality control of `Tair` [TA_F_QC]
#'    - PPFD: Photosynthetic photon flux density (umol m-2 s-1) [PPFD_IN]
#'    - PPFD_qc: Quality control of `PPFD` [PPFD_IN_QC]
#'    - VPD: Vapor pressure deficit (kPa) [VPD_F]
#'    - VPD_qc: Quality control of `VPD` [VPD_F_QC]
#'    - pressure: Atmospheric pressure (kPa) [PA_F]
#'    - precip: precipitation (mm) [P_F]
#'    - precip_qc: Quality control of `precip` [P_F_QC]
#'    - ustar: friction velocity (m s-1) [USTAR]
#'    - wind: horizontal wind velocity (m s-1) [WS_F]
#'    - wind_qc: Quality control of `wind` [WS_F_QC]
#'    - Ca: CO2 concentration (ppm) [CO2_F_MDS]
#'    - Ca_qc: Quality control of `Ca` [CO2_F_MDS_QC]
#'    - LW_up: upward longwave radiation (W m-2) [LW_OUT]
#'    - LW_down: downward longwave radiation (W m-2) [LW_IN_F]
#'    - Rn: Net radiation (W m-2) [NETRAD]
#'    - LE: Latent heat flux (W m-2) [LE_F_MDS]
#'    - LE_qc: Quality control of `LE` [LE_F_MDS_QC]
#'    - H: Sensible heat flux (W m-2) [H_F_MDS]
#'    - H_qc: Quality control of `H` [H_F_MDS_QC]
#'    - G: Ground heat flux (W m-2) [G_F_MDS]
#'    - G_qc: Quality control of `G` [G_F_MDS_QC]
#'    - NEE: Net ecosystem exchange (umol m-2 s-1) [NEE_VUT_USTAR50]
#'    - NEE_qc: Quality control of `NEE` [NEE_VUT_USTAR50_QC]
#'    - GPP: Gross primary productivity from nighttime partitioning (umol m-2 s-1) [GPP_NT_VUT_USTAR50]
#'    - GPP_qc: Quality control of `GPP` [NEE_VUT_USTAR50_QC]
#'    - Reco: Ecosystem respiration from nighttime partitioning (umol m-2 s-1) [RECO_NT_VUT_USTAR50]
#'  }
#'
#' # Note
#' The original variable names as provided by the FLUXNET2015 dataset are
#'       given in squared brackets. Note that variable units have been converted
#'       in some cases (e.g. VPD from hPa to kPa).
#'
#' @source original data were downloaded from
#'         \url{https://fluxnet_fluxdata_org/} (accessed 09 November 2016)
"DE_Tha_Jun_2014"

#' Eddy Covariance Data of FR-Pue (Puechabon)
#'
#' Halfhourly eddy covariance Data of the site FR-Pue,
#'              a Mediterranean evergreen oak forest in Southern France
#'              (\url{http://sites_fluxdata_org/FR-Pue}).
#'              Data are from May 2012.
#'
#' @format A data frame with 1488 observations and 29 columns:
#'  \describe
#'    - year: year of measurement
#'    - month: month of measurement
#'    - doy: day of year
#'    - hour: hour (0 - 23.5)
#'    - Tair: Air temperature (degC) [TA_F]
#'    - Tair_qc: Quality control of `Tair` [TA_F_QC]
#'    - PPFD: Photosynthetic photon flux density (umol m-2 s-1) [PPFD_IN]
#'    - PPFD_qc: Quality control of `PPFD` [PPFD_IN_QC]
#'    - VPD: Vapor pressure deficit (kPa) [VPD_F]
#'    - VPD_qc: Quality control of `VPD` [VPD_F_QC]
#'    - pressure: Atmospheric pressure (kPa) [PA_F]
#'    - precip: precipitation (mm) [P_F]
#'    - precip_qc: Quality control of `precip` [P_F_QC]
#'    - ustar: friction velocity (m s-1) [USTAR]
#'    - wind: horizontal wind velocity (m s-1) [WS_F]
#'    - wind_qc: Quality control of `wind` [WS_F_QC]
#'    - Ca: CO2 concentration (ppm) [CO2_F_MDS]
#'    - Ca_qc: Quality control of `Ca` [CO2_F_MDS_QC]
#'    - LW_up: upward longwave radiation (W m-2) [LW_OUT]
#'    - Rn: Net radiation (W m-2) [NETRAD]
#'    - LE: Latent heat flux (W m-2) [LE_F_MDS]
#'    - LE_qc: Quality control of `LE` [LE_F_MDS_QC]
#'    - H: Sensible heat flux (W m-2) [H_F_MDS]
#'    - H_qc: Quality control of `H` [H_F_MDS_QC]
#'    - NEE: Net ecosystem exchange (umol m-2 s-1) [NEE_VUT_USTAR50]
#'    - NEE_qc: Quality control of `NEE` [NEE_VUT_USTAR50_QC]
#'    - GPP: Gross primary productivity from nighttime partitioning (umol m-2 s-1) [GPP_NT_VUT_USTAR50]
#'    - GPP_qc: Quality control of `GPP` [NEE_VUT_USTAR50_QC]
#'    - Reco: Ecosystem respiration from nighttime partitioning (umol m-2 s-1) [RECO_NT_VUT_USTAR50]
#'  }
#'
#' # Note
#' The original variable names as provided by the FLUXNET2015 dataset are
#'       given in squared brackets. Note that variable units have been converted
#'       in some cases (e.g. VPD from hPa to kPa).
#'
#' @source original data were downloaded from
#'         \url{https://fluxnet_fluxdata_org/} (accessed 09 November 2016)
"FR_Pue_May_2012"


text:
# -*- coding: utf-8 -*-
# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .jl
#       format_name: light
#       format_version: '1.3'
#       jupytext_version: 1.0.4
#   kernelspec:
#     display_name: Julia 1.0.3
#     language: julia
#     name: julia-1.0
# ---

using SemanticModels
using SemanticModels.ModelTools
using SemanticModels.ModelTools.SimpleModels

import SemanticModels.ModelTools.SimpleModels: entrypoint, entryname, body
expr = quote
    module StatsMod
    using Statistics
    function foo(x)
        return x.^2
    end
    function bar(x,y)
        ρ = foo(x.-y)./(foo(x) .+ foo(y))
        return ρ
    end
    function main(n)
        x = rand(Float64, n)
        μ = mean(x)
        ρ = bar(x,μ)
        return x, ρ
    end
    end
end

m = model(SimpleModel, deepcopy(expr), :(main(n::Int)))

StatsMod = eval(m.expr)
StatsMod.main(10)

macro model(class, args...)
    expr = args[end]
    if expr.head == :block
        expr = expr.args[end]
    end

    ex = Expr(:nothing)
    expr = quote $expr end
    if length(args) > 1
        additional_args = args[1:end-1]
        ex = :(model($class, $expr, $additional_args...))
    else
        ex = :(model($class, $expr ))
    end
    return ex
end

m′ = @model SimpleModel main(n::Int64) quote
    module StatsMod
    using Statistics
    function foo(x)
        return x.^2
    end
    function bar(x,y)
        ρ = foo(x.-y)./(foo(x) .+ foo(y))
        return ρ
    end
    function main(n)
        x = rand(Float64, n)
        μ = mean(x)
        ρ = bar(x,μ)
        return x, ρ
    end
    end
end

m′.expr

m′.functions

m′.entry

Mod = eval(m′.expr)
getfield(Mod, entryname(m′))(10)


text:
"""
"""
function open_plots_during_tests(a::AbstractDict = ENV)
    result = lowercase(
        strip(
            get(a, "PREDICTMD_OPEN_PLOTS_DURING_TESTS", "")
            )
        ) == "true"
    return result
end


text:
abstract type Restart end

struct NoRestart<: Restart end

struct JSONRestart <: Restart
    filename::String
    freq::Int64
    io::IOStream
    function JSONRestart(filename::String,
                        freq::Int64)
        io=open(filename,"w")
        new(filename::String,
            freq::Int64,
            io::IOStream
        )
    end
end


text:
using DiffEqMonteCarlo, StochasticDiffEq, DiffEqBase,
      DiffEqProblemLibrary, OrdinaryDiffEq
using Test, Random, Statistics

using DiffEqProblemLibrary.SDEProblemLibrary: importsdeproblems; importsdeproblems()
import DiffEqProblemLibrary.SDEProblemLibrary: prob_sde_2Dlinear,
       prob_sde_additivesystem, prob_sde_lorenz
using DiffEqProblemLibrary.ODEProblemLibrary: importodeproblems; importodeproblems()
import DiffEqProblemLibrary.ODEProblemLibrary: prob_ode_linear

prob = prob_sde_2Dlinear
prob2 = MonteCarloProblem(prob)
sim = solve(prob2,SRIW1(),dt=1//2^(3),num_monte=10)
sim = solve(prob2,SRIW1(),dt=1//2^(3),num_monte=10,parallel_type=:threads)
sim = solve(prob2,SRIW1(),DiffEqMonteCarlo.MonteThreads(),dt=1//2^(3),num_monte=10)
err_sim = DiffEqBase.calculate_monte_errors(sim;weak_dense_errors=true)
@test length(sim) == 10

sim = solve(prob2,SRIW1(),DiffEqMonteCarlo.MonteThreads(),dt=1//2^(3),adaptive=false,num_monte=10)
err_sim = DiffEqBase.calculate_monte_errors(sim;weak_timeseries_errors=true)

sim = solve(prob2,SRIW1(),DiffEqMonteCarlo.MonteThreads(),dt=1//2^(3),num_monte=10)
DiffEqBase.calculate_monte_errors(sim)
@test length(sim) == 10

sim = solve(prob2,SRIW1(),DiffEqMonteCarlo.MonteSplitThreads(),dt=1//2^(3),num_monte=10)
DiffEqBase.calculate_monte_errors(sim)
@test length(sim) == 10

sim = solve(prob2,SRIW1(),DiffEqMonteCarlo.MonteSerial(),dt=1//2^(3),num_monte=10)
DiffEqBase.calculate_monte_errors(sim)
@test length(sim) == 10

prob = prob_sde_additivesystem
prob2 = MonteCarloProblem(prob)
sim = solve(prob2,SRA1(),dt=1//2^(3),num_monte=10)
DiffEqBase.calculate_monte_errors(sim)

output_func = function (sol,i)
  last(last(sol))^2,false
end
prob2 = MonteCarloProblem(prob,output_func=output_func)
sim = solve(prob2,SRA1(),dt=1//2^(3),num_monte=10)

prob = prob_sde_lorenz
prob2 = MonteCarloProblem(prob)
sim = solve(prob2,SRIW1(),dt=1//2^(3),num_monte=10)

output_func = function (sol,i)
  last(sol),false
end

prob = prob_ode_linear
prob_func = function (prob,i,repeat)
  ODEProblem(prob.f,rand()*prob.u0,prob.tspan,1.01)
end

Random.seed!(100)
reduction = function (u,batch,I)
  u = append!(u,batch)
  u,((var(u)/sqrt(last(I)))/mean(u)<0.5) ? true : false
end

prob2 = MonteCarloProblem(prob,prob_func=prob_func,output_func=output_func,reduction=reduction,u_init=Vector{Float64}())
sim = solve(prob2,Tsit5(),num_monte=10000,batch_size=20)
@test sim.converged == true

Random.seed!(100)
reduction = function (u,batch,I)
  u = append!(u,batch)
  u,false
end

prob2 = MonteCarloProblem(prob,prob_func=prob_func,output_func=output_func,reduction=reduction,u_init=Vector{Float64}())
sim = solve(prob2,Tsit5(),num_monte=100,batch_size=20)
@test sim.converged == false

Random.seed!(100)
reduction = function (u,batch,I)
  u+sum(batch),false
end
prob2 = MonteCarloProblem(prob,prob_func=prob_func,output_func=output_func,reduction=reduction,u_init=0.0)
sim2 = solve(prob2,Tsit5(),num_monte=100,batch_size=20)
@test sim2.converged == false
@test mean(sim.u) ≈ sim2.u/100

struct SomeUserType end
output_func = function (sol,i)
    (SomeUserType(),false)
end
prob2 = MonteCarloProblem(prob,prob_func=prob_func,output_func=output_func)
sim2 = solve(prob2,Tsit5(),num_monte=2)
@test !sim2.converged && typeof(sim2.u) == Vector{SomeUserType}


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

using Markdown
using InteractiveUtils

# ╔═╡ 7d0e3452-aff5-11ec-0675-bb8d03a2aff3
using CSV, DataFrames, Glob, Measures

# ╔═╡ 79a18654-7a71-4392-b2b0-dbc2ac4f1527
begin
	using Plots
	theme(:ggplot2)
	gr()
end

# ╔═╡ 6e04bd62-cc5c-4f1d-834c-a5944a4e601c
using LinearAlgebra, Distributions

# ╔═╡ 3a24c99f-0a6f-440c-af77-a2c364286296
md"""
# Category Distributions
"""

# ╔═╡ 77e650f3-fa34-4dd7-ba66-2183d6b09d19
struct Category
	name::Symbol
	dist::Distribution
end

# ╔═╡ c5a14200-d383-4247-a7a9-b653a83a71e1
begin
	"""
		TactileObject(label::Symbol, sides::Real, dots::Real)
	Tactile Object called label with two features, sides and dots

		Tactileobject(label::Symbol, feat_dist::Distribution, feat_ranges)
	Tactile Object called label constructed from bounded feature distributions

		TactileObject(category::Category, feat_ranges)
	Tactile Object in category with bounded features
	"""
	struct TactileObject
		category::Symbol
		sides::Real
		dots::Real
		# Alternative methods to construct a TactileObject
		TactileObject(label::Symbol, sides::Real, dots::Real) = new(label, sides, dots)
		TactileObject(label::Symbol, feat_dist::Distribution) = new(label, rand(feat_dist)...)
		function TactileObject(label::Symbol, feat_dist::Distribution, feat_ranges)
			sides, dots = rand(feat_dist)
			sides = clamp(sides, extrema(feat_ranges.sides)...)
			dots = clamp(dots, extrema(feat_ranges.dots)...)
			return new(label, sides, dots)
		end
		TactileObject(category::Category, feat_ranges) = TactileObject(category.name, category.dist, feat_ranges)
	end

	# Pretty print TactileObject
	Base.show(io::IO, tactobj::TactileObject) = print(io, "$(tactobj.category) with Sides: $(tactobj.sides), Dots: $(tactobj.dots)")

	"""
		get_feats(tactobj::TactileObject)

	Returns features (sides & dots) of Tactile Object as a tuple
	"""
	function get_feats(tactobj::TactileObject)
		return tactobj.sides, tactobj.dots
	end
end

# ╔═╡ 0befab8a-8bc9-46f9-93ad-aef57c016f06
begin
	feat_ranges = (sides=6:10, dots=4:8)
	feat_ranges
end

# ╔═╡ d71cf3fd-9e64-4001-8963-e5d2539387d1
begin
	# Mean Sides, Dots
	elyk_μ = [7.0, 5.0]
	# Stdev Sides, Dots
	elyk_Σ = (1.5^2)I
	# Elyk Object Distribution
	elyk_dist = MvNormal(elyk_μ, elyk_Σ)

	elyk = Category(:elyk, elyk_dist)
end

# ╔═╡ fd37e561-6ef8-427f-b7ef-66168673c617
begin
	res = 1
	sides_ax = range(extrema(feat_ranges.sides)..., step=res)
	dots_ax = range(extrema(feat_ranges.dots)..., step=res)

	elyk_pdf = [pdf(elyk_dist, [side, dot]) for side in sides_ax, dot in dots_ax]

	Plots.heatmap(sides_ax, dots_ax, elyk_pdf,
    	xlabel="Sides",
		ylabel="Dots (mm)",
    	title="Elyk Distribution",
	)
end

# ╔═╡ a2d57bed-0cf3-4895-a1ce-a7113bddd7de
begin
	# Sides, Dots mean
	noek_μ = [9.0, 7.0]
	# Sides, Dots stdev
	noek_Σ = (1.5^2)I
	# Noek Object Distribution
	noek_dist = MvNormal(noek_μ, noek_Σ)

	noek = Category(:noek, noek_dist)
end

# ╔═╡ 37af3db1-2e23-4637-ae27-5f2c73d520e5
begin
	noek_pdf = [pdf(noek_dist, [side, dot]) for side in sides_ax, dot in dots_ax]

	Plots.heatmap(sides_ax, dots_ax, noek_pdf,
    	xlabel="Sides",
		ylabel="Dots (mm)",
    	title="Noek Distribution",
	)
end

# ╔═╡ 58e30adf-d2b7-45ca-9ea8-578dc48f7d71
md"""
# Data Analysis
"""

# ╔═╡ e062bc9c-f51e-42d2-919d-246adbb55373
function get_csv(dir_with_csvs::String)
    ispath(dir_with_csvs) || error("Could not find path: $dir_with_csvs")
    csv_files = glob("*csv", dir_with_csvs)
    return csv_files
end

# ╔═╡ 81fafb11-a4d4-493b-a9bb-acbfdd38515a
function get_categorization_data(exp_dir)
    ispath(exp_dir) || error("Could not find path: $exp_dir")
	# p = participant
	p_dirs = readdir(exp_dir, join=true)
	p_data = [CSV.read(get_csv(p_dir), DataFrame) for p_dir in p_dirs]
	return p_data
end

# ╔═╡ daf71960-3d51-4989-b977-0644eb2a1875
function filter_p_data(all_p_data, cols_to_keep)
	return [p_data[:, cols_to_keep] for p_data in all_p_data]
end

# ╔═╡ 3afb7a95-6dc2-43d8-b121-a8eed4ae1b04
readdir("./categorizationdata")

# ╔═╡ f88c2324-935e-4def-b79c-cb4144e39921
all_p_data = get_categorization_data("./categorizationdata")

# ╔═╡ 1c4e653f-4df8-4804-9d75-b53383eaa756
p_dfs = filter_p_data(all_p_data, [:Sides, :Spacing, :Response, Symbol("Correct.")])

# ╔═╡ d5cc4ade-f6ee-4820-8d91-e5ad47269c3e
function df_to_dict(p_df)
	coordinates = [Dict([]), Dict([])]
	for row in eachrow(p_df)
		coord = (sides=row.Sides+6, dots=row.Spacing+4)
		response = row.Response
		if haskey(coordinates[response], coord)
			coordinates[response][coord] += 1
		else
			coordinates[response][coord] = 1
		end
	end

	# Calculate response probability

	# Iterate the longer dictionary
	longer_coordinates = length(coordinates[1]) > length(coordinates[2]) ? coordinates[1] : coordinates[2]

	shorter_coordinates = length(coordinates[1]) < length(coordinates[2]) ? coordinates[1] : coordinates[2]

	for k in keys(longer_coordinates)
		if !haskey(shorter_coordinates, k)
			# If this coordinate was never given other response 1, then 100% of time it was given response 2
			longer_coordinates[k] = 1.0
		else
			# Find total responses
			total_responses = longer_coordinates[k] + shorter_coordinates[k]
			longer_coordinates[k] /= total_responses
			shorter_coordinates[k] /= total_responses
		end
	end

	# Normalize all remaining keys in shorter_coordinates
	for k in keys(shorter_coordinates)
		if !haskey(longer_coordinates, k)
			shorter_coordinates[k] = 1.0
		end
	end
	return (res1=longer_coordinates, res2=shorter_coordinates)
end

# ╔═╡ 2588019b-7709-4e3e-9304-20bbc752ed31
begin
	test = Dict([(sides=2, dots=3)=>1])
	test[(sides=2, dots=3)] += 4
end

# ╔═╡ 06119f97-7405-4591-a080-7f2f4bbf59e5
all_p_probabilities = [df_to_dict(p_df) for p_df in p_dfs]

# ╔═╡ c88c8b35-99ba-4873-8a1d-db02bac8dbde
begin
	function dict_to_heatmap(p_prob_res, label)
		xs = collect(6:10)
		ys = collect(4:8)
		zs = zeros(length(xs), length(ys))
		for x in xs, y in ys
			if haskey(p_prob_res, (sides=x, dots=y))
				zs[x-5, y-3] = p_prob_res[(sides=x, dots=y)]
			end
		end
		resmap = Plots.heatmap(xs, ys, zs,
		    xlabel="Sides",
			ylabel="Dots (mm)",
	    	title="$label",
			margin=5mm
		)
		return resmap
	end

	function both_maps(p_prob)
		resmap1 = dict_to_heatmap(p_prob.res1, "Elyk")
		resmap2 = dict_to_heatmap(p_prob.res2, "Noek")

		p = Plots.plot(resmap1, resmap2, layout=2, plot_title="Participant Category Distribution", plot_titlefontsize=12, titlefontsize=10, size=(800, 300))
		return resmap1
	end
end

# ╔═╡ 80f06c64-fbd4-4a41-9eb6-816a7974a7ab
both_maps(all_p_probabilities[1])

# ╔═╡ 560ef6fc-06bc-4f26-a305-155a661ae29d
function p_dict_to_heatmap(p_probs)
	# Just ELyk
	p_zs = []
	xs = collect(6:10)
	ys = collect(4:8)
	for p_prob in p_probs
		zs = zeros(length(xs), length(ys))
		for x in xs, y in ys
			if haskey(p_prob.res1, (sides=x, dots=y))
				zs[x-5, y-3] = p_prob.res1[(sides=x, dots=y)]
			end
		end
		push!(p_zs, zs)
	end

	mean_zs = mean(p_zs)

	avgmap = Plots.heatmap(xs, ys, mean_zs,
		xlabel="Sides",
		ylabel="Dots (mm)",
		title="Mean Participant Elyk",
		margin=5mm
	)
	return avgmap
end

# ╔═╡ 29a226d0-bcb8-4bd8-9bfa-712044bd7dbd
p_dict_to_heatmap(all_p_probabilities)

# ╔═╡ ef69b242-4a96-4480-8c87-89677c3c2a1c
md"""
# Encoders & Decoders
"""

# ╔═╡ 4f21f20f-b677-4d7a-bc98-49e41ced32e3
function encode(stimulus::TactileObject, Σ_encoder)
	sensation_dist = MvNormal([stimulus.sides, stimulus.dots], Σ_encoder)
	sides, dots = rand(sensation_dist)
	return TactileObject(:object, sides, dots)
end

# ╔═╡ 981676e0-d852-4781-b7fd-3817a77cb872
"""
	decode_sense(sensations, Σ_encoder, feat_ranges)

Given set of stochastic sensations (i.e. encodings) of a stimulus, infer the most likely true features of the stimulus
"""
function decode_sense(sensations::Vector{T}, Σ_encoder, feat_ranges) where {T<:TactileObject}
	# Hypothesize several possible true stimulus values
	step = 0.1
	sides_hyp = range(extrema(feat_ranges.sides)..., step=step)
	dots_hyp = range(extrema(feat_ranges.dots)..., step=step)
	μ_hyps = [[side, dot] for side in sides_hyp, dot in dots_hyp]

	# Assume uniform prior for μ_hyps
	# prior = 1 / length(μ_hyps)

	# Calculate likelihood of sensed stimulus given hypotheses
	# 	Assume decoder knows the variability of the encoder
	data_loglikelihood(μ, stimuli) = sum(logpdf(Distributions.MvNormal(μ, Σ_encoder), collect(get_feats(sensation))) for sensation in sensations)

	loglikelihoods = [data_loglikelihood(μ, sensations) for μ in μ_hyps]
	likelihoods = exp.(loglikelihoods .- maximum(loglikelihoods))

	# Calculate most probable true stimulus values
	posteriors = likelihoods ./ sum(likelihoods)
	estimated_features = μ_hyps[argmax(posteriors)]
	return TactileObject(:object, estimated_features...)
end

# ╔═╡ bbf5078d-030c-46e8-bc30-eeddf43a0d2e
"""
	decode_category(stimulus, Σ_category)

Given a stimulus from a stochastic category distribution, infer the most likely true category of the stimulus
"""
function decode_category(stimulus::TactileObject, Σ_category)
	stimulus_feats = collect(get_feats(stimulus))
	# Calculate likelihoods
	loglikelihoods = [
		logpdf(Distributions.MvNormal(mean(elyk_dist), Σ_category), stimulus_feats),
		logpdf(Distributions.MvNormal(mean(noek_dist), Σ_category), stimulus_feats)
	]
	category_likelihoods = exp.(loglikelihoods .- maximum(loglikelihoods))
	# Calculate posteriors
	category_posteriors = category_likelihoods ./ sum(category_likelihoods)
	p_elyk, p_noek = category_posteriors
	return (elyk = round(p_elyk; digits=3), noek = round(p_noek; digits=3))
end

# ╔═╡ 91000689-45ac-474d-899a-2b691e3465f5
md"""
Bayesian Models
"""

# ╔═╡ a2caabf5-cec7-4a02-8014-6f247d37f700
struct ModelParams
	feat_ranges::NamedTuple
	num_encodings::Integer
	Σ_encoder
	Σ_category
end

# ╔═╡ 845655a2-fd26-45c6-b696-ad563a50c86b
begin
	function model_debug(stimulus::TactileObject, decoded_stim, decoded_cat)
		@show stimulus
		@show decoded_stim
		@show decoded_cat
		return
	end
end

# ╔═╡ 5334c8d1-6cd6-434a-9b0f-7664bee0e94b
"""
	model1(stimulus::TactileObject, params::ModelParams)

Decoder model that only takes into account sensory variability.

When making inferences, the model assumes Σ_category is sufficiently small to ignore.
"""
function model1(stimulus::TactileObject, params::ModelParams; debug=false)
	# Sense stimulus
	sensations = [encode(stimulus, params.Σ_encoder) for _=1:params.num_encodings]
	# Incorporate sensory variability
	estimated_stimulus = decode_sense(sensations, params.Σ_encoder, params.feat_ranges)
	# Assume sufficiently small category varibility
	assumed_Σ_category = (0.01^2)I
	estimated_category = decode_category(estimated_stimulus, assumed_Σ_category)
	debug && model_debug(stimulus, estimated_stimulus, estimated_category)
	return estimated_category
end

# ╔═╡ 0052708e-2d81-4b08-af51-3179addb0c00
"""
	model2(stimulus::TactileObject, params::ModelParams)

Decoder model that only takes into account category variability.

When making inferences, the model assumes Σ_encoder is sufficiently small to ignore.
"""
function model2(stimulus::TactileObject, params::ModelParams; debug=false)
	# Sense stimulus
	sensations = [encode(stimulus, params.Σ_encoder) for _=1:params.num_encodings]
	# Assume sufficiently small sensory varibility
	assumed_Σ_encoder = 0.001I
	estimated_stimulus = decode_sense(sensations, assumed_Σ_encoder, params.feat_ranges)
	# Incorporate category variability
	estimated_category = decode_category(estimated_stimulus, params.Σ_category)
	debug && model_debug(stimulus, estimated_stimulus, estimated_category)
	return estimated_category
end

# ╔═╡ 5b516aa4-5466-4b92-95c0-17d284797044
"""
	model3(stimulus::TactileObject, params::ModelParams)

Decoder model that takes into account category and sensory variability; an optimal Bayesian decoder
"""
function model3(stimulus::TactileObject, params::ModelParams; debug=false)
	# Sense stimulus
	sensations = [encode(stimulus, params.Σ_encoder) for _=1:params.num_encodings]
	# Incorporate sensory variability
	estimated_stimulus = decode_sense(sensations, params.Σ_encoder, params.feat_ranges)
	# Incorporate category variability
	estimated_category = decode_category(estimated_stimulus, params.Σ_category)
	debug && model_debug(stimulus, estimated_stimulus, estimated_category)
	return estimated_category
end

# ╔═╡ a5453d7c-8348-4d3a-8df2-9168c029bc80
md"""
# Categorization Experiment With Decoders
"""

# ╔═╡ e1ea0852-4473-4368-b249-ead09195b22c
function category_experiment(model, model_params, runs)
	# Define sides and dots ranges (x & y axes)
	xs = collect(feat_ranges.sides)
	ys = collect(feat_ranges.dots)
	# Allocate z axis arrays for elyk and noek
	zs_elyk = zeros(length(xs), length(ys))
	zs_noek = zeros(length(xs), length(ys))
	for x in xs, y in ys
		# For a particular combination of sides and dots:
		elyk_responses = 0
		noek_responses = 0
		stimulus = TactileObject(:object, x, y)
		# Run many trials of the experiment
		for i in 1:runs
			# Just in case the model spits out 50/50, force it to make a decision
			response = nothing
			while true
				# model return tuple of category probabilities
				# 	(elyk=0.79, noek=0.21), so argmax returns the category symbol
				response = argmax(model(stimulus, model_params))
				response == 0.5 || break
			end
			if response == :elyk
				elyk_responses += 1
			elseif response == :noek
				noek_responses += 1
			end
		end
		zs_elyk[x-5, y-3] = elyk_responses / runs
		zs_noek[x-5, y-3] = noek_responses / runs
	end
	# Plotting
	elyk_map = Plots.heatmap(xs, ys, zs_elyk,
		xlabel="Sides",
		ylabel="Dots (mm)",
		title="$(Symbol(model)) Elyk",
		margin=5mm
	)

	noek_map = Plots.heatmap(xs, ys, zs_noek,
		xlabel="Sides",
		ylabel="Dots (mm)",
		title="Noek",
		margin=5mm
	)

	# Plot both together

	p = Plots.plot(elyk_map, noek_map, layout=2, plot_title="$(Symbol(model)) Category Distribution", plot_titlefontsize=12, titlefontsize=10, size=(800, 300))
	return elyk_map
end

# ╔═╡ c26d946f-9df5-4d14-a3d5-18fd44b8fa49
begin
	model_params = ModelParams(feat_ranges, 3, Diagonal([1.2^2, 1.4^2]), cov(elyk_dist))
end

# ╔═╡ 5790dfae-bb09-4a08-a768-72aa1cbc7e19
category_experiment(model1, model_params, 20)

# ╔═╡ 762aa7a5-fcba-450d-836a-9a3dddedeab3
category_experiment(model2, model_params, 20)

# ╔═╡ c6c647fc-840d-4ebc-aaeb-403fbdd982e6
category_experiment(model3, model_params, 20)

# ╔═╡ 7b55a52f-90ad-4218-a8b8-4fd70035baf5
σ

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
Glob = "c27321d9-0574-5035-807b-f59d2c89b15c"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"

[compat]
CSV = "~0.10.3"
DataFrames = "~1.3.2"
Distributions = "~0.25.53"
Glob = "~1.3.0"
Measures = "~0.3.1"
Plots = "~1.27.3"
"""

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

julia_version = "1.7.2"
manifest_format = "2.0"

[[deps.Adapt]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "af92965fb30777147966f58acb05da51c5616b5f"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "3.3.3"

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

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

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

[[deps.Bzip2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2"
uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
version = "1.0.8+0"

[[deps.CSV]]
deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings"]
git-tree-sha1 = "9310d9495c1eb2e4fa1955dd478660e2ecab1fbb"
uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
version = "0.10.3"

[[deps.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 = "4b859a208b2397a7a623a03449e4636bdb17bcf2"
uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
version = "1.16.1+1"

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

[[deps.ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "9950387274246d08af38f6eef8cb5480862a435f"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "1.14.0"

[[deps.ChangesOfVariables]]
deps = ["ChainRulesCore", "LinearAlgebra", "Test"]
git-tree-sha1 = "bf98fa45a0a4cee295de98d4c1462be26345b9a1"
uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0"
version = "0.1.2"

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

[[deps.ColorSchemes]]
deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"]
git-tree-sha1 = "12fc73e5e0af68ad3137b886e3f7c1eacfca2640"
uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
version = "3.17.1"

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

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

[[deps.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 = "96b0bc6c52df76506efc8a441c6cf1adcb1babc4"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.42.0"

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

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

[[deps.Crayons]]
git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15"
uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
version = "4.1.1"

[[deps.DataAPI]]
git-tree-sha1 = "cc70b17275652eb47bc9e5f81635981f13cea5c8"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.9.0"

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

[[deps.DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
git-tree-sha1 = "3daef5523dd2e769dad2365274f760ff5f282c7d"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
version = "0.18.11"

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

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

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

[[deps.DensityInterface]]
deps = ["InverseFunctions", "Test"]
git-tree-sha1 = "80c3e8639e3353e5d2912fb3a1916b8455e2494b"
uuid = "b429d917-457f-4dbc-8f4c-0cc954292b1d"
version = "0.4.0"

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

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

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

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

[[deps.DualNumbers]]
deps = ["Calculus", "NaNMath", "SpecialFunctions"]
git-tree-sha1 = "5837a837389fccf076445fce071c8ddaea35a566"
uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74"
version = "0.6.8"

[[deps.EarCut_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "3f3a2501fa7236e9b911e0f7a588c657e822bb6d"
uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5"
version = "2.2.3+0"

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

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

[[deps.FFMPEG_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_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 = "d8a578692e3077ac998b50c0217dfd67f21d1e5f"
uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5"
version = "4.4.0+0"

[[deps.FilePathsBase]]
deps = ["Compat", "Dates", "Mmap", "Printf", "Test", "UUIDs"]
git-tree-sha1 = "129b104185df66e408edd6625d480b7f9e9823a0"
uuid = "48062228-2e41-5def-b9a4-89aafe57970f"
version = "0.9.18"

[[deps.FillArrays]]
deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"]
git-tree-sha1 = "246621d23d1f43e3b9c368bf3b72b2331a27c286"
uuid = "1a297f60-69ca-5386-bcde-b61e274b549b"
version = "0.13.2"

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

[[deps.Fontconfig_jll]]
deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03"
uuid = "a3f928ae-7b40-5064-980b-68af3947d34b"
version = "2.13.93+0"

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

[[deps.FreeType2_jll]]
deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9"
uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7"
version = "2.10.4+0"

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

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

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

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

[[deps.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 = "83578392343a7885147726712523c39edc714956"
uuid = "d2c73de3-f751-5644-a686-071e5b155ba9"
version = "0.64.1+0"

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

[[deps.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"

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

[[deps.Glob]]
git-tree-sha1 = "4df9f7e06108728ebf00a0a11edee4b29a482bb2"
uuid = "c27321d9-0574-5035-807b-f59d2c89b15c"
version = "1.3.0"

[[deps.Graphite2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011"
uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472"
version = "1.3.14+0"

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

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

[[deps.HarfBuzz_jll]]
deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"]
git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3"
uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566"
version = "2.8.1+1"

[[deps.HypergeometricFunctions]]
deps = ["DualNumbers", "LinearAlgebra", "SpecialFunctions", "Test"]
git-tree-sha1 = "65e4589030ef3c44d3b90bdc5aac462b4bb05567"
uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a"
version = "0.3.8"

[[deps.IniFile]]
git-tree-sha1 = "f550e6e32074c939295eb5ea6de31849ac2c9625"
uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f"
version = "0.5.1"

[[deps.InlineStrings]]
deps = ["Parsers"]
git-tree-sha1 = "61feba885fac3a407465726d0c330b3055df897f"
uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48"
version = "1.1.2"

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

[[deps.InverseFunctions]]
deps = ["Test"]
git-tree-sha1 = "91b5dcf362c5add98049e6c29ee756910b03051d"
uuid = "3587e190-3f89-42d0-90ee-14403ec27112"
version = "0.1.3"

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

[[deps.IrrationalConstants]]
git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151"
uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
version = "0.1.1"

[[deps.IterTools]]
git-tree-sha1 = "fa6287a4469f5e048d763df38279ee729fbd44e5"
uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
version = "1.4.0"

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

[[deps.JLLWrappers]]
deps = ["Preferences"]
git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.4.1"

[[deps.JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.3"

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

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

[[deps.LERC_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434"
uuid = "88015f11-f218-50d7-93a8-a6af411a945d"
version = "3.0.0+1"

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

[[deps.LaTeXStrings]]
git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996"
uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
version = "1.3.0"

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

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

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

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

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

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

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

[[deps.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"

[[deps.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"

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

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

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

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

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

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

[[deps.LogExpFunctions]]
deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"]
git-tree-sha1 = "58f25e56b706f95125dcb796f39e1fb01d913a71"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.3.10"

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

[[deps.MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.9"

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

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

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

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

[[deps.Missings]]
deps = ["DataAPI"]
git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f"
uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
version = "1.0.2"

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

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

[[deps.NaNMath]]
git-tree-sha1 = "737a5957f387b17e74d4ad2f440eb330b39a62c5"
uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
version = "1.0.0"

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

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

[[deps.OpenBLAS_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"

[[deps.OpenLibm_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "05823500-19ac-5b8b-9628-191a04bc5112"

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

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

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

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

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

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

[[deps.Parsers]]
deps = ["Dates"]
git-tree-sha1 = "85b5da0fa43588c75bb1ff986493443f821c70b7"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.2.3"

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

[[deps.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"

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

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

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

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

[[deps.Preferences]]
deps = ["TOML"]
git-tree-sha1 = "d3538e7f8a790dc8903519090857ef8e1283eecd"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.5"

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

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

[[deps.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"

[[deps.QuadGK]]
deps = ["DataStructures", "LinearAlgebra"]
git-tree-sha1 = "78aadffb3efd2155af139781b8a8df1ef279ea39"
uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
version = "2.4.2"

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

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

[[deps.RecipesBase]]
git-tree-sha1 = "6bf3f380ff52ce0832ddd3a2a7b9538ed1bcca7d"
uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
version = "1.2.1"

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

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

[[deps.RelocatableFolders]]
deps = ["SHA", "Scratch"]
git-tree-sha1 = "cdbd3b1338c72ce29d9584fdbe9e9b70eeb5adca"
uuid = "05181044-ff0b-4ac5-8273-598c1e38db00"
version = "0.1.3"

[[deps.Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.3.0"

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

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

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

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

[[deps.SentinelArrays]]
deps = ["Dates", "Random"]
git-tree-sha1 = "6a2f7d70512d205ca8c7ee31bfa9f142fe74310c"
uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c"
version = "1.3.12"

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

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

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

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

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

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

[[deps.SpecialFunctions]]
deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"]
git-tree-sha1 = "5ba658aeecaaf96923dce0da9e703bd1fe7666f9"
uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
version = "2.1.4"

[[deps.StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "4f6ec5d99a28e1a749559ef7dd518663c5eca3d5"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.4.3"

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

[[deps.StatsAPI]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "c3d8ba7f3fa0625b062b82853a7d5229cb728b6b"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.2.1"

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

[[deps.StatsFuns]]
deps = ["ChainRulesCore", "HypergeometricFunctions", "InverseFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"]
git-tree-sha1 = "25405d7016a47cf2bd6cd91e66f4de437fd54a07"
uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
version = "0.9.16"

[[deps.StructArrays]]
deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"]
git-tree-sha1 = "57617b34fa34f91d536eb265df67c2d4519b8b98"
uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a"
version = "0.6.5"

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

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

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

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

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

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

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

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

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

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

[[deps.UnicodeFun]]
deps = ["REPL"]
git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf"
uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1"
version = "0.4.1"

[[deps.Unzip]]
git-tree-sha1 = "34db80951901073501137bdbc3d5a8e7bbd06670"
uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d"
version = "0.1.2"

[[deps.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"

[[deps.Wayland_protocols_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4528479aa01ee1b3b4cd0e6faef0e04cf16466da"
uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91"
version = "1.25.0+0"

[[deps.WeakRefStrings]]
deps = ["DataAPI", "InlineStrings", "Parsers"]
git-tree-sha1 = "b1be2855ed9ed8eac54e5caff2afcdb442d52c23"
uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5"
version = "1.4.2"

[[deps.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"

[[deps.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"

[[deps.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"

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

[[deps.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"

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

[[deps.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"

[[deps.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"

[[deps.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"

[[deps.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"

[[deps.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"

[[deps.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"

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

[[deps.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"

[[deps.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"

[[deps.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"

[[deps.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"

[[deps.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"

[[deps.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"

[[deps.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"

[[deps.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"

[[deps.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"

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

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

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

[[deps.libass_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47"
uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0"
version = "0.15.1+0"

[[deps.libblastrampoline_jll]]
deps = ["Artifacts", "Libdl", "OpenBLAS_jll"]
uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"

[[deps.libfdk_aac_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55"
uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280"
version = "2.0.2+0"

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

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

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

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

[[deps.x264_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2"
uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a"
version = "2021.5.5+0"

[[deps.x265_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9"
uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76"
version = "3.5.0+0"

[[deps.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:
# ╠═7d0e3452-aff5-11ec-0675-bb8d03a2aff3
# ╠═79a18654-7a71-4392-b2b0-dbc2ac4f1527
# ╠═6e04bd62-cc5c-4f1d-834c-a5944a4e601c
# ╠═3a24c99f-0a6f-440c-af77-a2c364286296
# ╠═77e650f3-fa34-4dd7-ba66-2183d6b09d19
# ╠═c5a14200-d383-4247-a7a9-b653a83a71e1
# ╠═0befab8a-8bc9-46f9-93ad-aef57c016f06
# ╠═d71cf3fd-9e64-4001-8963-e5d2539387d1
# ╠═fd37e561-6ef8-427f-b7ef-66168673c617
# ╠═a2d57bed-0cf3-4895-a1ce-a7113bddd7de
# ╠═37af3db1-2e23-4637-ae27-5f2c73d520e5
# ╠═58e30adf-d2b7-45ca-9ea8-578dc48f7d71
# ╠═e062bc9c-f51e-42d2-919d-246adbb55373
# ╠═81fafb11-a4d4-493b-a9bb-acbfdd38515a
# ╠═daf71960-3d51-4989-b977-0644eb2a1875
# ╠═3afb7a95-6dc2-43d8-b121-a8eed4ae1b04
# ╠═f88c2324-935e-4def-b79c-cb4144e39921
# ╠═1c4e653f-4df8-4804-9d75-b53383eaa756
# ╠═d5cc4ade-f6ee-4820-8d91-e5ad47269c3e
# ╠═2588019b-7709-4e3e-9304-20bbc752ed31
# ╠═06119f97-7405-4591-a080-7f2f4bbf59e5
# ╠═c88c8b35-99ba-4873-8a1d-db02bac8dbde
# ╠═80f06c64-fbd4-4a41-9eb6-816a7974a7ab
# ╠═560ef6fc-06bc-4f26-a305-155a661ae29d
# ╠═29a226d0-bcb8-4bd8-9bfa-712044bd7dbd
# ╠═ef69b242-4a96-4480-8c87-89677c3c2a1c
# ╠═4f21f20f-b677-4d7a-bc98-49e41ced32e3
# ╠═981676e0-d852-4781-b7fd-3817a77cb872
# ╠═bbf5078d-030c-46e8-bc30-eeddf43a0d2e
# ╠═91000689-45ac-474d-899a-2b691e3465f5
# ╠═a2caabf5-cec7-4a02-8014-6f247d37f700
# ╠═845655a2-fd26-45c6-b696-ad563a50c86b
# ╠═5334c8d1-6cd6-434a-9b0f-7664bee0e94b
# ╠═0052708e-2d81-4b08-af51-3179addb0c00
# ╠═5b516aa4-5466-4b92-95c0-17d284797044
# ╠═a5453d7c-8348-4d3a-8df2-9168c029bc80
# ╠═e1ea0852-4473-4368-b249-ead09195b22c
# ╠═c26d946f-9df5-4d14-a3d5-18fd44b8fa49
# ╠═5790dfae-bb09-4a08-a768-72aa1cbc7e19
# ╠═762aa7a5-fcba-450d-836a-9a3dddedeab3
# ╠═c6c647fc-840d-4ebc-aaeb-403fbdd982e6
# ╠═7b55a52f-90ad-4218-a8b8-4fd70035baf5
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


text:
export post_process

function post_process(data::SyntheticData, model::Model, J::Int64, statehist::Array{Array{Float64,2},1})
    Ne = size(statehist[1],2)
    @show Ne
    # Post_process compute the statistics (mean, median, and
    # standard deviation) of the RMSE, spread and coverage
    # probability over (J-T_BurnIn) assimilation steps.

    # enshist contains the initial condition, so one more element
    idx_xt = model.Tstep+1:model.Tspinup+model.Tstep
    idx_ens = model.Tstep-model.Tburn+2:model.Tstep+1
    # Compute root mean square error statistics
    Rmse, Rmse_med, Rmse_mean, Rmse_std = metric_hist(rmse, data.xt[:,idx_xt], statehist[idx_ens])
    # Compute ensemble spread statistics
    Spread, Spread_med, Spread_mean, Spread_std = metric_hist(spread, statehist[idx_ens])
    # Compute quantile information
    qinf, qsup = quant(statehist[idx_ens])

    # Compute coverage probability statistics

    Covprob = zeros(length(idx_xt))
    b = zeros(Bool, model.Nx)
    for (i,idx) in enumerate(idx_xt)
        for j=1:model.Nx
        b[j] = (qsup[j,i] >= data.xt[j,idx] >= qinf[j,i])
        end
        Covprob[i] = deepcopy(mean(b))
    end

    Covprob_med  = median(Covprob)
    Covprob_mean = mean(Covprob)
    Covprob_std  = std(Covprob)

    Metric = Metrics(Ne, Rmse, Rmse_med, Rmse_mean, Rmse_std, Spread, Spread_med,
                    Spread_mean, Spread_std, Covprob, Covprob_med,
                    Covprob_mean, Covprob_std)
    return Metric
end


text:
using LinearAlgebra
using SparseArrays

"""
    equivalent_matrices(x::AbstractMatrix)

Returns a collection of matrixes that are equal to the input `x`, but of a different type.
Useful for testing if things still work on different types of matrix.
"""
function equivalent_matrices(x::AbstractMatrix)
    mats = [
        Base.PermutedDimsArray(x, (1,2)),  # identity permutation
        view(x, :, :),
        view(x, collect.(axes(x))...),  # breaks `strides`
        sparse(x),
    ]
    if issymmetric(x)
        append!(mats, [
            Symmetric(x),
            Transpose(x),
        ])
    end
    return mats
end