text:
import Plots: current, plot, plot!, vline!, annotate!, scatter!, gr

mutable struct FuzzyNumber <: FuzzySet
    levels::Vector{<:Real}
    grades::Vector{Interval}

    function FuzzyNumber(levels::Vector{<:Real}, grades::Vector{Interval})
        A = new(levels, grades)
        # println("FuzzyNumber $(peak(A)) created")
        return A
    end

    # function FuzzyNumber(levels::Vector{<:Real}; number::Real=0.0, width::Real=0.5)
    #     println("Triangular FuzzyNumber $number created")
    #     new(levels, triangle.(levels, b=number, width=width))
    # end

    # function FuzzyNumber(levels::Vector{<:Real}; number::Real, w_l::Real, w_r::Real, a::Real)
    #     println("Trapezoidal FuzzyNumber $number created")
    #     new(levels, trapezoid.(levels, p=number, w_l=w_l, w_r=w_r, a=a))
    # end
end

function TriangularFuzzyNumber(levels::Vector{<:Real}; number::Real=0.0, width::Real=0.5)
    println("Triangular FuzzyNumber $number created")
    FuzzyNumber(levels, triangle.(levels, b=number, width=width))
end

function TrapezoidalFuzzyNumber(levels::Vector{<:Real}; number::Real, w_l::Real, w_r::Real, a::Real)
    println("Trapezoidal FuzzyNumber $number created")
    FuzzyNumber(levels, trapezoid.(levels, p=number, w_l=w_l, w_r=w_r, a=a))
end

function GaussianFuzzyNumber(levels::Vector{<:Real}; μ::Real, σ::Real)
    println("Gaussian FuzzyNumber $μ created")
    A = FuzzyNumber(levels, gaussian_interval.(levels; μ=μ, σ=σ))
    A.grades[1:80] .= [A.grades[81]] # solve infinite support
    A
end

function BoxFuzzyNumber(levels::Vector{<:Real}; a::Real, b::Real)
    println("BoxFuzzyNumber created")
    FuzzyNumber(levels, box.(levels, a=a, b=b))
end

Base.show(io::IO, A::FuzzyNumber) = println(io, "fuzzy number peak $(peak(A))")
Base.copy(A::FuzzyNumber) = FuzzyNumber(copy(A.levels), copy(A.grades))

function Base.:(==)(A::FuzzyNumber, B::FuzzyNumber)
    if A.levels != B.levels
        return false
    end
    for lvl = 1:length(A.levels)
        if A[lvl] != B[lvl]
            return false
        end
    end
    return true
end

function triangle(α::Real; b=0, width=0.5)
    (α >= 0 && α <= 1) || error("Invalid α")
    left(α, a, b) = (b - a) * α + a
    right(α, b, c) = c - (c - b) * α
    mfx(α, a, b, c) = Interval(left(α, a, b), right(α, b, c))
    return mfx(α, b - width, b, b + width)
end

function triangle(levels::Vector{<:Real}; b=0, width=0.5)
    return triangle.(levels, b=b, width=width)
end

function trapezoid(α::Real; p, w_l, w_r, a)
    (α >= 0 && α <= 1) || error("Invalid α")
    left(α, a, b) = (b - a) * α + a
    right(α, b, c) = c - (c - b) * α
    mfx(α, a, b, c, d) = Interval(left(α, a, b), right(α, c, d))
    return mfx(α, p - w_l - a, p - w_l, p + w_r, p + w_r + a)
end

function trapezoid(levels::Vector{<:Real}; p, w_l, w_r, a)
    return trapezoid.(levels, p=p, w_l=w_l, w_r=w_r, a=a)
end

function box(α::Real; a=0, b=1)
    (α >= 0 && α <= 1) || error("Invalid α")
    return Interval(a, b)
end

function box(levels::Vector{<:Real}; a=0, b=1)
    return box.(levels, a=a, b=b)
end

function SingletonFuzzyNumber(levels::Vector{<:Real}; number::Real=0.0)
    return FuzzyNumber(levels, repeat([Interval(number)], length(levels)))
end

function isSingleton(A::FuzzyNumber)
    if A[1].left != A[1].right
        return false
    end
    B = SingletonFuzzyNumber(A.levels, number=A[1].left)
    return A == B
end

function gaussian_interval(y::Real; μ::Real, σ::Real)
    term = sqrt(-2 * σ^2 * log(y))
    Interval(μ - term, μ + term)
end

function draw(fuzzynumber::FuzzyNumber; fig=nothing, range=nothing, linecolor="black", font=Plots.font("Times", 8), ylabel="", dpi=200)
    # gr(xguidefont=font, yguidefont=font, xtickfont=font, ytickfont=font, legendfont=font)
	if isnothing(fig)
		if isnothing(range)
            fig = plot(ylabel=ylabel, ylims = (0, 1))
        else
			xmin = range[1]
			xmax = range[2]
            fig = plot(ylabel=ylabel, xlims = (xmin, xmax), ylims = (0, 1)) # xticks=collect(xmin:1:xmax)
		end
	end
	if linecolor == "random"
		linecolor = rand(["black", "red", "blue", "green"])
	end

    # draw level cuts
	for i = 1:length(fuzzynumber.levels)
		lvl = fuzzynumber.levels[i]
        interval = fuzzynumber[i]
        if interval.left == interval.right
            scatter!(fig, [interval.left], [lvl], c=linecolor, marker=1, legend=false)
        else
            plot!(fig, vec(interval), [lvl, lvl], linecolor=linecolor, legend=false)
        end
        # break
	end
    # points = [Point2f0(fuzzynumber.grades[i][1], fuzzynumber.levels[i]) => Point2f0(fuzzynumber.grades[i][2], fuzzynumber.levels[i]) for i = 1:length(fuzzynumber.levels)]
    # linesegments(points, color = :red, linewidth = 2)

    # marking peak
    xₘ = peak(fuzzynumber)
    μ = fuzzynumber(xₘ)
    annotate!(fig, [(xₘ, μ, (round(xₘ, digits=2), 8, :blue, :left))])
    # vline!(fig, [xₘ], line=(:dot), linecolor=:black, legend=false)
    if isSingleton(fuzzynumber)
        annotate!(fig, [(0.4, 0.5, ("singleton", 8, :black, :left))])
    end
    plot!(dpi=dpi)

    current()
    return fig
end

function draw_u(fuzzynumbers::Vector{FuzzyNumber}; fig=nothing, range=nothing, linecolors::Vector{String}=["black", "red"], xlabel="", ylabel="", font=Plots.font("Times", 8), size=(450, 150), offset_value=0)
    gr(xguidefont=font, xtickfont=font, ytickfont=font, legendfont=font)
	if isnothing(fig)
		if isnothing(range)
            fig = plot(ylims = (0, 1))
        else
			xmin = range[1]
			xmax = range[2]
            fig = plot(xlims = (xmin, xmax), ylims = (0, 1), xticks=collect(xmin:0.2:xmax))
		end
	end

    for (index, (fuzzynumber, linecolor)) in enumerate(zip(fuzzynumbers, linecolors))
        # draw level cuts
        if isSingleton(fuzzynumber)
            println("SINGLETON!")
            vline!(fig, [fuzzynumber[1].left], linecolor=linecolor, legend=false, xlabel=xlabel, ylabel=ylabel)
        end
        for i = 1:length(fuzzynumber.levels)
            lvl = fuzzynumber.levels[i]
            interval = fuzzynumber[i]
            if interval.left == interval.right
                # scatter!(fig, [interval.left], [lvl], c=linecolor, marker=1, markershape=:cross, legend=false, xlabel=xlabel, ylabel=ylabel)
            else
                plot!(fig, vec(interval), [lvl, lvl], linecolor=linecolor, legend=false, seriesalpha=0.2)
            end
            # break
        end

        # points = [Point2f0(fuzzynumber.grades[i][1], fuzzynumber.levels[i]) => Point2f0(fuzzynumber.grades[i][2], fuzzynumber.levels[i]) for i = 1:length(fuzzynumber.levels)]
        # linesegments(points, color = :red, linewidth = 2)

        # marking peak
        xₘ = peak(fuzzynumber)
        μ = fuzzynumber(xₘ)
        peak_text = string(round(xₘ, digits=2))
        if isSingleton(fuzzynumber)
            # peak_text *= " [s]"
        end
        # if xₘ == 1.0
        #     xₘ -= 0.1
        # end
        offset = -(index - 1) * offset_value
        position = index == 1 ? :left : :right
        annotate!(fig, [(xₘ, μ+offset, (peak_text, 8, linecolor, position, "Times"))])
        # vline!(fig, [xₘ], line=(:dot), linecolor=:black, legend=false)
    end
    plot!(dpi=600, size=size, xlabel=xlabel, ylabel=ylabel)

    current()
    return fig
end

# FUZZY ARITHMETIC ============================================================

Base.:-(A::FuzzyNumber) = FuzzyNumber(A.levels, (-).(A.grades))
Base.:^(A::FuzzyNumber, exponent::Real) = FuzzyNumber(A.levels, A.grades .^ exponent)

Base.:+(A::FuzzyNumber, B::FuzzyNumber) = FuzzyNumber(A.levels, (+).(A.grades, B.grades))
Base.:-(A::FuzzyNumber, B::FuzzyNumber) = FuzzyNumber(A.levels, (-).(A.grades, B.grades))
Base.:*(A::FuzzyNumber, B::FuzzyNumber) = FuzzyNumber(A.levels, (*).(A.grades, B.grades))
Base.:/(A::FuzzyNumber, B::FuzzyNumber) = FuzzyNumber(A.levels, (/).(A.grades, B.grades))
Base.:*(a::Real, A::FuzzyNumber) = FuzzyNumber(A.levels, (*).(a, A.grades))
Base.:*(A::FuzzyNumber, a::Real) = a * A

# =============================================================================

function cut(X::Vector{FuzzyNumber}, α::Real)
	N = length(X)
	cuts = [cut(X[i], α) for i = 1:N]
    cuts
end


text:
using PyCall, PicoQuant

# Some utility functions to help with testing

export switch_endianness, get_statevector_using_picoquant, get_statevector_using_qiskit

"""
    function switch_endianness(vec)

Reverses the qubit ordering for a given state vector
"""
function switch_endianness(vec)
    n = convert(Int, log2(length(vec)))
    vec = reshape(vec, Tuple([2 for _ in 1:n]))
    vec = permutedims(vec, [i for i in n:-1:1])
    reshape(vec, 2^n)
end

"""
    function get_statevector_using_qiskit(circ; big_endian=true)

Uses qiskit to calculate the state vector for a given circuit
"""
function get_statevector_using_qiskit(circ; big_endian=true)
    qiskit = pyimport("qiskit")
    backend = qiskit.Aer.get_backend("statevector_simulator")
    job = qiskit.execute(circ, backend)
    result = job.result()
    vec = result.get_statevector()
    if !big_endian
        return switch_endianness(vec)
    else
        return vec
    end
end

"""
    function get_statevector_using_picoquant(circ; big_endian=false)

Uses picoquant to calculate statevector resulting from given circuit
"""
function get_statevector_using_picoquant(circ; big_endian=false)
    tn = PicoQuant.convert_qiskit_circ_to_network(circ, PicoQuant.InteractiveBackend(), decompose=false, transpile=false)
    qubits = circ.n_qubits
    PicoQuant.add_input!(tn, "0"^qubits)
    wf = PicoQuant.full_wavefunction_contraction!(tn, "vector")
    load_tensor_data(tn, wf)
end

ext: jl


text:
using ExactConversions
using Test
using TestSetExtensions

_int_types = [UInt8, UInt16, UInt32, UInt64, UInt128, Int8, Int16, Int32, Int64, Int128]
_float_types = [Float16, Float32, Float64]

macro skip(code) end

function tryconv(T, x)
    c = convert(T, x)
    x == c ? c : nothing
end

@testset ExtendedTestSet "ExactConversions.jl" begin

    @testset "bounds" begin
        @testset "$I $F" for I in _int_types, F in _float_types
            i, f = mincommon(I, F), mincommon(F, I)
            @test BigInt(i) == BigInt(f)
            i, f = maxcommon(I, F), maxcommon(F, I)
            @test BigInt(i) == BigInt(f)
        end
    end

    @testset "conversions" begin
        @testset "$I $F" for I in _int_types, F in _float_types
            @test exactconv(F, I(0)) == F(0)
            @test exactconv(I, F(0)) == I(0)
            i, f = mincommon(I, F), mincommon(F, I)
            @test exactconv(I, f) === i
            @test exactconv(F, i) === f
            i, f = maxcommon(I, F), maxcommon(F, I)
            @test exactconv(I, f) === i
            @test exactconv(F, i) === f
        end
    end

    @testset "integer to floating-point" begin
        function check_all_int_to_float(I, F)
            for n in typemin(I):typemax(I)
                x = exactconv(F, n)
                f = F(n)
                if f == n
                    x === f || return false
                else
                    x === nothing || return false
                end
            end
            return true
        end
        @testset "$I to $F" for I in [UInt8, Int8, UInt16, Int16], F in _float_types
            @test check_all_int_to_float(I, F)
        end

        function check_all_int_to_float_try_conv(I, F)
            for n in typemin(I):typemax(I)
                exactconv(F, n) === tryconv(F, n) || return false
            end
            return true
        end
        @testset "$I to $F" for I in [UInt8, Int8, UInt16, Int16], F in _float_types
            @test check_all_int_to_float_try_conv(I, F)
        end
    end

    @testset "floating-point to integer" begin
        @testset "Float16 to integer" begin
            function check_all_Float16_to_int(I)
                for u in typemin(UInt16):typemax(UInt16)
                    x = reinterpret(Float16, u)
                    n = exactconv(I, x)
                    if isinteger(x) && typemin(I) <= x <= typemax(I)
                        n === I(x) || return false
                    else
                        n === nothing || return false
                    end
                end
                return true
            end
            @testset "Float16 to $I" for I in _int_types
                @test check_all_Float16_to_int(I)
            end
        end

        @skip @testset "Float32 to integer" begin
            # function check_all_Float32(I)
            #     for u in typemin(UInt32):typemax(UInt32)
            #         x = reinterpret(Float32, u)
            #         n = exactconv(I, x)
            #         if isinteger(x) && typemin(I) <= x <= typemax(I)
            #             n === I(x) || return false
            #         else
            #             n === nothing || return false
            #         end
            #     end
            #     return true
            # end
            function check_positive_Float32(I)
                for u in reinterpret(UInt32, Float32(0)):reinterpret(UInt32, prevfloat(Inf32))
                    x = reinterpret(Float32, u)
                    n = exactconv(I, x)
                    if isinteger(x) && typemin(I) <= x <= typemax(I)
                        n === I(x) || return false
                    else
                        n === nothing || return false
                    end
                end
                return true
            end
            @testset "Float32 to $I" for I in _int_types
                # @test check_all_Float32(I)
                @test check_positive_Float32(I)
            end
        end
    end

end


text:
import Base: isvalid

#### Boundary Conditions ####

abstract BoundaryCondition
type BCnil <: BoundaryCondition; end # ignore edges (error when invalid)
type BCnan <: BoundaryCondition; end  # NaN when over the edge
type BCna <: BoundaryCondition; end  # Normalize to available data (NaN when none)
type BCreflect <: BoundaryCondition; end # Reflecting boundary conditions
type BCperiodic <: BoundaryCondition; end # Periodic boundary conditions
type BCnearest <: BoundaryCondition; end # Return closest edge element
type BCfill <: BoundaryCondition; end # Use specified fill value

# Note: for interpolation, BCna is currently defined to be identical
# to BCnan. Other applications might define different behavior,
# particularly for filtering operations.

#needs_validating{BC<:BoundaryCondition}(::Type{BC}) = false
#needs_validating{BC<:Union(BCnil,BCnan,BCna)}(::Type{BC}) = true
isvalid{BC<:BoundaryCondition}(::Type{BC}, pos::Int, min::Int, max::Int) = true
isvalid{BC<:Union(BCnan,BCna)}(::Type{BC}, pos::Int, min::Int, max::Int) = min <= pos <= max
wrap{BC<:BoundaryCondition}(::Type{BC}, pos::Int, len::Int) = pos
wrap(::Type{BCreflect}, pos::Int, len::Int) = wraprefl(mod(pos-1, 2*len), len)
wraprefl(posrem::Int, len::Int) = posrem < len ? posrem+1 : 2*len-posrem
wrap(::Type{BCperiodic}, pos::Int, len::Int) = mod(pos-1, len) + 1
wrap{BC<:Union(BCnearest,BCfill)}(::Type{BC}, pos::Int, len::Int) = pos < 1 ? 1 : (pos > len ? len : pos)


text:
immutable Multinomial <: DiscreteMultivariateDistribution
    n::Int
    prob::Vector{Float64}

    function Multinomial(n::Integer, p::Vector{Float64})
        if n <= 0
            throw(ArgumentError("n must be a positive integer."))
        end
        if !isprobvec(p)
            throw(ArgumentError("p = $p is not a probability vector."))
        end
        new(int(n), p)
    end
end

immutable MultinomialSampler <: DiscreteMultivariateDistribution
    d::Multinomial
    alias::AliasTable
    function MultinomialSampler(d::Multinomial)
        new(d, AliasTable(d.prob))
    end
end

sampler(d::Multinomial) = MultinomialSampler(d)

function Multinomial(n::Integer, d::Integer)
    if d < 1
        error("d must be greater than 0")
    end
    prob = Array(Float64, d)
    fill!(prob, 1.0 / d)
    Multinomial(n, prob)
end

# TODO: Debate removing this
Multinomial(d::Integer) = Multinomial(1, d)

dim(d::Multinomial) = length(d.prob)
dim(s::MultinomialSampler) = length(s.d.prob)

entropy(d::Multinomial) = NumericExtensions.entropy(d.prob)

function insupport{T <: Real}(d::Multinomial, x::Vector{T})
    n = length(x)
    if length(d.prob) != n
        return false
    end
    s = 0.0
    for i in 1:n
        if x[i] < 0.0 || !isinteger(x[i])
            return false
        end
        s += x[i]
    end
    if abs(s - d.n) > 1e-8
        return false
    end
    return true
end

mean(d::Multinomial) = d.n .* d.prob

function var(d::Multinomial)
    p = d.prob
    k = length(p)
    v = Array(Float64, k)
    n = d.n
    for i = 1:k
        pi = p[i]
        v[i] = n * pi * (1.0 - pi)
    end
    v
end

function cov(d::Multinomial)
    p = d.prob
    k = length(p)
    C = Array(Float64, k, k)
    n = d.n

    for j = 1:k
        pj = p[j]
        for i = 1:j-1
            C[i,j] = - n * p[i] * pj
        end

        C[j,j] = n * pj * (1.0-pj)
    end

    for j = 1:k-1
        for i = j+1:k
            C[i,j] = C[j,i]
        end
    end
    C
end

function mgf(d::Multinomial, t::AbstractVector)
    p, n = d.prob, d.n
    k = length(p)
    s = 0.0
    for i in 1:k
        s += p[i] * exp(t[i])
    end
    return s^n
end

function cf(d::Multinomial, t::AbstractVector)
    p, n = d.prob, d.n
    k = length(p)
    s = 0.0 + 0.0im
    for i in 1:k
        s += p[i] * exp(im * t[i])
    end
    return s^n
end

pdf{T <: Real}(d::Multinomial, x::Vector{T}) = exp(logpdf(d, x))

function logpdf{T <: Real}(d::Multinomial, x::Vector{T})
    if !insupport(d, x)
        return -Inf
    else
        s = lgamma(d.n + 1.0)
        for i in 1:length(x)
            s -= lgamma(x[i] + 1.0)
            s += x[i] * log(d.prob[i])
        end
        return s
    end
end

# TODO: Debate making T <: Integer
function rand!{T <: Real}(d::Multinomial, x::Vector{T})
    n, k = d.n, dim(d)
    fill!(x, 0)
    psum = 1.0
    for j in 1:(k - 1)
        tmp = rand(Binomial(n, d.prob[j] / psum))
        x[j] = tmp
        n -= tmp
        if n == 0
            break
        end
        psum -= d.prob[j]
    end
    x[k] = n
    return x
end

function rand!{T <: Real}(s::MultinomialSampler, x::Vector{T})
    d = s.d
    n, k = d.n, dim(d)
    fill!(x, 0)
    if n^2 > k
        # Use sequential binomial sampling
        # TODO: Refactor this code to make it DRYer
        psum = 1.0
        for j in 1:(k - 1)
            tmp = rand(Binomial(n, d.prob[j] / psum))
            x[j] = tmp
            n -= tmp
            if n == 0
                break
            end
            psum -= d.prob[j]
        end
        x[k] = n
    else
        # Use an alias table
        for itr in 1:n
            x[rand(s.alias)] += 1
        end
    end
    return x
end

function rand(d::Multinomial)
    x = zeros(Int, dim(d))
    return rand!(d, x)
end

function rand(s::MultinomialSampler)
    x = zeros(Int, dim(s.d))
    return rand!(s, x)
end

## Fit model

immutable MultinomialStats
    n::Int  # number of trials in each experiment
    scnts::Vector{Float64}  # sum of counts
    tw::Float64  # total sample weight

    MultinomialStats(n::Int, scnts::Vector{Float64}, tw::Real) = new(n, scnts, float64(tw))
end

function suffstats{T<:Real}(::Type{Multinomial}, x::Matrix{T})
    K = size(x, 1)
    n::T = zero(T)
    scnts = zeros(K)

    for j = 1:size(x,2)
        nj = zero(T)
        for i = 1:K
            xi = x[i,j]
            nj += xi

            scnts[i] += xi
        end

        if j == 1
            n = nj
        elseif nj != n
            error("Each sample in X should sum to the same value.")
        end
    end
    MultinomialStats(n, scnts, size(x,2))
end

function suffstats{T<:Real}(::Type{Multinomial}, x::Matrix{T}, w::Array{Float64})
    if length(w) != size(x, 2)
        throw(ArgumentError("Inconsistent argument dimensions."))
    end

    K = size(x, 1)
    n::T = zero(T)
    scnts = zeros(K)
    tw = 0.

    for j = 1:size(x,2)
        nj = zero(T)
        wj = w[j]
        tw += wj
        for i = 1:K
            xi = x[i,j]
            nj += xi

            scnts[i] += xi * wj
        end

        if j == 1
            n = nj
        elseif nj != n
            error("Each sample in X should sum to the same value.")
        end
    end
    MultinomialStats(n, scnts, tw)
end

fit_mle(::Type{Multinomial}, ss::MultinomialStats) = Multinomial(ss.n, ss.scnts * inv(ss.tw * ss.n))


text:
# This is a test-for-tests, verifying the code in utils.jl.
using Test

@testset "Abort" begin
    ex = Base.parse_input_line("""
    x = 1
    for i = 1:10
        x += 1
    end
    let y = 0
        z = 5
    end
    if 2 > 1
        println("Hello, world!")
    end
    @elapsed sum(rand(5))
    """; filename="fake.jl")
    modexs, _ = JuliaInterpreter.split_expressions(Main, ex; filename="fake.jl")
    # find the 3rd assignment statement in the 2nd frame (corresponding to the x += 1 line)
    frame = JuliaInterpreter.prepare_thunk(modexs[2])
    i = 0
    for k = 1:3
        i = findnext(stmt->isexpr(stmt, :(=)), frame.framecode.src.code, i+1)
    end
    @test Aborted(frame, i).at.line == 3
    # Check interior of let block
    frame = JuliaInterpreter.prepare_thunk(modexs[3])
    i = 0
    for k = 1:2
        i = findnext(stmt->isexpr(stmt, :(=)), frame.framecode.src.code, i+1)
    end
    @test Aborted(frame, i).at.line == 6
    # Check conditional
    frame = JuliaInterpreter.prepare_thunk(modexs[4])
    i = findfirst(stmt->JuliaInterpreter.is_gotoifnot(stmt), frame.framecode.src.code) + 1
    @test Aborted(frame, i).at.line == 9
    # Check macro
    frame = JuliaInterpreter.prepare_thunk(modexs[5])
    if VERSION < v"1.4.0-DEV.475"
        @test Aborted(frame, 1).at.file == Symbol("util.jl")
    else
        @test Aborted(frame, 1).at.file == Symbol("fake.jl")
    end
end

module EvalLimited end

@testset "evaluate_limited" begin
    aborts = Aborted[]
    ex = Base.parse_input_line("""
    s = 0
    for i = 1:5
        global s
        s += 1
    end
    """)
    modexs, _ = JuliaInterpreter.split_expressions(EvalLimited, ex)
    nstmts = 1000  # enough to ensure it finishes
    for modex in modexs
        frame = JuliaInterpreter.prepare_thunk(modex)
        @test isa(frame, Frame)
        nstmtsleft = nstmts
        while true
            ret, nstmtsleft = evaluate_limited!(frame, nstmtsleft, true)
            isa(ret, Some{Any}) && break
            isa(ret, Aborted) && push!(aborts, ret)
        end
    end
    @test EvalLimited.s == 5
    @test isempty(aborts)

    ex = Base.parse_input_line("""
    s = 0
    for i = 1:50
        global s
        s += 1
    end
    """; filename="fake.jl")
    if length(ex.args) == 2
        # Sadly, parse_input_line doesn't insert line info at toplevel, so do it manually
        insert!(ex.args, 2, LineNumberNode(2, Symbol("fake.jl")))
        insert!(ex.args, 1, LineNumberNode(1, Symbol("fake.jl")))
    end
    modexs, _ = JuliaInterpreter.split_expressions(EvalLimited, ex)
    nstmts = 100 # enough to ensure it gets into the loop but doesn't finish
    for modex in modexs
        frame = JuliaInterpreter.prepare_thunk(modex)
        @test isa(frame, Frame)
        nstmtsleft = nstmts
        while true
            ret, nstmtsleft = evaluate_limited!(Compiled(), frame, nstmtsleft, true)
            isa(ret, Some{Any}) && break
            isa(ret, Aborted) && (push!(aborts, ret); break)
        end
    end
    @test 8 < EvalLimited.s < 50  # with Compiled(), 9 statements per iteration
    @test length(aborts) == 1
    @test aborts[1].at.line ∈ (2, 3, 4)  # 2 corresponds to lowering of the for loop

    # Now try again with recursive stack
    empty!(aborts)
    modexs, _ = JuliaInterpreter.split_expressions(EvalLimited, ex)
    for modex in modexs
        frame = JuliaInterpreter.prepare_thunk(modex)
        @test isa(frame, Frame)
        nstmtsleft = nstmts
        while true
            ret, nstmtsleft = evaluate_limited!(frame, nstmtsleft, true)
            isa(ret, Some{Any}) && break
            isa(ret, Aborted) && (push!(aborts, ret); break)
        end
    end
    @test EvalLimited.s < 5
    @test length(aborts) == 1
    lin = aborts[1].at
    if lin.file == Symbol("fake.jl")
        @test lin.line ∈ (2, 3, 4)
    else
        @test lin.file == Symbol("range.jl")  # if it aborts in `iterate`
    end
end


text:
include("../examples/solenoid.jl")
using LinearAlgebra
using JLD
using SharedArrays
using Distributed
using Zygote
function sens(s,nSteps)
    d = 3
    s_ind = 3
    u = rand(d)

    n_runup = 500
    for i = 1:n_runup
        u = next(u,s)
    end

    dui = rand(d,d)
    ppi = rand(d)
    dppi = rand(d,d)

    dpert(x) = jacobian(x -> pert(x,s,s_ind), x)[1]
    d2next(x) = jacobian(x -> dstep(x,s), x)[1]

    vs = zeros(d)
    q = rand(d)
    q /= norm(q)

    pp = rand(d)
    q1 = rand(d)
    vs1 = zeros(d)

    dJds_st = 0.
    dJds_ust = 0.
    N = 12
    nSteps = nSteps + 1
    g = zeros(nSteps)

    # Df represents the derivative of f
    # on the
    # unstable manifold.
    # Xu = a q
    # d = 2
    Xu = zeros(d, nSteps)
    a = zeros(nSteps)
    J = zeros(nSteps)
    Da = zeros(nSteps)
    Dq = zeros(d)
    Dvs = zeros(d)
    Dvs1 = zeros(d)

    # nSteps large number.
    for i = 1:nSteps-1
        J[i] = u[1]*u[1] + u[2]*u[2]
        dJdu = [2*u[1], 2*u[2], 0.]
	ppi .= pert(u,s,s_ind)
        dui .= dstep(u,s) # for large systems, can't store Jacobian.
        dppi .= dpert(u)*inv(dui) # profile against using solve (backslash) here.
        q1 .= dui*q
        z = norm(q1)
        q1 ./= z

        z2 = z*z

        vs1 .= dui*vs + ppi
        a[i+1] = dot(vs1, q1)
        vs1 .-= a[i+1]*q1

        ddui = d2next(u)
        d2q = reshape(ddui*q,d,d)
        Dq = d2q*q/z2 + dui*Dq/z2
        dzdx = dot(z*Dq, q1)
        Dq .= Dq .- dot(Dq,q1)*q1

        Dvs1 .= d2q*vs/z + dui*Dvs/z + dppi*q1
        Da[i+1] = dot(vs1, Dq) + dot(Dvs1, q1)
        Dvs1 .= Dvs1 - Da[i+1]*q1 - a[i+1]*Dq

        g[i+1] = g[i]/z - dzdx/z

        dJds_st += dot(dJdu, vs)/nSteps

        vs .= vs1
        q .= q1
        Dvs .= Dvs1
        u .= next(u,s)

    end
    for n = 1:N
        J_shift = J[n+1:end]
        nJ = length(J_shift)
        g_shift = g[2:nJ+1]
        Da_shift = Da[2:nJ+1]
        a_shift = a[2:nJ+1]
        dJds_ust -= dot(J_shift,Da_shift)/nJ
        dJds_ust -= dot(J_shift,g_shift.*a_shift)/nJ
    end
    @show dJds_st
    return dJds_st + dJds_ust
end
function get_sens(s)
    nSteps = 60000
    # J = r2
    n_exps = size(s)[2]
    dJds = zeros(n_exps)
    n_rep = 160000
    n_samples = nSteps*n_rep
    dJds_proc = SharedArray{Float64}(n_rep)
    for k=1:n_exps
        sk = s[:,k]
        dJds_proc .= 0.
        t = @distributed for j=1:n_rep
            dJds_proc[j] = sens(sk,nSteps)/n_rep
        end
        wait(t)
        dJds[k] = sum(dJds_proc)
        @show dJds[k]
    end
    save("../data/sens/solenoid/dJds_K12_$(n_samples).jld", "s",
         s[1,:], "dJds", dJds)
end

max_stars_repo_name: nishaChandramoorthy/linearResponse

max_issues_repo_name: nishaChandramoorthy/linearResponse

max_forks_repo_name: nishaChandramoorthy/linearResponse


text:
"""

Just check if solute and solvent are the same

"""
function isautocorrelation(trajectory::Trajectory)
    if trajectory.solute.index == trajectory.solvent.index
        true
    else
        false
    end
end


text:
# Tests the routine kickfast jacobian.  This routine
# computes the impulse gradient after Dehnen & Hernandez (2017).

import NbodyGradient: kickfast!, Derivatives

# Next, try computing three-body Keplerian Jacobian:

@testset "kickfast" begin
n = 3
H = [3,1,1]
t0 = 7257.93115525
h  = 0.05
tmax = 600.0
dlnq = big(1e-15)

elements = readdlm("elements.txt", ',')
elements[2,1] = 1.0
elements[3,1] = 1.0

m = zeros(n)
x0 = zeros(3, n)
v0 = zeros(3, n)
# Define which pairs will have impulse rather than -drift+Kepler:
pair = ones(Bool, n, n)  # This does impulses
# We want Keplerian between star & planets, and impulses between
# planets.  Impulse is indicated with 'true', -drift+Kepler with 'false':
for i = 2:n
    pair[1,i] = false  # This does a Kepler + drift
  # We don't need to define this, but let's anyways:
    pair[i,1] = false
end

# jac_step = zeros(7*n,7*n)

for k = 1:n
    m[k] = elements[k,1]
end
m0 = copy(m)

init = ElementsIC(t0, H, elements)
ic_big = ElementsIC(big(t0), H, big.(elements))
s0 = State(init)
s0.pair .= pair
s0big = State(ic_big)
s0big.pair .= pair

# Tilt the orbits a bit:
s0.x[2,1] = 5e-1 * sqrt(s0.x[1,1]^2 + s0.x[3,1]^2)
s0.x[2,2] = -5e-1 * sqrt(s0.x[1,2]^2 + s0.x[3,2]^2)
s0.x[2,3] = -5e-1 * sqrt(s0.x[1,2]^2 + s0.x[3,2]^2)
s0.v[2,1] = 5e-1 * sqrt(s0.v[1,1]^2 + s0.v[3,1]^2)
s0.v[2,2] = -5e-1 * sqrt(s0.v[1,2]^2 + s0.v[3,2]^2)
s0.v[2,3] = -5e-1 * sqrt(s0.v[1,2]^2 + s0.v[3,2]^2)

# Take a step:
s0big.x .= big.(s0.x)
s0big.v .= big.(s0.v)
ahl21!(s0,h)
ahl21!(s0big,big(h))

# Now, copy these to compute Jacobian (so that I don't step
# x0 & v0 forward in time):
s = deepcopy(s0)
s.xerror .= 0.0; s.verror .= 0.0
# Compute jacobian exactly:
d = Derivatives(Float64, s.n);
s.jac_step .= 0.0
d.dqdt_kick .= 0.0
kickfast!(s,d,h)
# Add in identity matrix:
for i = 1:7 * n
    d.jac_kick[i,i] += 1
end

# Now compute numerical derivatives, using BigFloat to avoid
# round-off errors:
jac_step_num = zeros(BigFloat, 7 * n, 7 * n)
# Save these so that I can compute derivatives numerically:
xsave = copy(s0big.x)
vsave = copy(s0big.v)
msave = copy(s0big.m)
hbig = big(h)

sbig = deepcopy(s0big)
sbig.x .= xsave
sbig.v .= vsave
sbig.m .= msave
sbig.xerror .= 0.0; sbig.verror .= 0.0
# Carry out step using BigFloat for extra precision:
kickfast!(sbig,hbig)
# Save back to use in derivative calculations
xsave .= sbig.x
vsave .= sbig.v
msave .= sbig.m
sbig = deepcopy(s0big)
sbig.xerror .= 0.0; sbig.verror .= 0.0
# Compute numerical derivatives wrt time:
dqdt_num = zeros(BigFloat, 7 * n)
# Vary time:
kickfast!(sbig,hbig)
# Initial positions, velocities & masses:
sbig = deepcopy(s0big)
sbig.xerror .= 0.0; sbig.verror .= 0.0
hbig = big(h)
dq = dlnq * hbig
hbig += dq
kickfast!(sbig,hbig)
# Now x & v are final positions & velocities after time step
for i in 1:n, k in 1:3
    dqdt_num[(i - 1) * 7 +  k] = (sbig.x[k,i] - xsave[k,i]) / dq
    dqdt_num[(i - 1) * 7 + 3 + k] = (sbig.v[k,i] - vsave[k,i]) / dq
end
hbig = big(h)
# Vary the initial parameters of planet j:
for j = 1:n
  # Vary the initial phase-space elements:
    for jj = 1:3
  # Initial positions, velocities & masses:
        sbig = deepcopy(s0big)
        sbig.xerror .= 0.0; sbig.verror .= 0.0
        dq = dlnq * sbig.x[jj,j]
        if sbig.x[jj,j] != 0.0
            sbig.x[jj,j] +=  dq
        else
            dq = dlnq
            sbig.x[jj,j] = dq
        end
        kickfast!(sbig, hbig)
        # Now x & v are final positions & velocities after time step
        for i = 1:n
            for k = 1:3
                jac_step_num[(i - 1) * 7 +  k,(j - 1) * 7 + jj] = (sbig.x[k,i] - xsave[k,i]) / dq
                jac_step_num[(i - 1) * 7 + 3 + k,(j - 1) * 7 + jj] = (sbig.v[k,i] - vsave[k,i]) / dq
            end
        end
        sbig = deepcopy(s0big)
        sbig.xerror .= 0.0; sbig.verror .= 0.0
        dq = dlnq * sbig.v[jj,j]
        if sbig.v[jj,j] != 0.0
            sbig.v[jj,j] +=  dq
        else
            dq = dlnq
            sbig.v[jj,j] = dq
        end
        kickfast!(sbig, hbig)
        for i in 1:n
            for k = 1:3
                jac_step_num[(i - 1) * 7 +  k,(j - 1) * 7 + 3 + jj] = (sbig.x[k,i] - xsave[k,i]) / dq
                jac_step_num[(i - 1) * 7 + 3 + k,(j - 1) * 7 + 3 + jj] = (sbig.v[k,i] - vsave[k,i]) / dq
            end
        end
    end
    # Now vary mass of planet:
    sbig = deepcopy(s0big)
    sbig.xerror .= 0.0; sbig.verror .= 0.0
    dq = sbig.m[j] * dlnq
    sbig.m[j] += dq
    kickfast!(sbig, hbig)
    for i = 1:n
        for k = 1:3
            jac_step_num[(i - 1) * 7 +  k,j * 7] = (sbig.x[k,i] - xsave[k,i]) / dq
            jac_step_num[(i - 1) * 7 + 3 + k,j * 7] = (sbig.v[k,i] - vsave[k,i]) / dq
        end
    # Mass unchanged -> identity
        jac_step_num[7 * i,7 * i] = big(1.0)
    end
end
jac_step_num = convert(Array{Float64,2}, jac_step_num)
dqdt_num = convert(Array{Float64,1}, dqdt_num)

@test isapprox(d.jac_kick, jac_step_num;norm=maxabs)
@test isapprox(d.dqdt_kick, dqdt_num;norm=maxabs)
end


text:
module Wasmer

include("./LibWasmer.jl")

using .LibWasmer

include("./vec_t.jl")
include("./val_t.jl")
include("./engine.jl")
include("./store.jl")
include("./module.jl")
include("./wasi.jl")
include("./wat2wasm.jl")
include("./instance.jl")

export WasmEngine,
    WasmMemory,
    WasmStore,
    WasmInstance,
    WasmExports,
    exports,
    WasmStore,
    WasmModule,
    imports,
    WasmImports,
    WasmFunc,
    @wat_str

end # module


text:
using Knet, AutoGrad, Printf
using Knet: @cudart, cudnnhandle, Cptr, TD, cudnnSoftmaxForward, cudnnSoftmaxBackward, TD4, _logp
using BenchmarkTools

# algo=2 corresponds to logp(x,1)
function logp_(x;dims=:)
    if isa(x,Number)
        return zero(x)
    elseif isempty(x)
        return x
    elseif dims == Colon()
        x1 = reshape(x, (1,1,length(x),1))
        y1 = cudnnSoftmaxForward(x1,algo=2)
        reshape(y1,size(x))
    elseif dims == 1
        cudnnSoftmaxForward(x,algo=2)
    elseif dims == 2
        x1 = transpose(x)
        y1 = cudnnSoftmaxForward(x1,algo=2)
        transpose(y1)
    else
        error("logp $d not implemented yet.")
    end
end

x1 = ka(randn(Float32,10,100))
x2 = ka(randn(Float32,100,100))
x3 = ka(randn(Float32,1000,100))
x4 = ka(randn(Float32,10000,100))
x5 = ka(randn(Float32,100000,100))

cds()=@cudart(cudaDeviceSynchronize, ())
rep(x)=clamp(div(10^8,length(x)),10,1000)
logp0(x;dims=:)=(for i=1:rep(x); _logp(x;dims=dims); end; cds()) # old implementation
logp1(x;dims=:)=(for i=1:rep(x); logp_(x;dims=dims); end; cds()) # test implementation
logp2(x;dims=:)=(for i=1:rep(x); logp(x;dims=dims); end; cds())  # new (hybrid) implementation, should be best of the other two
sump0(x;dims=:)=sum(_logp(x;dims=dims)[1,:]); grad0 = grad(sump0)
sump1(x;dims=:)=sum(logp_(x;dims=dims)[1,:]); grad1 = grad(sump1)
sump2(x;dims=:)=sum(logp(x;dims=dims)[1,:]);  grad2 = grad(sump2)
back0(x;dims=:)=(for i=1:rep(x); grad0(x;dims=dims); end; cds())
back1(x;dims=:)=(for i=1:rep(x); grad1(x;dims=dims); end; cds())
back2(x;dims=:)=(for i=1:rep(x); grad2(x;dims=dims); end; cds())
# macro bm(ex); :(println($(sprint(Base.show_unquoted,ex)));show(@benchmark $ex)) end

@show logp(x1) ≈ logp_(x1) ≈ _logp(x1)
@show logp(x1,dims=1) ≈ logp_(x1,dims=1) ≈ _logp(x1,dims=1)
@show logp(x1',dims=2) ≈ logp_(x1',dims=2) ≈ _logp(x1',dims=2)

@show grad0(x1) ≈ grad1(x1) ≈ grad2(x1)
@show grad0(x1,dims=1) ≈ grad1(x1,dims=1) ≈ grad2(x1,dims=1)
@show grad0(x1',dims=2) ≈ grad1(x1',dims=2) ≈ grad2(x1',dims=2)

# dimensions: 0/1/2, forw/back, model0/1, x1:5

for d in (0,1,2)
    for f in (logp0, logp1, logp2, back0, back1, back2)
        @printf("%s(x,%d)",f,d)
        for x in (x1,x2,x3,x4,x5)
            xt = permutedims(x)
            Knet.gc()
            b = (d==0 ? (@benchmark $f($x)) :
                 d==1 ? (@benchmark $f($x,dims=1)) :
                 d==2 ? (@benchmark $f($xt,dims=2)) :
                 error())
            times = b.times ./ rep(x)
            # @printf("\t%dx%d/%.1e/%.1e/%.1e", length(times), rep(x), minimum(times), median(times), mean(times))
            @printf("\t%.1e", minimum(times))
        end
        println()
    end
end

#=
logp0(x,0)	8.5e+04	8.6e+04	1.0e+05	2.8e+05	2.2e+06
logp1(x,0)	1.2e+04	4.7e+04	3.8e+05	5.4e+06	5.3e+07
logp2(x,0)	1.2e+04	4.7e+04	1.0e+05	2.8e+05	2.2e+06
back0(x,0)	2.2e+05	2.5e+05	2.8e+05	6.2e+05	4.5e+06
back1(x,0)	1.5e+05	1.7e+05	7.5e+05	9.5e+06	9.4e+07
back2(x,0)	1.4e+05	1.7e+05	2.3e+05	6.2e+05	4.5e+06
logp0(x,1)	3.3e+04	3.6e+04	5.5e+04	2.8e+05	2.4e+06
logp1(x,1)	1.2e+04	1.3e+04	1.9e+04	1.4e+05	1.2e+06
logp2(x,1)	1.2e+04	1.3e+04	1.9e+04	1.4e+05	1.2e+06
back0(x,1)	1.6e+05	1.7e+05	1.8e+05	6.1e+05	4.8e+06
back1(x,1)	1.3e+05	1.3e+05	1.3e+05	3.5e+05	2.5e+06
back2(x,1)	1.3e+05	1.3e+05	1.3e+05	3.5e+05	2.5e+06
logp0(x,2)	3.3e+04	3.8e+04	9.1e+04	6.3e+05	7.9e+06
logp1(x,2)	2.7e+04	3.0e+04	4.1e+04	2.5e+05	2.1e+06
logp2(x,2)	2.7e+04	3.0e+04	4.1e+04	2.5e+05	2.1e+06
back0(x,2)	1.7e+05	1.7e+05	2.4e+05	1.2e+06	1.3e+07
back1(x,2)	1.7e+05	1.7e+05	1.7e+05	5.8e+05	4.5e+06
back2(x,2)	1.7e+05	1.7e+05	1.7e+05	5.8e+05	4.5e+06
=#

function timesoftmax(x,dir,algo,mode)
    if dir == 0
        (for i=1:rep(x); cudnnSoftmaxForward(x,algo=algo,mode=mode); end; cds())
    else # dir == 1
        (for i=1:rep(x); cudnnSoftmaxBackward(x,x,algo=algo,mode=mode); end; cds())
    end
end

# test other configurations
#=
for dir in (0,1)
    for algo in (0,1,2)
        for mode in (0,1)
            @printf("%s%d%d",dir,algo,mode)
            for x in (x1,x2,x3,x4,x5)
                Knet.gc()
                b = (@benchmark $timesoftmax($x,$dir,$algo,$mode))
                times = b.times ./ rep(x)
                @printf("\t%.1e", minimum(times))
            end
            println()
        end
    end
end

forw:
000	9.4e+03	1.0e+04	1.6e+04	1.2e+05	9.7e+05 # fast mode has slight advantage in forw
001	9.4e+03	1.0e+04	1.6e+04	1.2e+05	9.7e+05
010	1.2e+04	1.3e+04	2.0e+04	1.4e+05	1.2e+06
011	1.2e+04	1.3e+04	2.0e+04	1.4e+05	1.2e+06
020	1.2e+04	1.3e+04	1.9e+04	1.4e+05	1.2e+06 # log mode is the same as slow mode
021	1.2e+04	1.3e+04	1.9e+04	1.4e+05	1.2e+06
back:
100	9.4e+03	9.3e+03	1.5e+04	9.7e+04	7.4e+05
101	2.0e+05	2.0e+05	4.2e+05	2.6e+06	2.2e+07 # mode=1 has expensive back
110	9.4e+03	9.3e+03	1.5e+04	9.7e+04	7.4e+05
111	2.0e+05	2.0e+05	4.2e+05	2.6e+06	2.2e+07
120	9.4e+03	1.0e+04	1.6e+04	8.7e+04	7.1e+05
121	2.3e+05	2.3e+05	5.6e+05	3.5e+06	2.9e+07
=#

# commit 359d3646 2018-09-22, julia 1.0.0  vs commit 4aa5f92f 2018-08-14, julia 0.6.4
# GPU:V100, CPU:Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GHz
#
# logp(x1) ≈ logp_(x1) ≈ _logp(x1) = true
# logp(x1, dims=1) ≈ logp_(x1, dims=1) ≈ _logp(x1, dims=1) = true
# logp(x1', dims=2) ≈ logp_(x1', dims=2) ≈ _logp(x1', dims=2) = true
# grad0(x1) ≈ grad1(x1) ≈ grad2(x1) = true
# grad0(x1, dims=1) ≈ grad1(x1, dims=1) ≈ grad2(x1, dims=1) = true
# grad0(x1', dims=2) ≈ grad1(x1', dims=2) ≈ grad2(x1', dims=2) = true
# logp0(x,0)	5.9e+04	6.4e+04	6.2e+04	1.2e+05	8.5e+05		logp0(x,0)	4.8e+04	4.8e+04	4.9e+04	1.2e+05	8.4e+05
# logp1(x,0)	7.3e+03	9.9e+03	1.4e+05	1.8e+06	2.6e+07         logp1(x,0)	5.7e+03	1.0e+04	1.4e+05	1.9e+06	2.6e+07
# logp2(x,0)	6.0e+04	6.4e+04	6.3e+04	1.2e+05	8.5e+05         logp2(x,0)	5.9e+03	1.0e+04	5.0e+04	1.2e+05	8.5e+05
# back0(x,0)	2.1e+05	2.2e+05	2.2e+05	3.0e+05	1.6e+06         back0(x,0)	1.7e+05	1.7e+05	1.8e+05	2.7e+05	1.6e+06
# back1(x,0)	1.4e+05	1.5e+05	3.3e+05	3.5e+06	4.4e+07         back1(x,0)	1.3e+05	1.3e+05	3.3e+05	3.6e+06	4.5e+07
# back2(x,0)	2.2e+05	2.2e+05	2.0e+05	3.0e+05	1.6e+06         back2(x,0)	1.2e+05	1.3e+05	1.7e+05	2.7e+05	1.6e+06
# logp0(x,1)	3.8e+04	3.6e+04	4.0e+04	7.1e+04	5.9e+05         logp0(x,1)	3.0e+04	3.3e+04	3.0e+04	7.2e+04	5.9e+05
# logp1(x,1)	7.2e+03	7.2e+03	6.4e+03	3.1e+04	3.9e+05         logp1(x,1)	6.8e+03	7.3e+03	7.0e+03	3.1e+04	3.9e+05
# logp2(x,1)	3.9e+04	3.9e+04	3.7e+04	7.2e+04	5.9e+05         logp2(x,1)	6.7e+03	7.3e+03	7.3e+03	3.1e+04	3.9e+05
# back0(x,1)	1.7e+05	1.7e+05	1.6e+05	2.2e+05	1.2e+06         back0(x,1)	1.5e+05	1.5e+05	1.6e+05	2.0e+05	1.2e+06
# back1(x,1)	1.1e+05	1.2e+05	1.2e+05	1.4e+05	8.1e+05         back1(x,1)	1.2e+05	1.2e+05	1.3e+05	1.4e+05	8.1e+05
# back2(x,1)	1.7e+05	1.8e+05	1.7e+05	2.4e+05	1.2e+06         back2(x,1)	1.2e+05	1.2e+05	1.3e+05	1.4e+05	8.1e+05
# logp0(x,2)	3.7e+04	3.7e+04	3.6e+04	1.1e+05	1.0e+06         logp0(x,2)	3.1e+04	3.1e+04	3.4e+04	1.1e+05	1.0e+06
# logp1(x,2)	1.8e+04	1.9e+04	1.9e+04	4.9e+04	6.2e+05         logp1(x,2)	1.7e+04	1.7e+04	1.9e+04	4.9e+04	6.2e+05
# logp2(x,2)	3.6e+04	3.6e+04	3.7e+04	1.1e+05	1.0e+06         logp2(x,2)	1.7e+04	1.7e+04	1.9e+04	4.9e+04	6.2e+05
# back0(x,2)	1.8e+05	1.8e+05	1.7e+05	2.8e+05	1.9e+06         back0(x,2)	1.5e+05	1.5e+05	1.6e+05	2.6e+05	1.9e+06
# back1(x,2)	1.6e+05	1.6e+05	1.5e+05	1.9e+05	1.3e+06         back1(x,2)	1.6e+05	1.6e+05	1.7e+05	1.8e+05	1.3e+06
# back2(x,2)	1.8e+05	1.8e+05	1.7e+05	2.8e+05	1.9e+06         back2(x,2)	1.6e+05	1.6e+05	1.7e+05	1.8e+05	1.3e+06


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

using Markdown
using InteractiveUtils

# ╔═╡ c8f6136d-a7a0-4a25-842e-b76a30444d08
using PlutoUI; TableOfContents(aside=false)

# ╔═╡ 141ce59d-ca9d-464e-b642-90a10adadc18
using CSV, DataFrames

# ╔═╡ ecf79151-b628-4a04-bed8-ababb5743420
using Statistics # mean

# ╔═╡ fc96a1a8-0b70-4437-8df3-d8bbc355a5ab
using FreqTables

# ╔═╡ d4863f7d-ddde-4c8d-b960-ac0b1ed27aed
using AlgebraOfGraphics, CairoMakie # Plot, Cairo is the future.

# ╔═╡ 051d9767-42c6-47a3-b832-f58ad0a15c4f
using GLM

# ╔═╡ 23d7a0d4-6704-4f16-812a-a68c5fcf01d7
md"""
### Load packages
"""

# ╔═╡ 0d093f1d-918b-48f4-965e-0e711a7a4eae
md"""
### Preprocess data
"""

# ╔═╡ 17c8b2cc-77de-4998-8dce-9ec2e3927cb0
md"""
- Downsampling: 250 Hz
- Bandpass filtering: 0.1 Hz - 50 Hz
- Epoch (N3 Onset): -200ms - 1000ms
- Baseline correction
- Rereferenced to sum of channels
"""

# ╔═╡ 48c903d8-413b-4e62-ae03-84aca4552a57
md"""
### Read data
"""

# ╔═╡ 91923052-5ee4-11ec-09cf-33cdea5e9d3b
cd(@__DIR__) # pwd()

# ╔═╡ d2e6e365-d026-4f23-a194-1c6a02bd8eb0
txt_list = filter(endswith(".txt"), readdir("EpochData", join = true));

# ╔═╡ bb0f7c02-9f48-431d-88d3-7e9bbaa96c34
# Read each `txt` file and `vcat` them, `?mapreduce` for more information
df = mapreduce(vcat, txt_list) do txt

	# 1. Transpose and read the txt file into DataFrame
	df1 = CSV.read(txt, DataFrame, transpose = true)

	# 2. Delete rows containing missing values
	dropmissing!(df1)

	# 3. Retrieve File information from txt file name
	File = replace(txt, r"(\w*?)\/(\w*?)(\s*?).txt" => s"\2")

	# 4. Insert columns, `file`, `pause`, `connective` and `participant`
	# insertcols!(df1, 2, :file  => File)
	insertcols!(df1, 1, :pause => occursin("Nopause", File) ? "0.0 S" : "0.2 S")
	insertcols!(df1, 1, :connective  => occursin("And", File) ? "And" : "Or")
	insertcols!(df1, 1, :participant => string(SubString(File, 1, 3)))

	# 5. Stack wide format to Long format,
	#     with two new columns: `channel` and `amplitute`
	df1 = stack(df1, Not([:participant, :connective, :pause, :time]),
		variable_name = "channel", value_name = "amplitute")

end;

# ╔═╡ e6ead18b-04c0-444e-8744-1cfa57451af0
# subset!(df, :participant => ByRow(!=("S10")));

# ╔═╡ 6e1a3492-1b81-47ae-9880-a3b8d3f8c675
describe(df)

# ╔═╡ eba0cd43-a11f-4549-93d5-0d2743b39c62
unique(df.participant)

# ╔═╡ a0f52445-1a24-4a84-b4bc-a52c3d9e81f6
nrow(df)

# ╔═╡ 2b5018b1-7723-4ba1-9698-644828e7ac12
unique(df.channel)

# ╔═╡ e0c43f8a-9eb7-4869-94c9-e2aeab49bbb7
md"""
### Statistical model
"""

# ╔═╡ 40ae436e-615c-43bd-a330-ac2730455dff
md"""
Define a function to obtain the p value regarding the difference between the two connectives at a specific time:
"""

# ╔═╡ ac4a35ec-3033-4760-8d3f-49942db117b7
formula =  @formula(amplitute ~ connective);

# ╔═╡ 6c686b26-aa9c-4feb-aab4-426dda517ae3
pv(x) = (coeftable(fit(LinearModel, formula, x)).cols)[4][2];

# ╔═╡ 534d6937-072c-475d-a8da-c913a56fef4b
md"""
### Noun 3: Time by Pause
"""

# ╔═╡ 2d6fd02d-3231-4437-9cc3-4addd3257c89
begin
	# Group by `pause * time * channel * connective` for plotting
	gbp1 = groupby(df, [:pause, :time, :channel, :connective]);

	# Combine the groups
	dfp1 = combine(gbp1, :amplitute => mean => :amplitute);
end;

# ╔═╡ d510f764-bf43-4683-b20c-d32fd282469a
begin
	# 1. Group by `pause * time * channel` for statistics
	gbs1 = groupby(df, [:pause, :time, :channel]);

	# 2. Collect difference between two connectives (p-values) into a vector
	pval = mapreduce(pv, vcat, gbs1)

	# 3. Create a DataFrame based on groups
	gbs1r = DataFrame(keys(gbs1))

	# 4. Insert the pvalues into the created DataFrame
	insertcols!(gbs1r, :pvals => pval)

end;

# ╔═╡ e7b40a4e-9114-4857-87e3-82b949269430
begin
	# 1. Add the obtained p-values into `dfp1`
	dfcj1 = innerjoin(dfp1, gbs1r, on = [:pause, :time, :channel])

	# 2. Subset the significant results
	dfcj1s = subset(dfcj1, :pvals => ByRow(<(.05)))

	# 3. Group by `pause * time * channel`
	dfcj1sg = groupby(dfcj1s, [:pause, :time, :channel, :pvals])

	# 4. Retrieve min and max value for plotting
	dfcj1sgc = combine(dfcj1sg,
		:amplitute => (x -> [extrema(x)]) => [:min, :max]);
end;

# ╔═╡ f81f0b9e-7755-40b6-8e09-b246c139d79b
# Time range where differences were observed
extrema(dfcj1sgc.time)

# ╔═╡ 4220f15b-fd6b-40e3-aef3-d35d5ea24e9d
# Define a function to do the poltting
TimeByPause(chs...) = begin

	sigdata = subset(dfcj1sgc, :channel => ByRow( x -> x .∈ Ref([chs...])) )
	rawdata = subset(dfp1,     :channel => ByRow( x -> x .∈ Ref([chs...])) )

	draw(
		data(sigdata)                                             *
		visual(Rangebars, color = :gray70, linewidth = 3)         *
		mapping(:time, :min, :max, col = :pause, row = :channel)

		+

		data(rawdata)                                             *
		visual(Lines, linewidth = 3)                              *
		mapping(:time, :amplitute,
			col = :pause, row = :channel,
			color = :connective => "Connective:") ;

		axis = (width = 600, height = 300, xticks = -200:100:1000,
			xlabel = "Time (ms) from the onset of Noun 3",
			ylabel = L"Amplitute ($\mu V$)"),

		legend = (position = :bottom, titleposition = :left)
	)
end

# ╔═╡ c6a96b1b-10d8-4d15-a9df-d38ab30f65ac
AFavgTP = TimeByPause("AFavg")

# ╔═╡ 61c09312-d0b2-48b1-8f3c-04f7a77d1a89
save("AFavgTP.pdf", AFavgTP);

# ╔═╡ fa0a13cf-6d32-4f40-8c28-9ddbd5965ad3
md"""
### Noun 3: Time (Average out pause)
"""

# ╔═╡ e2914465-b825-4046-932b-3dc13223c408
begin
	# Group by `pause * time * channel * connective` for plotting
	gbp2 = groupby(df, [:time, :channel, :connective]);

	# Combine the groups
	dfp2 = combine(gbp2, :amplitute => mean => :amplitute);
end;

# ╔═╡ c49c808b-bde4-4112-8a0f-d37143a16db1
begin
	# 1. Group by `pause * time * channel` for statistics
	gbs2 = groupby(df, [:time, :channel]);

	# 2. Collect difference between two connectives (p-values) into a vector
	pval2 = mapreduce(pv, vcat, gbs2)

	# 3. Create a DataFrame based on groups
	gbs2r = DataFrame(keys(gbs2))

	# 4. Insert the pvalues into the created DataFrame
	insertcols!(gbs2r, :pvals => pval2)

end;

# ╔═╡ 66b2c29b-920b-4ca6-b790-fbea021b7636
begin
	# 1. Add the obtained p-values into `dfp1`
	dfcj2 = innerjoin(dfp2, gbs2r, on = [:time, :channel])

	# 2. Subset the significant results
	dfcj2s = subset(dfcj2, :pvals => ByRow(<(.05)))

	# 3. Group by `pause * time * channel`
	dfcj2sg = groupby(dfcj2s, [:time, :channel, :pvals])

	# 4. Retrieve min and max value for plotting
	dfcj2sgc = combine(dfcj2sg,
		:amplitute => (x -> [extrema(x)]) => [:min, :max]);
end;

# ╔═╡ 4e008fc3-f554-4b46-b234-d49543630b37
# Time range where differences were observed
extrema(dfcj1sgc.time)

# ╔═╡ c86cf7ce-4780-495e-bfd8-3a4529181dac
# Define a function to do the poltting
TimeOnly(chs...; height = 300, linewidth = 3) = begin

	sigdata = subset(dfcj2sgc, :channel => ByRow( x -> x .∈ Ref([chs...])) )
	rawdata = subset(dfp2,     :channel => ByRow( x -> x .∈ Ref([chs...])) )

	draw(
		data(sigdata)                                       *
		visual(Rangebars, color = :gray70, linewidth = 3)   *
		mapping(:time, :min, :max, row = :channel)

		+

		data(rawdata)                                       *
		visual(Lines, linewidth = linewidth)                *
		mapping(:time, :amplitute, row = :channel,
			color = :connective  => "Connective:");

		axis = (width = 600, height = height, xticks = -200:100:1000,
			xlabel = "Time (ms) from the onset of Noun 3",
			ylabel = L"Amplitute ($\mu V$)"),

		legend = (position = :bottom, titleposition = :left)
	)
end

# ╔═╡ c20cf0de-2085-4163-838e-be76ccb1a7b6
AFavgT = TimeOnly("AFavg")

# ╔═╡ eebcc255-c6e0-4275-82ec-686f7fe1df12
save("AFavgT.pdf", AFavgT);

# ╔═╡ 9d81457a-94e9-4ed1-b864-260f314c55c4
# TimeOnly("Fp2", "Fpz")

# ╔═╡ 98074da2-12ca-4c6b-81a1-e01234095fad
TmAll = TimeOnly(unique(df.channel)[1:60]...; height = 100, linewidth = 1)

# ╔═╡ 2619c021-43ec-4813-9ad8-9255decdb6fd
save("TmAll.pdf", TmAll);

# ╔═╡ 2bf7bc42-610a-4f44-88e0-b4d6a359e15b
md"""
### Conclusion

- There exists a difference between the conjunction connective `and` and the disjuncitve connective `or`, roughly at the period of N400, baseline corrected on the onset of the third noun.

- It seems that the pause delayed the difference.

- The observed effect is weak, however, because the difference disappear if the familywise errors are corrected.
"""

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
AlgebraOfGraphics = "cbdf2221-f076-402e-a563-3d30da359d67"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
FreqTables = "da1fdf0e-e0ff-5433-a45f-9bb5ff651cb1"
GLM = "38e38edf-8417-5370-95a0-9cbb8c7f171a"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[compat]
AlgebraOfGraphics = "~0.6.0"
CSV = "~0.9.11"
CairoMakie = "~0.6.6"
DataFrames = "~1.3.1"
FreqTables = "~0.4.5"
GLM = "~1.5.1"
PlutoUI = "~0.7.25"
"""

# ╔═╡ 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.AbstractFFTs]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "485ee0867925449198280d4af84bdb46a2a404d0"
uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c"
version = "1.0.1"

[[deps.AbstractPlutoDingetjes]]
deps = ["Pkg"]
git-tree-sha1 = "abb72771fd8895a7ebd83d5632dc4b989b022b5b"
uuid = "6e696c72-6542-2067-7265-42206c756150"
version = "1.1.2"

[[deps.AbstractTrees]]
git-tree-sha1 = "03e0550477d86222521d254b741d470ba17ea0b5"
uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
version = "0.3.4"

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

[[deps.AlgebraOfGraphics]]
deps = ["Colors", "Dates", "FileIO", "GLM", "GeoInterface", "GeometryBasics", "GridLayoutBase", "KernelDensity", "Loess", "Makie", "PlotUtils", "PooledArrays", "RelocatableFolders", "StatsBase", "StructArrays", "Tables"]
git-tree-sha1 = "a79d1facb9fb0cd858e693088aa366e328109901"
uuid = "cbdf2221-f076-402e-a563-3d30da359d67"
version = "0.6.0"

[[deps.Animations]]
deps = ["Colors"]
git-tree-sha1 = "e81c509d2c8e49592413bfb0bb3b08150056c79d"
uuid = "27a7e980-b3e6-11e9-2bcd-0b925532e340"
version = "0.4.1"

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

[[deps.ArrayInterface]]
deps = ["Compat", "IfElse", "LinearAlgebra", "Requires", "SparseArrays", "Static"]
git-tree-sha1 = "265b06e2b1f6a216e0e8f183d28e4d354eab3220"
uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
version = "3.2.1"

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

[[deps.Automa]]
deps = ["Printf", "ScanByte", "TranscodingStreams"]
git-tree-sha1 = "d50976f217489ce799e366d9561d56a98a30d7fe"
uuid = "67c07d97-cdcb-5c2c-af73-a7f9c32a568b"
version = "0.8.2"

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

[[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.CEnum]]
git-tree-sha1 = "215a9aa4a1f23fbd05b92769fdd62559488d70e9"
uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82"
version = "0.4.1"

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

[[deps.Cairo]]
deps = ["Cairo_jll", "Colors", "Glib_jll", "Graphics", "Libdl", "Pango_jll"]
git-tree-sha1 = "d0b3f8b4ad16cb0a2988c6788646a5e6a17b6b1b"
uuid = "159f3aea-2a34-519c-b102-8c37f9878175"
version = "1.0.5"

[[deps.CairoMakie]]
deps = ["Base64", "Cairo", "Colors", "FFTW", "FileIO", "FreeType", "GeometryBasics", "LinearAlgebra", "Makie", "SHA", "StaticArrays"]
git-tree-sha1 = "774ff1cce3ae930af3948c120c15eeb96c886c33"
uuid = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
version = "0.6.6"

[[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.CategoricalArrays]]
deps = ["DataAPI", "Future", "Missings", "Printf", "Requires", "Statistics", "Unicode"]
git-tree-sha1 = "c308f209870fdbd84cb20332b6dfaf14bf3387f8"
uuid = "324d7699-5711-5eae-9e2f-1d82baa6b597"
version = "0.10.2"

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

[[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.ColorBrewer]]
deps = ["Colors", "JSON", "Test"]
git-tree-sha1 = "61c5334f33d91e570e1d0c3eb5465835242582c4"
uuid = "a2cac450-b92f-5266-8821-25eda20663c8"
version = "0.4.0"

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

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

[[deps.ColorVectorSpace]]
deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"]
git-tree-sha1 = "3f1f500312161f1ae067abe07d13b40f78f32e07"
uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4"
version = "0.9.8"

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

[[deps.Combinatorics]]
git-tree-sha1 = "08c8b6831dc00bfea825826be0bc8336fc369860"
uuid = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
version = "1.0.2"

[[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 = "44c37b4636bc54afac5c574d2d02b625349d6582"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.41.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 = "3f71217b538d7aaee0b69ab47d9b7724ca8afa0d"
uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
version = "4.0.4"

[[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 = "cfdfef912b7f93e4b848e80b9befdf9e331bc05a"
uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
version = "1.3.1"

[[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.Distances]]
deps = ["LinearAlgebra", "SparseArrays", "Statistics", "StatsAPI"]
git-tree-sha1 = "3258d0659f812acde79e8a74b11f17ac06d0ca04"
uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7"
version = "0.10.7"

[[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 = "c1724611e6ae29c6094c8d9850e3136297ba7fff"
uuid = "31c24e10-a181-5473-b8eb-7969acd0382f"
version = "0.25.36"

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

[[deps.EllipsisNotation]]
deps = ["ArrayInterface"]
git-tree-sha1 = "3fe985505b4b667e1ae303c9ca64d181f09d5c05"
uuid = "da5c29d0-fa7d-589e-88eb-ea29b0a81949"
version = "1.1.3"

[[deps.Expat_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f"
uuid = "2e619515-83b5-522b-bb60-26c02a35a201"
version = "2.2.10+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.FFTW]]
deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"]
git-tree-sha1 = "463cb335fa22c4ebacfd1faba5fde14edb80d96c"
uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
version = "1.4.5"

[[deps.FFTW_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c6033cc3892d0ef5bb9cd29b7f2f0331ea5184ea"
uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a"
version = "3.3.10+0"

[[deps.FileIO]]
deps = ["Pkg", "Requires", "UUIDs"]
git-tree-sha1 = "2db648b6712831ecb333eae76dbfd1c156ca13bb"
uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
version = "1.11.2"

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

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

[[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.FreeType]]
deps = ["CEnum", "FreeType2_jll"]
git-tree-sha1 = "cabd77ab6a6fdff49bfd24af2ebe76e6e018a2b4"
uuid = "b38be410-82b0-50bf-ab77-7b57e271db43"
version = "4.0.0"

[[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.FreeTypeAbstraction]]
deps = ["ColorVectorSpace", "Colors", "FreeType", "GeometryBasics", "StaticArrays"]
git-tree-sha1 = "770050893e7bc8a34915b4b9298604a3236de834"
uuid = "663a7486-cb36-511b-a19d-713bb74d65c9"
version = "0.9.5"

[[deps.FreqTables]]
deps = ["CategoricalArrays", "Missings", "NamedArrays", "Tables"]
git-tree-sha1 = "488ad2dab30fd2727ee65451f790c81ed454666d"
uuid = "da1fdf0e-e0ff-5433-a45f-9bb5ff651cb1"
version = "0.4.5"

[[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.GLM]]
deps = ["Distributions", "LinearAlgebra", "Printf", "Reexport", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "StatsModels"]
git-tree-sha1 = "f564ce4af5e79bb88ff1f4488e64363487674278"
uuid = "38e38edf-8417-5370-95a0-9cbb8c7f171a"
version = "1.5.1"

[[deps.GeoInterface]]
deps = ["RecipesBase"]
git-tree-sha1 = "f63297cb6a2d2c403d18b3a3e0b7fcb01c0a3f40"
uuid = "cf35fbd7-0cd7-5166-be24-54bfbe79505f"
version = "0.5.6"

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

[[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.Graphics]]
deps = ["Colors", "LinearAlgebra", "NaNMath"]
git-tree-sha1 = "1c5a84319923bea76fa145d49e93aa4394c73fc2"
uuid = "a2bd30eb-e257-5431-a919-1863eab51364"
version = "1.1.1"

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

[[deps.GridLayoutBase]]
deps = ["GeometryBasics", "InteractiveUtils", "Observables"]
git-tree-sha1 = "70938436e2720e6cb8a7f2ca9f1bbdbf40d7f5d0"
uuid = "3955a311-db13-416c-9275-1d80ed98e5e9"
version = "0.6.4"

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

[[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.Hyperscript]]
deps = ["Test"]
git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9"
uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91"
version = "0.0.4"

[[deps.HypertextLiteral]]
git-tree-sha1 = "2b078b5a615c6c0396c77810d92ee8c6f470d238"
uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
version = "0.9.3"

[[deps.IOCapture]]
deps = ["Logging", "Random"]
git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a"
uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
version = "0.2.2"

[[deps.IfElse]]
git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1"
uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
version = "0.1.1"

[[deps.ImageCore]]
deps = ["AbstractFFTs", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Graphics", "MappedArrays", "MosaicViews", "OffsetArrays", "PaddedViews", "Reexport"]
git-tree-sha1 = "9a5c62f231e5bba35695a20988fc7cd6de7eeb5a"
uuid = "a09fc81d-aa75-5fe9-8630-4744c3626534"
version = "0.9.3"

[[deps.ImageIO]]
deps = ["FileIO", "Netpbm", "OpenEXR", "PNGFiles", "TiffImages", "UUIDs"]
git-tree-sha1 = "a2951c93684551467265e0e32b577914f69532be"
uuid = "82e4d734-157c-48bb-816b-45c225c6df19"
version = "0.5.9"

[[deps.Imath_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "87f7662e03a649cffa2e05bf19c303e168732d3e"
uuid = "905a6f67-0a94-5f89-b386-d35d92009cd1"
version = "3.1.2+0"

[[deps.IndirectArrays]]
git-tree-sha1 = "012e604e1c7458645cb8b436f8fba789a51b257f"
uuid = "9b13fd28-a010-5f03-acff-a1bbcff69959"
version = "1.0.0"

[[deps.Inflate]]
git-tree-sha1 = "f5fc07d4e706b84f72d54eedcc1c13d92fb0871c"
uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9"
version = "0.1.2"

[[deps.InlineStrings]]
deps = ["Parsers"]
git-tree-sha1 = "8d70835a3759cdd75881426fced1508bb7b7e1b6"
uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48"
version = "1.1.1"

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

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

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

[[deps.IntervalSets]]
deps = ["Dates", "EllipsisNotation", "Statistics"]
git-tree-sha1 = "3cc368af3f110a767ac786560045dceddfc16758"
uuid = "8197267c-284f-5f27-9208-e0e47529a953"
version = "0.5.3"

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

[[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.Isoband]]
deps = ["isoband_jll"]
git-tree-sha1 = "f9b6d97355599074dc867318950adaa6f9946137"
uuid = "f1662d9f-8043-43de-a69a-05efc1cc6ff4"
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 = "642a199af8b68253517b80bd3bfd17eb4e84df6e"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.3.0"

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

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

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

[[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.LazyArtifacts]]
deps = ["Artifacts", "Pkg"]
uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3"

[[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.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.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.Loess]]
deps = ["Distances", "LinearAlgebra", "Statistics"]
git-tree-sha1 = "46efcea75c890e5d820e670516dc156689851722"
uuid = "4345ca2d-374a-55d4-8d30-97f9976e7612"
version = "0.5.4"

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

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

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

[[deps.Makie]]
deps = ["Animations", "Base64", "ColorBrewer", "ColorSchemes", "ColorTypes", "Colors", "Contour", "Distributions", "DocStringExtensions", "FFMPEG", "FileIO", "FixedPointNumbers", "Formatting", "FreeType", "FreeTypeAbstraction", "GeometryBasics", "GridLayoutBase", "ImageIO", "IntervalSets", "Isoband", "KernelDensity", "LaTeXStrings", "LinearAlgebra", "MakieCore", "Markdown", "Match", "MathTeXEngine", "Observables", "Packing", "PlotUtils", "PolygonOps", "Printf", "Random", "RelocatableFolders", "Serialization", "Showoff", "SignedDistanceFields", "SparseArrays", "StaticArrays", "Statistics", "StatsBase", "StatsFuns", "StructArrays", "UnicodeFun"]
git-tree-sha1 = "56b0b7772676c499430dc8eb15cfab120c05a150"
uuid = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
version = "0.15.3"

[[deps.MakieCore]]
deps = ["Observables"]
git-tree-sha1 = "7bcc8323fb37523a6a51ade2234eee27a11114c8"
uuid = "20f20a25-4f0e-4fdf-b5d1-57303727442b"
version = "0.1.3"

[[deps.MappedArrays]]
git-tree-sha1 = "e8b359ef06ec72e8c030463fe02efe5527ee5142"
uuid = "dbb5928d-eab1-5f90-85c2-b9b0edb7c900"
version = "0.4.1"

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

[[deps.Match]]
git-tree-sha1 = "1d9bc5c1a6e7ee24effb93f175c9342f9154d97f"
uuid = "7eb4fadd-790c-5f42-8a69-bfa0b872bfbf"
version = "1.2.0"

[[deps.MathTeXEngine]]
deps = ["AbstractTrees", "Automa", "DataStructures", "FreeTypeAbstraction", "GeometryBasics", "LaTeXStrings", "REPL", "RelocatableFolders", "Test"]
git-tree-sha1 = "70e733037bbf02d691e78f95171a1fa08cdc6332"
uuid = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53"
version = "0.2.1"

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

[[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.MosaicViews]]
deps = ["MappedArrays", "OffsetArrays", "PaddedViews", "StackViews"]
git-tree-sha1 = "b34e3bc3ca7c94914418637cb10cc4d1d80d877d"
uuid = "e94cdb99-869f-56ef-bcf0-1ae2bcbe0389"
version = "0.3.3"

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

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

[[deps.NamedArrays]]
deps = ["Combinatorics", "DataStructures", "DelimitedFiles", "InvertedIndices", "LinearAlgebra", "Random", "Requires", "SparseArrays", "Statistics"]
git-tree-sha1 = "2fd5787125d1a93fbe30961bd841707b8a80d75b"
uuid = "86f7a689-2022-50b4-a561-43c23ac3c673"
version = "0.9.6"

[[deps.Netpbm]]
deps = ["FileIO", "ImageCore"]
git-tree-sha1 = "18efc06f6ec36a8b801b23f076e3c6ac7c3bf153"
uuid = "f09324ee-3d7c-5217-9330-fc30815ba969"
version = "1.0.2"

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

[[deps.Observables]]
git-tree-sha1 = "fe29afdef3d0c4a8286128d4e45cc50621b1e43d"
uuid = "510215fc-4207-5dde-b226-833fc4488ee2"
version = "0.4.0"

[[deps.OffsetArrays]]
deps = ["Adapt"]
git-tree-sha1 = "043017e0bdeff61cfbb7afeb558ab29536bbb5ed"
uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
version = "1.10.8"

[[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.OpenEXR]]
deps = ["Colors", "FileIO", "OpenEXR_jll"]
git-tree-sha1 = "327f53360fdb54df7ecd01e96ef1983536d1e633"
uuid = "52e1d378-f018-4a11-a4be-720524705ac7"
version = "0.3.2"

[[deps.OpenEXR_jll]]
deps = ["Artifacts", "Imath_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "923319661e9a22712f24596ce81c54fc0366f304"
uuid = "18a262bb-aa17-5467-a713-aee519bc75cb"
version = "3.1.1+0"

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

[[deps.OpenSSL_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "15003dcb7d8db3c6c857fda14891a539a8f2705a"
uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
version = "1.1.10+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 = "ee26b350276c51697c9c2d88a072b339f9f03d73"
uuid = "90014a1f-27ba-587c-ab20-58faa44d9150"
version = "0.11.5"

[[deps.PNGFiles]]
deps = ["Base64", "CEnum", "ImageCore", "IndirectArrays", "OffsetArrays", "libpng_jll"]
git-tree-sha1 = "6d105d40e30b635cfed9d52ec29cf456e27d38f8"
uuid = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883"
version = "0.3.12"

[[deps.Packing]]
deps = ["GeometryBasics"]
git-tree-sha1 = "1155f6f937fa2b94104162f01fa400e192e4272f"
uuid = "19eb6ba3-879d-56ad-ad62-d5c202156566"
version = "0.4.2"

[[deps.PaddedViews]]
deps = ["OffsetArrays"]
git-tree-sha1 = "646eed6f6a5d8df6708f15ea7e02a7a2c4fe4800"
uuid = "5432bcbf-9aad-5242-b902-cca2824c8663"
version = "0.5.10"

[[deps.Pango_jll]]
deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "FriBidi_jll", "Glib_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "9bc1871464b12ed19297fbc56c4fb4ba84988b0d"
uuid = "36c8627f-9965-5494-a995-c6b170f724f3"
version = "1.47.0+0"

[[deps.Parsers]]
deps = ["Dates"]
git-tree-sha1 = "d7fa6237da8004be601e19bd6666083056649918"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.1.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.PkgVersion]]
deps = ["Pkg"]
git-tree-sha1 = "a7a7e1a88853564e551e4eba8650f8c38df79b37"
uuid = "eebad327-c553-4316-9ea0-9fa01ccd7688"
version = "0.1.1"

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

[[deps.PlutoUI]]
deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "UUIDs"]
git-tree-sha1 = "93cf0910f09a9607add290a3a2585aa376b4feb6"
uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
version = "0.7.25"

[[deps.PolygonOps]]
git-tree-sha1 = "77b3d3605fc1cd0b42d95eba87dfcd2bf67d5ff6"
uuid = "647866c9-e3ac-4575-94e7-e3d426903924"
version = "0.1.2"

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

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

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

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

[[deps.ProgressMeter]]
deps = ["Distributed", "Printf"]
git-tree-sha1 = "afadeba63d90ff223a6a48d2009434ecee2ec9e8"
uuid = "92933f4c-e287-5a05-a399-4b506db050ca"
version = "1.7.1"

[[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.Ratios]]
deps = ["Requires"]
git-tree-sha1 = "01d341f502250e81f6fec0afe662aa861392a3aa"
uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439"
version = "0.4.2"

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

[[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 = "8f82019e525f4d5c669692772a6f4b0a58b06a6a"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.2.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.SIMD]]
git-tree-sha1 = "9ba33637b24341aba594a2783a502760aa0bff04"
uuid = "fdea26ae-647d-5447-a871-4b548cad5224"
version = "3.3.1"

[[deps.ScanByte]]
deps = ["Libdl", "SIMD"]
git-tree-sha1 = "9cc2955f2a254b18be655a4ee70bc4031b2b189e"
uuid = "7b38b023-a4d7-4c5e-8d43-3f3097f304eb"
version = "0.3.0"

[[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 = "244586bc07462d22aed0113af9c731f2a518c93e"
uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c"
version = "1.3.10"

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

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

[[deps.ShiftedArrays]]
git-tree-sha1 = "22395afdcf37d6709a5a0766cc4a5ca52cb85ea0"
uuid = "1277b4bf-5013-50f5-be3d-901d8477a67a"
version = "1.0.0"

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

[[deps.SignedDistanceFields]]
deps = ["Random", "Statistics", "Test"]
git-tree-sha1 = "d263a08ec505853a5ff1c1ebde2070419e3f28e9"
uuid = "73760f76-fbc4-59ce-8f25-708e95d2df96"
version = "0.4.0"

[[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 = "f0bccf98e16759818ffc5d97ac3ebf87eb950150"
uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
version = "1.8.1"

[[deps.StackViews]]
deps = ["OffsetArrays"]
git-tree-sha1 = "46e589465204cd0c08b4bd97385e4fa79a0c770c"
uuid = "cae243ae-269e-4f55-b966-ac2d0dc13c15"
version = "0.1.1"

[[deps.Static]]
deps = ["IfElse"]
git-tree-sha1 = "7f5a513baec6f122401abfc8e9c074fdac54f6c1"
uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
version = "0.4.1"

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

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

[[deps.StatsAPI]]
git-tree-sha1 = "0f2aa8e32d511f758a2ce49208181f7733a0936a"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.1.0"

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

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

[[deps.StatsModels]]
deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Printf", "REPL", "ShiftedArrays", "SparseArrays", "StatsBase", "StatsFuns", "Tables"]
git-tree-sha1 = "677488c295051568b0b79a77a8c44aa86e78b359"
uuid = "3eaba693-59b7-5ba5-a881-562e759f1c8d"
version = "0.6.28"

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

[[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", "TableTraits", "Test"]
git-tree-sha1 = "bb1064c9a84c52e277f1096cf41434b675cd368b"
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
version = "1.6.1"

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

[[deps.TensorCore]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6"
uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50"
version = "0.1.1"

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

[[deps.TiffImages]]
deps = ["ColorTypes", "DataStructures", "DocStringExtensions", "FileIO", "FixedPointNumbers", "IndirectArrays", "Inflate", "OffsetArrays", "PkgVersion", "ProgressMeter", "UUIDs"]
git-tree-sha1 = "c342ae2abf4902d65a0b0bf59b28506a6e17078a"
uuid = "731e570b-9d59-4bfa-96dc-6df516fadf69"
version = "0.5.2"

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

[[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.WeakRefStrings]]
deps = ["DataAPI", "InlineStrings", "Parsers"]
git-tree-sha1 = "c69f9da3ff2f4f02e811c3323c22e5dfcb584cfa"
uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5"
version = "1.4.1"

[[deps.WoodburyMatrices]]
deps = ["LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "de67fa59e33ad156a590055375a30b23c40299d3"
uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6"
version = "0.5.5"

[[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_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_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_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.isoband_jll]]
deps = ["Libdl", "Pkg"]
git-tree-sha1 = "a1ac99674715995a536bbce674b068ec1b7d893d"
uuid = "9a68df92-36a6-505f-a73e-abb412b6bfb4"
version = "0.2.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"
"""

# ╔═╡ Cell order:
# ╟─c8f6136d-a7a0-4a25-842e-b76a30444d08
# ╟─23d7a0d4-6704-4f16-812a-a68c5fcf01d7
# ╠═141ce59d-ca9d-464e-b642-90a10adadc18
# ╠═ecf79151-b628-4a04-bed8-ababb5743420
# ╠═fc96a1a8-0b70-4437-8df3-d8bbc355a5ab
# ╠═d4863f7d-ddde-4c8d-b960-ac0b1ed27aed
# ╠═051d9767-42c6-47a3-b832-f58ad0a15c4f
# ╟─0d093f1d-918b-48f4-965e-0e711a7a4eae
# ╟─17c8b2cc-77de-4998-8dce-9ec2e3927cb0
# ╟─48c903d8-413b-4e62-ae03-84aca4552a57
# ╠═91923052-5ee4-11ec-09cf-33cdea5e9d3b
# ╠═d2e6e365-d026-4f23-a194-1c6a02bd8eb0
# ╠═bb0f7c02-9f48-431d-88d3-7e9bbaa96c34
# ╠═e6ead18b-04c0-444e-8744-1cfa57451af0
# ╠═6e1a3492-1b81-47ae-9880-a3b8d3f8c675
# ╠═eba0cd43-a11f-4549-93d5-0d2743b39c62
# ╠═a0f52445-1a24-4a84-b4bc-a52c3d9e81f6
# ╠═2b5018b1-7723-4ba1-9698-644828e7ac12
# ╟─e0c43f8a-9eb7-4869-94c9-e2aeab49bbb7
# ╟─40ae436e-615c-43bd-a330-ac2730455dff
# ╠═ac4a35ec-3033-4760-8d3f-49942db117b7
# ╠═6c686b26-aa9c-4feb-aab4-426dda517ae3
# ╟─534d6937-072c-475d-a8da-c913a56fef4b
# ╠═2d6fd02d-3231-4437-9cc3-4addd3257c89
# ╠═d510f764-bf43-4683-b20c-d32fd282469a
# ╠═e7b40a4e-9114-4857-87e3-82b949269430
# ╠═f81f0b9e-7755-40b6-8e09-b246c139d79b
# ╠═4220f15b-fd6b-40e3-aef3-d35d5ea24e9d
# ╠═c6a96b1b-10d8-4d15-a9df-d38ab30f65ac
# ╠═61c09312-d0b2-48b1-8f3c-04f7a77d1a89
# ╟─fa0a13cf-6d32-4f40-8c28-9ddbd5965ad3
# ╠═e2914465-b825-4046-932b-3dc13223c408
# ╠═c49c808b-bde4-4112-8a0f-d37143a16db1
# ╠═66b2c29b-920b-4ca6-b790-fbea021b7636
# ╠═4e008fc3-f554-4b46-b234-d49543630b37
# ╠═c86cf7ce-4780-495e-bfd8-3a4529181dac
# ╠═c20cf0de-2085-4163-838e-be76ccb1a7b6
# ╠═eebcc255-c6e0-4275-82ec-686f7fe1df12
# ╠═9d81457a-94e9-4ed1-b864-260f314c55c4
# ╠═98074da2-12ca-4c6b-81a1-e01234095fad
# ╠═2619c021-43ec-4813-9ad8-9255decdb6fd
# ╟─2bf7bc42-610a-4f44-88e0-b4d6a359e15b
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


text:
"""
    AbstractSolver{T} <: MathOptInterface.AbstractNLPEvaluator

Abstract solver for trajectory optimization problems

# Interface
Any type that inherits from `AbstractSolver` must define the following methods:
```julia
model = get_model(::AbstractSolver)::AbstractModel
obj   = get_objective(::AbstractSolver)::AbstractObjective
E     = get_cost_expansion(::AbstractSolver)::QuadraticExpansion  # quadratic error state expansion
Z     = get_trajectory(::AbstractSolver)::Traj
n,m,N = Base.size(::AbstractSolver)
x0    = get_initial_state(::AbstractSolver)::StaticVector
solve!(::AbstractSolver)
```

Optional methods for line search and merit function interface. Note that these do not
    have to return `Traj`
```julia
Z     = get_solution(::AbstractSolver)  # current solution (defaults to get_trajectory)
Z     = get_primals(::AbstractSolver)   # current primals estimate used in the line search
dZ    = get_step(::AbstractSolver)      # current step in the primal variables
```

Optional methods
```julia
opts  = options(::AbstractSolver)       # options struct for the solver. Defaults to `solver.opts`
st    = solver_stats(::AbstractSolver)  # dictionary of solver statistics. Defaults to `solver.stats`
iters = iterations(::AbstractSolver)    #
```
"""
abstract type AbstractSolver{T} end

"$(TYPEDEF) Unconstrained optimization solver. Will ignore
any constraints in the problem"
abstract type UnconstrainedSolver{T} <: AbstractSolver{T} end

"""$(TYPEDEF)
Abstract solver for constrained trajectory optimization problems

In addition to the methods required for `AbstractSolver`, all `ConstrainedSolver`s
    must define the following method
```julia
get_constraints(::ConstrainedSolver)::ConstrainSet
```
"""
abstract type ConstrainedSolver{T} <: AbstractSolver{T} end

# methods
@inline iterations(solver::AbstractSolver) = solver.stats.iterations
@inline status(solver::AbstractSolver) = solver.stats.status
@inline is_constrained(::Type{<:AbstractSolver})::Bool = true
@inline is_constrained(::Type{<:ConstrainedSolver})::Bool = true
@inline is_constrained(::Type{<:UnconstrainedSolver})::Bool = false
@inline is_constrained(solver::AbstractSolver) = is_constrained(typeof(solver)) && !isempty(get_constraints(solver))

"""
    terminate!(solver::AbstractSolver)

Perform any necessary actions after finishing the solve.
"""
function terminate!(solver::AbstractSolver)
    # Time solve
    stat = solver.stats
    stat.tsolve = (time_ns() - stat.tstart)*1e-6  # in ms

    # Delete extra stats entries, only if terminal solver
    trim!(solver.stats, solver.solver_name)

    # Print solve summary
    if solver.opts.show_summary && is_parentsolver(solver)
        print_summary(solver)
    end
end

"""
    TerminationStatus

* `UNSOLVED`: Initial value. Solve either hasn't been attempted or is in process..
* `SOLVE_SUCCEEDED`: Solve met all the required convergence criteria.
* `MAX_ITERATIONS`: Solve was unable to meet the required convergence criteria within the maximum number of iterations.
* `MAX_ITERATIONS_OUTER`: Solve was unable to meet the required constraint satisfaction the maximum number of outer loop iterations.
* `MAXIMUM_COST`: Cost exceeded maximum allowable cost.
* `STATE_LIMIT`: State values exceeded the imposed numerical limits.
* `CONTROL_LIMIT`: Control values exceeded the imposed numerical limits.
* `NO_PROGRESS`: iLQR was unable to make any progress for `dJ_counter_limit` consecutive iterations.
* `COST_INCREASE`: The cost increased during the iLQR forward pass.
"""
@enum TerminationStatus begin
    UNSOLVED = 1
    MAX_ITERATIONS_OUTER = 2
    MAX_ITERATIONS = 3
    SOLVE_SUCCEEDED = 4
    MAXIMUM_COST = 5
    STATE_LIMIT = 6
    CONTROL_LIMIT = 7
    NO_PROGRESS = 8
    COST_INCREASE = 9
end

function print_summary(solver::S) where S <: AbstractSolver
    stat = stats(solver)
    col_h1 = crayon"bold green"
    col_h2 = crayon"bold blue"
    col0 = Crayon(reset=true)
    get_color(v::Bool) = v ? crayon"green" : crayon"red"

    # Info header
    println(col_h1, "\nSOLVE COMPLETED")
    print(col0," solved using the ")
    print(col0, crayon"bold cyan", solvername(solver))
    print(col0, " Solver,\n part of the Altro.jl package developed by the REx Lab at Stanford and Carnegie Mellon Universities\n")

    # Stats
    println(col_h2, "\n  Solve Statistics")
    println(col0, "    Total Iterations: ", iterations(solver))
    println(col0, "    Solve Time: ", stat.tsolve, " (ms)")

    # Convergence
    println(col_h2, "\n  Covergence")
    if iterations(solver) == 0
        println(crayon"red", "    Solver failed to make it through the first iteration.")
    else
        println(col0, "    Terminal Cost: ", stat.cost[end])
        println(col0, "    Terminal dJ: ", get_color(stat.dJ[end] < solver.opts.cost_tolerance), stat.dJ[end])
        println(col0, "    Terminal gradient: ", get_color(stat.gradient[end] < solver.opts.gradient_tolerance), stat.gradient[end])
        if is_constrained(solver)
            println(col0, "    Terminal constraint violation: ", get_color(stat.c_max[end] < solver.opts.constraint_tolerance), stat.c_max[end])
        end
    end
    println(col0, "    Solve Status: ", crayon"bold", get_color(status(solver) == SOLVE_SUCCEEDED), status(solver))
    print(Crayon(reset=true))  # reset output color
end

# logging

log_level(solver::AbstractSolver) = OuterLoop

is_verbose(solver::AbstractSolver) =
    log_level(solver) >= LogLevel(-100*solver.opts.verbose)

function set_verbosity!(solver::AbstractSolver)
    llevel = log_level(solver)
    if is_verbose(solver)
        set_logger()
        Logging.disable_logging(LogLevel(llevel.level-1))
    else
        Logging.disable_logging(llevel)
    end
end

function clear_cache!(solver::AbstractSolver)
    llevel = log_level(solver)
    if is_verbose(solver)
        SolverLogging.clear_cache!(global_logger().leveldata[llevel])
    end
end