text:
# https://github.com/sisl/PGFPlots.jl

supportedArgs(::PGFPlotsBackend) = [
    # :annotation,
    # :axis,
     :background_color,
    # :color_palette,
    # :fillrange,
     :fillcolor,
     :fillalpha,
    # :foreground_color,
    # :group,
    # :label,
    # :layout,
    # :legend,
     :seriescolor, :seriesalpha,
     :linecolor,
     :linestyle,
     :linetype,
     :linewidth,
     :linealpha,
     :markershape,
     :markercolor,
     :markersize,
     :markeralpha,
    # :markerstrokewidth,
     :markerstrokecolor,
     :markerstrokestyle,
    # :n,
    # :bins,
    # :nc,
    # :nr,
    # :pos,
    # :smooth,
    # :show,
    # :size,
     :title,
    # :windowtitle,
     :x,
     :xlabel,
     :xlims,
    # :xticks,
     :y,
     :ylabel,
     :ylims,
    # :yrightlabel,
    # :yticks,
     :xscale,
     :yscale,
     :xflip,
     :yflip,
     :z,
     :zscale,
    # :tickfont,
    # :guidefont,
    # :legendfont,
     :grid,
    # :surface
    # :levels,
  ]
supportedAxes(::PGFPlotsBackend) = [:auto, :left]
supportedTypes(::PGFPlotsBackend) = [:path, :path3d, :scatter, :line, :steppre, :stepmid, :steppost, :hist, :bar, :hist2d, :sticks, :ysticks, :xsticks, :contour] #  :hexbin, :hline, :vline,]
supportedStyles(::PGFPlotsBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::PGFPlotsBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape)
supportedScales(::PGFPlotsBackend) = [:identity, :log, :ln, :log2, :log10] # :asinh, :sqrt]
subplotSupported(::PGFPlotsBackend) = false

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

function _initialize_backend(::PGFPlotsBackend; kw...)
  @eval begin
    import PGFPlots
    export PGFPlots
    # TODO: other initialization that needs to be eval-ed
  end
  # TODO: other initialization
end
const _pgfplots_linestyles = KW(
    :solid => "solid",
    :dash => "dashed",
    :dot => "dotted",
    :dashdot => "dashdotted",
    :dashdotdot => "dashdotdotted"
)

const _pgfplots_markers = KW(
    :none => "mark = none,",
    :cross => "mark = +,",
    :xcross => "mark = x,",
    :utriangle => "mark = triangle*,",
    :dtriangle => "mark = triangle*,",
    :ellipse => "mark = o*,",
    :rect => "mark = square*,",
    :star5 => "mark = star,",
    :star6 => "mark = asterisk,",
    :diamond => "mark = diamond*,",
    :pentagon => "mark = pentagon*,"
)

function _pgfplots_get_color(kwargs, symb)
    c = typeof(kwargs[symb]) == Symbol ? convertColor(kwargs[symb]) : kwargs[symb].c
    "{rgb,1:red,$(float(c.r));green,$(float(c.g));blue,$(float(c.b))}"
end

function _pgfplots_get_linestyle!(kwargs, plt)
    ls = plt[:linestyle]
    if haskey(_pgfplots_linestyles, ls)
        kwargs[:style] *= _pgfplots_linestyles[ls]*","
    end

    kwargs[:style] *= "line width = $(plt[:linewidth]) pt"*","
end

function _pgfplots_get_marker!(kwargs, plt)
    # Control marker shape
    mark = plt[:markershape]
    kwargs[:style] *= _pgfplots_markers[mark]

    # Control marker size
    kwargs[:style] *= "mark size = $(plt[:markersize]/2),"

    # Control marker colors and alphas
    α = plt[:markeralpha] == nothing ? 1.0 : plt[:markeralpha]
    kwargs[:style] *= "mark options = {color=$(_pgfplots_get_color(plt, :markerstrokecolor)),"
    kwargs[:style] *= mark == :dtriangle ? "rotate=180," : ""
    kwargs[:style] *= "fill=$(_pgfplots_get_color(plt, :markercolor)),"
    kwargs[:style] *= "fill opacity = $α,"
    markstrokestyle = plt[:markerstrokestyle]
    if haskey(_pgfplots_linestyles, markstrokestyle)
        kwargs[:style] *= _pgfplots_linestyles[markstrokestyle]
    end
    kwargs[:style] *= "},"
end

function _pgfplots_get_series_color!(kwargs, plt)
    α = plt[:seriesalpha] == nothing ? 1.0 : plt[:seriesalpha]
    kwargs[:style] *= "color=$(_pgfplots_get_color(plt, :seriescolor)),"
    kwargs[:style] *= "draw opacity = $α,"
end

function _pgfplots_get_line_color!(kwargs, plt)
    α = plt[:linealpha] == nothing ? 1.0 : plt[:linealpha]
    kwargs[:style] *= "color=$(_pgfplots_get_color(plt, :linecolor)),"
    kwargs[:style] *= "draw opacity = $α,"
end

function _pgfplots_get_fill_color!(kwargs, plt)
    α = plt[:fillalpha] == nothing ? 1.0 : plt[:fillalpha]
    kwargs[:style] *= "fill=$(_pgfplots_get_color(plt, :fillcolor)),"
    kwargs[:style] *= "fill opacity = $α,"
end

function _pgfplots_get_plot_kwargs(plt)
    kwargs = KW()
    kwargs[:style] = ""
    _pgfplots_get_linestyle!(kwargs, plt)
    _pgfplots_get_marker!(kwargs, plt)
    _pgfplots_get_series_color!(kwargs, plt)
    kwargs
end

function _pgfplots_axis(plt_series)
    line_type = plt_series[:linetype]
    plt_kwargs = _pgfplots_get_plot_kwargs(plt_series)
        if line_type == :path
        PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
    elseif line_type == :path3d
        PGFPlots.Linear3(plt_series[:x], plt_series[:y], plt_series[:z]; plt_kwargs...)
    elseif line_type == :scatter
        PGFPlots.Scatter(plt_series[:x], plt_series[:y]; plt_kwargs...)
    elseif line_type == :steppre
        plt_kwargs[:style] *= "const plot mark right,"
        PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
    elseif line_type == :stepmid
        plt_kwargs[:style] *= "const plot mark mid,"
        PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
    elseif line_type == :steppost
        plt_kwargs[:style] *= "const plot,"
        PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
    elseif line_type == :hist
        #TODO patch this in PGFPlots.jl instead; the problem is that PGFPlots will
        # save _all_ data points in the figure which can be quite heavy
        plt_hist = hist(plt_series[:y])
        plt_kwargs[:style] *= "ybar interval,"
        _pgfplots_get_line_color!(plt_kwargs, plt_series)
        _pgfplots_get_fill_color!(plt_kwargs, plt_series)
        PGFPlots.Linear(plt_hist[1][1:end-1]+plt_hist[1].step/2, plt_hist[2]; plt_kwargs...)
    elseif line_type == :hist2d
        PGFPlots.Histogram2(plt_series[:x], plt_series[:y])
    elseif line_type == :bar
        plt_kwargs[:style] *= "ybar,"
        _pgfplots_get_line_color!(plt_kwargs, plt_series)
        _pgfplots_get_fill_color!(plt_kwargs, plt_series)
        PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
    elseif line_type == :sticks || line_type == :ysticks
        plt_kwargs[:style] *= "ycomb"
        PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
    elseif line_type == :xsticks
        plt_kwargs[:style] *= "xcomb"
        PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...)
    elseif line_type == :contour
        PGFPlots.Contour(plt_series[:z].surf, plt_series[:x], plt_series[:y])
    end
end

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

function _create_plot(pkg::PGFPlotsBackend, d::KW)
  # TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
  # TODO: initialize the plot... title, xlabel, bgcolor, etc
  Plot(nothing, pkg, 0, d, KW[])
end

function _add_series(::PGFPlotsBackend, plt::Plot, d::KW)
  # TODO: add one series to the underlying package
  push!(plt.seriesargs, d)
  plt
end

function _add_annotations{X,Y,V}(plt::Plot{PGFPlotsBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
  # set or add to the annotation_list
  if haskey(plt.plotargs, :annotation_list)
    append!(plt.plotargs[:annotation_list], anns)
  else
    plt.plotargs[:annotation_list] = anns
  end
end

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

function _before_update_plot(plt::Plot{PGFPlotsBackend})
end

# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot(plt::Plot{PGFPlotsBackend}, d::KW)
end

function _update_plot_pos_size(plt::AbstractPlot{PGFPlotsBackend}, d::KW)
end

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

# accessors for x/y data

# function getxy(plt::Plot{PGFPlotsBackend}, i::Int)
#   d = plt.seriesargs[i]
#   d[:x], d[:y]
# end
#
# function setxy!{X,Y}(plt::Plot{PGFPlotsBackend}, xy::Tuple{X,Y}, i::Integer)
#   d = plt.seriesargs[i]
#   d[:x], d[:y] = xy
#   plt
# end

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

function _create_subplot(subplt::Subplot{PGFPlotsBackend}, isbefore::Bool)
  # TODO: build the underlying Subplot object.  this is where you might layout the panes within a GUI window, for example
  true
end

function _expand_limits(lims, plt::Plot{PGFPlotsBackend}, isx::Bool)
  # TODO: call expand limits for each plot data
end

function _remove_axis(plt::Plot{PGFPlotsBackend}, isx::Bool)
  # TODO: if plot is inner subplot, might need to remove ticks or axis labels
end

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

function _pgfplots_get_axis_kwargs(d)
    axisargs = KW()
    for arg in (:xlabel, :ylabel, :zlabel, :title)
        axisargs[arg] = d[arg]
    end
    axisargs[:style] = ""
    axisargs[:style] *= d[:xflip] == true ? "x dir=reverse," : ""
    axisargs[:style] *= d[:yflip] == true ? "y dir=reverse," : ""
    if d[:xscale] in (:log, :log2, :ln, :log10)
        axisargs[:xmode] = "log"
        if d[:xscale] == :log2
            axisargs[:style] *= "log basis x=2,"
        elseif d[:xscale] in (:log, :log10)
            axisargs[:style] *= "log basis x=10,"
        end
    end
    if d[:yscale] in (:log, :log2, :ln, :log10)
        axisargs[:ymode] = "log"
        if d[:yscale] == :log2
            axisargs[:style] *= "log basis y=2,"
        elseif d[:yscale] in (:log, :log10)
            axisargs[:style] *= "log basis x=10,"
        end
    end
    if d[:zscale] in (:log, :log2, :ln, :log10)
        axisargs[:zmode] = "log"
        if d[:zscale] == :log2
            axisargs[:style] *= "log basis z=2,"
        elseif d[:zscale] in (:log, :log10)
            axisargs[:style] *= "log basis x=10,"
        end
    end

    # Control background color
    axisargs[:style] *= "axis background/.style={fill=$(_pgfplots_get_color(d, :background_color))},"
    # Control x/y-limits
    if d[:xlims] !== :auto
        axisargs[:xmin] = d[:xlims][1]
        axisargs[:xmax] = d[:xlims][2]
    end
    if d[:ylims] !== :auto
        axisargs[:ymin] = d[:ylims][1]
        axisargs[:ymax] = d[:ylims][2]
    end
    if d[:grid] == true
        axisargs[:style] *= "grid = major"
    elseif d[:grid] == false

    end

    axisargs
end

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

#################  This is the important method to implement!!! #################
function _make_pgf_plot(plt::Plot{PGFPlotsBackend})
    os = [_pgfplots_axis(plt_series) for plt_series in plt.seriesargs]
    axisargs  =_pgfplots_get_axis_kwargs(plt.plotargs)
    plt.o = PGFPlots.Axis([os...]; axisargs...)
end

function Base.writemime(io::IO, mime::MIME"image/svg+xml", plt::AbstractPlot{PGFPlotsBackend})
  plt.o = _make_pgf_plot(plt)
  writemime(io, mime, plt.o)
end

# function Base.writemime(io::IO, ::MIME"text/html", plt::AbstractPlot{PGFPlotsBackend})
# end

function Base.display(::PlotsDisplay, plt::AbstractPlot{PGFPlotsBackend})
  plt.o = _make_pgf_plot(plt)
  display(plt.o)
end

# function Base.display(::PlotsDisplay, plt::Subplot{PGFPlotsBackend})
#   # TODO: display/show the subplot
# end


text:
abstract type InjectLocation end

struct InjectByPrependingToMessage <: InjectLocation end
struct InjectByAddingToKwargs <: InjectLocation end

#const date_format = "yyyy-mm-dd HH:MM:SS"
struct TimestampLoggingFormat{T<: DateFormat, S <: InjectLocation}
    date_format::T
    location::S
end

TimestampLoggingFormat(fmt::AbstractString, location) =
    TimestampLoggingFormat(DateFormat(fmt), location)

function logger(L::AbstractLogger, fmt::TimestampLoggingFormat)
    return TransformerLogger(L) do log
        formatted_datetime = Dates.format(now(), fmt.date_format)
        inject_log(log, formatted_datetime, fmt.location)
    end
end

function inject_log(log, ts::AbstractString, location::InjectByPrependingToMessage)
    return merge(log, (; message = "$ts $(log.message)"))
end

function inject_log(log, ts::AbstractString, location::InjectByAddingToKwargs)
    updated_kwargs = (:timestamp => ts, log.kwargs...)
    return merge(log, (; kwargs = updated_kwargs))
end

struct OneLineLoggingFormat
end

function logger(L::AbstractLogger, fmt::OneLineLoggingFormat)
    return TransformerLogger(L) do log
           kw_string = join(["$(kv[1])=$(kv[2])" for kv in log.kwargs], " ")
           return merge(log, (;message="$(log.message) $kw_string", kwargs= ()))
    end
end

struct JSONLoggingFormat
    indent::Union{Nothing,Int}
end

function logger(L::AbstractLogger, fmt::JSONLoggingFormat)
    return TransformerLogger(L) do log
        dct = Dict{Any, Any}(log.kwargs)
        push!(dct, :message => log.message)
        push!(dct, :level => string(log.level))
        kw_string = fmt.indent === nothing ? json(dct) : json(dct, fmt.indent)
        return merge(log, (;message= "$kw_string", kwargs= ()))
    end
end

ext: jl


text:
function PDE_solver(X_domain, X_boundary, max_iter, step_size, sol, L)
    N_domain = size(X_domain)[1]
    N_boundary = size(X_boundary)[1]
    rhs_f = zeros((N_domain,1))
    bdy_g = zeros((N_boundary,1))

    for iter_i = 1:N_domain
        rhs_f[iter_i] = f(X_domain[iter_i,1],X_domain[iter_i,2])
    end
    for iter_i = 1:N_boundary
        bdy_g[iter_i] = g(X_boundary[iter_i,1],X_boundary[iter_i,2])
    end

    J_array = zeros((max_iter+1,1))
    for iter_step = 1:max_iter
        temp_mtx = hcat(alpha*m*Diagonal((sol[:]).^(m-1)), Matrix(1.0I,N_domain,N_domain), zeros((N_domain,N_boundary)));
        temp_vec = [alpha*sol.^m-rhs_f; sol; bdy_g]
        J = L\temp_vec
        J = J'*J
        J_array[iter_step,1]=J[1]
        temp = L\(transpose(Matrix{Float64}(temp_mtx)))
        # J = 1/2*temp_vec'*Theta^{-1}*temp_vec
        grad_now = temp'*(L\temp_vec) #grad(temp_vec,sol)*Theta^{-1}*temp_vec
        GN_hessian_now = temp'*temp #grad(temp_vec,sol)*Theta^{-1}*grad(temp_vec,sol)
        sol = sol - step_size*GN_hessian_now\grad_now;
    end
    temp_vec=[alpha*sol.^m-rhs_f; sol; bdy_g]
    J = L\temp_vec
    J = J'*J
    J_array[max_iter+1,1]=J[1]
    return sol, J_array
end


text:
@testset "Exceptions" begin
  # initial population size is zero or negative
  @test_throws DomainError trans_prob( 0, 20, 72.0, [0.1, 0.05])
  @test_throws DomainError trans_prob(-1, 20, 72.0, [0.1, 0.05])

  # final population size is negative
  @test_throws DomainError trans_prob(10, -1, 72.0, [0.1,  0.05])

  # time is negative
  @test_throws DomainError trans_prob(10, 20, -1.0, [0.1,  0.05])

  # birth rate is negative
  @test_throws DomainError trans_prob(10, 20, 72.0, [-0.1, 0.05])

  # death rate is negative
  @test_throws DomainError trans_prob(10, 20,  1.0, [0.1, -0.05])
end

@testset "Type stability" begin
  @testset for I = [Int8, Int16, Int32, Int64, Int128], F = [Float32, Float64, BigFloat]
    # parameters are zero
    @test @inferred(trans_prob(I(1), I(1), F(0), [F(1), F(1)])) == F(0)
    @test typeof(trans_prob(I(1), I(1), F(0), [F(1), F(1)])) === F

    @test @inferred(trans_prob(I(1), I(1), F(1), [F(0), F(0)])) == F(0)
    @test typeof(trans_prob(I(1), I(1), F(1), [F(0), F(0)])) === F

    @test @inferred(trans_prob(I(1), I(2), F(0), [F(1), F(1)])) == F(-Inf)
    @test typeof(trans_prob(I(1), I(2), F(0), [F(1), F(1)])) === F

    @test @inferred(trans_prob(I(1), I(2), F(1), [F(0), F(0)])) == F(-Inf)
    @test typeof(trans_prob(I(1), I(2), F(1), [F(0), F(0)])) === F

    # equal rates
    # t = 1 / λ, j > 0
    g = trans_prob(I(8), I(4), F(0.5), [F(2), F(2)])
    @test @inferred(trans_prob(I(8), I(4), F(0.5), [F(2), F(2)])) == g
    @test typeof(g) === F

    # t = 1 / λ, j = 0
    g = trans_prob(I(8), I(0), F(0.5), [F(2), F(2)])
    @test @inferred(trans_prob(I(8), I(0), F(0.5), [F(2), F(2)])) == g
    @test typeof(g) === F

    # t != 1 / λ, j = 0
    g = trans_prob(I(8), I(0), F(1), [F(2), F(2)])
    @test @inferred(trans_prob(I(8), I(0), F(1), [F(2), F(2)])) == g
    @test typeof(g) === F

    # t > 1 / λ, j > 0
    g = trans_prob(I(8), I(4), F(1), [F(2), F(2)])
    @test @inferred(trans_prob(I(8), I(4), F(1), [F(2), F(2)])) == g
    @test typeof(g) === F

    # t < 1 / λ, j > 0
    g = trans_prob(I(8), I(4), F(0.1), [F(2), F(2)])
    @test @inferred(trans_prob(I(8), I(4), F(0.1), [F(2), F(2)])) == g
    @test typeof(g) === F

    # pure birth process
    g = trans_prob(I(4), I(8), F(1), [F(2), F(0)])
    @test @inferred(trans_prob(I(4), I(8), F(1), [F(2), F(0)])) == g
    @test typeof(g) === F

    @test @inferred(trans_prob(I(8), I(4), F(1), [F(2), F(0)])) == F(-Inf)
    @test typeof(trans_prob(I(8), I(4), F(1), [F(2), F(0)])) === F

    # pure death process
    g = trans_prob(I(8), I(4), F(1), [F(0), F(2)])
    @test @inferred(trans_prob(I(8), I(4), F(1), [F(0), F(2)])) == g
    @test typeof(g) === F

    @test @inferred(trans_prob(I(4), I(8), F(1), [F(0), F(2)])) == F(-Inf)
    @test typeof(trans_prob(I(4), I(8), F(1), [F(0), F(2)])) === F

    # unequal rates
    # t = log(λ / μ) / (λ - μ), j > 0
    g = trans_prob(I(4), I(8), F(log(2)), [F(2), F(1)])
    @test @inferred(trans_prob(I(4), I(8), F(log(2)), [F(2), F(1)])) == g
    @test typeof(g) === F

    # t = log(λ / μ) / (λ - μ), j = 0
    g = trans_prob(I(4), I(0), F(log(2)), [F(2), F(1)])
    @test @inferred(trans_prob(I(4), I(0), F(log(2)), [F(2), F(1)])) == g
    @test typeof(g) === F

    # t != log(λ / μ) / (λ - μ), j = 0
    g = trans_prob(I(4), I(0), F(1), [F(2), F(1)])
    @test @inferred(trans_prob(I(4), I(0), F(1), [F(2), F(1)])) == g
    @test typeof(g) === F

    # t > log(λ / μ) / (λ - μ), j > 0
    g = trans_prob(I(4), I(8), F(1), [F(2), F(1)])
    @test @inferred(trans_prob(I(4), I(8), F(1), [F(2), F(1)])) == g
    @test typeof(g) === F

    # t < log(λ / μ) / (λ - μ), j > 0
    g = trans_prob(I(4), I(8), F(0.5), [F(2), F(1)])
    @test @inferred(trans_prob(I(4), I(8), F(0.5), [F(2), F(1)])) == g
    @test typeof(g) === F
  end
end

@testset "Time is zero" begin
  @test trans_prob(10, 10, 0.0, [0.1, 0.05]) === 0.0
  @test trans_prob(10,  5, 0.0, [0.1, 0.05]) === -Inf
  @test trans_prob(10, 15, 0.0, [0.1, 0.05]) === -Inf
end

@testset "Both parameters are zero" begin
  @test trans_prob(10, 10, 72.0, [0.0, 0.0]) === 0.0
  @test trans_prob(10,  5, 72.0, [0.0, 0.0]) === -Inf
  @test trans_prob(10, 15, 72.0, [0.0, 0.0]) === -Inf
end

@testset "Pure birth process" begin
  t = 1.0
  η = [1.5, 0.0]

  @test trans_prob(1, 0, t, η) === -Inf
  @test trans_prob(100, 50, t, η) === -Inf

  p = [trans_prob(100, j, t, η, log_value=false) for j = 0:10000]
  @test sum(p) ≈ 1.0
end

@testset "Pure death process" begin
  t = 1.0
  η = [0.0, 1.5]

  @test trans_prob(1, 2, t, η) === -Inf
  @test trans_prob(100, 150, t, η) === -Inf

  p = [trans_prob(10000, j, t, η, log_value=false) for j = 0:10000]
  @test sum(p) ≈ 1.0
end

@testset "Equal rates" begin
  i = 1000
  η = [0.1, 0.1]

  # addends are all positive
  p = [trans_prob(i, j, 5.0, η, log_value=false) for j = 0:10000]
  @test sum(p) ≈ 1.0

  # addends have alternating signs
  p = [trans_prob(i, j, 100.0, η, log_value=false) for j = 0:10000]
  @test sum(p) ≈ 1.0

  # time is exactly equal to 1 / λ
  p = [trans_prob(i, j, 10.0, η, log_value=false) for j = 0:10000]
  @test sum(p) ≈ 1.0
end

@testset "Death rate greater than birth rate" begin
  i = 1000
  η = [0.01, 0.02]
  ω = log(η[1] / η[2]) / (η[1] - η[2])

  # addends are all positive
  p = [trans_prob(i, j, ω * 0.5, η, log_value=false) for j = 0:10000]
  @test sum(p) ≈ 1.0

  # addends have alternating signs
  p = [trans_prob(i, j, ω * 2.0, η, log_value=false) for j = 0:10000]
  @test sum(p) ≈ 1.0

  # time is exactly equal to log(λ / μ) / (λ - μ)
  p = [trans_prob(i, j, ω, η, log_value=false) for j = 0:10000]
  @test sum(p) ≈ 1.0
end

@testset "Birth rate greater than death rate" begin
  i = 1000
  η = [0.02, 0.01]
  ω = log(η[1] / η[2]) / (η[1] - η[2])

  # addends are all positive
  p = [trans_prob(i, j, ω * 0.5, η, log_value=false) for j = 0:10000]
  @test sum(p) ≈ 1.0

  # addends have alternating signs
  p = [trans_prob(i, j, ω * 2.0, η, log_value=false) for j = 0:10000]
  @test sum(p) ≈ 1.0

  # time is exactly equal to log(λ / μ) / (λ - μ)
  p = [trans_prob(i, j, ω, η, log_value=false) for j = 0:10000]
  @test sum(p) ≈ 1.0
end


text:
module Observers

export Observer, results, empty_results!, empty_results, update!

const FunctionAndResults = NamedTuple{(:f,:results),Tuple{Union{Nothing,Function},Any}}

struct Observer <: AbstractDict{String,FunctionAndResults}
  data::Dict{String,FunctionAndResults}
end

function Observer(key_function_pairs::Vector{<:Pair})
  keys = first.(key_function_pairs)
  functions = last.(key_function_pairs)
  d = Dict{eltype(keys),FunctionAndResults}()
  for (k, v) in zip(keys, functions)
    d[k] = (f = v, results = Any[])
  end
  return Observer(d)
end

function Observer(functions::Vector{<:Function})
  return Observer(string.(functions) .=> functions)
end

function Observer(key_function_pairs::Pair...)
  return Observer([key_function_pairs...])
end

function Observer(functions::Function...)
  return Observer([functions...])
end

struct MissingMethod end

Observer() = Observer(Dict{String,FunctionAndResults}())

Base.length(obs::Observer) = length(obs.data)
Base.iterate(obs::Observer, args...) = iterate(obs.data, args...)

Base.getindex(obs::Observer, n) = obs.data[string(n)]
Base.get(obs::Observer, n, x) = get(obs.data, n, x)

Base.setindex!(obs::Observer, observable::Union{Nothing,Function}, obsname) =
  Base.setindex!(obs.data, (f = observable, results = Any[]), obsname)

Base.setindex!(obs::Observer, measurements::NamedTuple, obsname) =
  Base.setindex!(obs.data, measurements, obsname)

Base.setindex!(obs::Observer, measurements::Tuple{Union{Nothing,Function},Vector{Any}}, obsname) =
  Base.setindex!(obs.data, (f = first(measurements), results = last(measurements)), obsname)

Base.copy(observer::Observer) = Observer(copy(observer.data))

Base.empty!(observer::Observer) = empty!(observer.data)

function empty_results!(observer::Observer, k)
  empty!(results(observer, k))
  return observer
end

function empty_results!(observer::Observer)
  for k in keys(observer)
    empty_results!(observer, k)
  end
  return observer
end

empty_results(observer::Observer, args...) = empty_results!(copy(observer), args...)

results(observer::Observer, obsname) =
  observer[obsname].results

function set_results!(observer::Observer, results, obsname)
  observer[obsname] = (f=observer[obsname].f, results=results)
  return observer
end

functions_and_results(obs::Observer) =
  obs.data

results(observer::Observer) =
  Dict([obsname => last(observer[obsname]) for obsname in keys(observer)])

"""
    update!(obs::Observer, args...; kwargs...)

Update the observer by executing the functions in it.
"""
function update!(obs::Observer, args...; kwargs...)
  # loop over the functions
  for (k, v) in obs
    obs_k = obs[k]
    # if a function is defined
    if !isnothing(obs_k.f)
      # collect the types of each positional argument being passed into the observer
      args_types = typeof.(args)
      # initialize the result to catch a method not being found
      result = MissingMethod()
      # loop over the sequences of possible positional arguments
      for i in 0:length(args_types)
        tlist = args_types[1:i]
        # if a function with argument matching tlist exists:
        if hasmethod(obs_k.f, tlist)
          # check the kwargs of such function
          kwargs_list = Base.kwarg_decl(which(obs_k.f, tlist))
          # remove the kwargs... from the kwargs
          filter!(x -> !(length(string(x)) ≥ 4 && string(x)[end-2:end] == "..."), kwargs_list)
          # execute the function
          result = obs_k.f(args[1:i]...; (kwargs_list .=> [kwargs[κ] for κ in kwargs_list])...)
          break
        end
      end
      result isa MissingMethod && error("No method found")
      update!(obs, obs_k.f, k, result)
    end
  end
  return obs
end

function update!(obs::Observer, f::Function, k, result)
  if result isa eltype(obs[k].results) && !isempty(obs[k].results)
    update!(f, obs[k].results, result)
  elseif isempty(obs[k].results)
    # This sets the type of the results to the type
    # of the initial results.
    set_results!(obs, [result], k)
  else
    # If the type of the result doesn't fit into the current
    # results storage, convert the results.
    T = promote_type(typeof(result), eltype(obs[k].results))
    obs_k_results = convert(Vector{T}, obs[k].results)
    update!(f, obs_k_results, result)
    set_results!(obs, obs_k_results, k)
  end
end

# Allows external users to customize updating the results for
# a given function, for example by emptying them.
update!(f::Function, results, result) = push!(results, result)

end # module


text:
using Ion
using Test

@testset "Ion.jl" begin
    # Write your own tests here.
end


text:
using Agents
using AgentsX

include("LayeredAgentActions.jl")

"""
    Social <:ParamLayer
The Social layer for LayeredAgent
"""
mutable struct Social <: ParamLayer
    ethnicity::Int
end

"""
    Economic <:ParamLayer
The Economic layer for LayeredAgent
"""
mutable struct Economic <: ParamLayer
    rich::Bool
end

"""
    Cognitive <:ParamLayer
The Cognitive Layer for LayeredAgent
"""
mutable struct Cognitive <: ParamLayer
    tired::Bool
end

"""
    LayeredAgent <: AbstractAgent
A LayeredAgent in a GridSpace
This agent has Social, Economic, and Cognitive Layers
"""
mutable struct LayeredAgent <: AbstractAgent
    id::Int
    pos::NTuple{2, Int}
    Social::Social
    Economic::Economic
    Cognitive::Cognitive
end


text:
# This file was generated, do not modify it. # hide
avg = MyAverageTwo(regressor1=forest,
                   regressor2=ridge)

stack = MyTwoModelStack(regressor1=forest,
                        regressor2=ridge,
                        judge=linear)

all_models = [forest, ridge, avg, stack];

for model in all_models
    print_performance(model, X, y)
end;

max_stars_repo_name: ven-k/MLJTutorials

max_issues_repo_name: ven-k/MLJTutorials

max_forks_repo_name: ven-k/MLJTutorials


text:
const GLTypeMap = Dict(
   GL_BOOL           => Bool,
   GL_BYTE           => Cchar,
   GL_SHORT          => Cshort,
   GL_INT            => Cint,
   GL_FLOAT          => Cfloat,
   GL_DOUBLE         => Cdouble,
   GL_UNSIGNED_BYTE  => Cuchar,
   GL_UNSIGNED_SHORT => Cushort,
   GL_UNSIGNED_INT   => Cuint,
)

for (enum, T) in GLTypeMap
   @eval gtype(::Type{$T}) = $(enum)
end

@export begin
   function genum(type::GLenum)
      if type in keys(GLTypeMap)
         return GLTypeMap[type]
      else
         error("No DataType found for $type")
      end
   end

   gtype(::Type{SVector{N, T}}) where {N, T} = gtype(T)
   gbool(x::Bool)    = x ? GL_TRUE : GL_FALSE
   gbool(x::GLenum)  = x == GL_TRUE
end

max_stars_repo_name: jorge-brito/Glutils

max_issues_repo_name: jorge-brito/Glutils

max_forks_repo_name: jorge-brito/Glutils


text:
function CM(ALPHA,EL)
      A=[0.2050    0.0810   -0.0460   -0.1740   -0.2590
         0.1680    0.0770   -0.0200   -0.1450   -0.2020
         0.1860    0.1070   -0.0090   -0.1210   -0.1840
         0.1960    0.1100   -0.0050   -0.1270   -0.1930
         0.2130    0.1100   -0.0060   -0.1290   -0.1990
         0.2510    0.1410    0.0100   -0.1020   -0.1500
         0.2450    0.1270    0.0060   -0.0970   -0.1600
         0.2380    0.1190   -0.0010   -0.1130   -0.1670
         0.2520    0.1330    0.0140   -0.0870   -0.1040
         0.2310    0.1080         0   -0.0840   -0.0760
         0.1980    0.0810   -0.0130   -0.0690   -0.0410
         0.1920    0.0930    0.0320   -0.0060   -0.0050]
      #
      S= 0.2 * ALPHA
      K= floor(S)+3
      if(K <= 1)
            K= 2
      end
      if(K >= 12)
            K=  11
      end
      DA= S - K +3
      L = K + fix( 1.1*sign(DA) )
      #
      S= EL/12.0
      M= floor(S)+3
      if(M <= 1)
            M= 2
      end
      if(M >=  5)
            M=  4
      end
      DE= S - M +3
      N= M + fix( 1.1*sign(DE) )
      #
      K=convert(Int64, K)
      L=convert(Int64, L)
      M=convert(Int64, M)
      N=convert(Int64, N)
      T= A[K,M]
      U= A[K,N]
      V= T + abs(DA) * (A[L,M] - T)
      W= U + abs(DA) * (A[L,N] - U)
      return cmv = V + (W-V)  * abs(DE)
end


text:
@info "Loading DataFrames"
using DataFrames

@info "Loading LinearAlgebra"
using LinearAlgebra

@info "Loading JuMP"
using JuMP

@info "Loading Cbc"
using Cbc

@info "Loading StatsBase"
using StatsBase

include("../types.jl")
include("../utilities.jl")
include("../topsis.jl")
include("../vikor.jl")
include("../electre.jl")
include("../moora.jl")
include("../dematel.jl")
include("../ahp.jl")
include("../nds.jl")
include("../singlecriterion.jl")
include("../game.jl")
include("../dataenvelop.jl")
include("../grey.jl")
include("../saw.jl")
include("../aras.jl")
include("../wpm.jl")
include("../waspas.jl")
include("../edas.jl")
include("../marcos.jl")
include("../mabac.jl")
include("../mairca.jl")
include("../copras.jl")
include("../promethee.jl")

decmat = [2.50 240 57 45 1.10 0.333333;
2.50 285 60 75 4.00 0.428571;
4.50 320 100 65 7.50 1.111111;
4.50 365 100 90 7.50 1.111111;
5.00 400 100 90 11.00 1.111111;
2.50 225 60 45 1.10 0.333333;
2.50 270 57 60 4.00 0.428571;
4.50 330 100 70 7.50 1.111111;
4.50 365 100 80 7.50 1.111111;
5.00 380 110 65 8.00 1.111111;
2.50 285 65 80 4.00 0.400000;
4.00 280 75 65 4.00 0.400000;
4.50 365 102 95 7.50 1.111111;
4.50 400 102 95 7.50 1.111111;
6.00 450 110 95 11.00 1.176471;
6.00 510 110 105 11.00 1.176471;
6.00 330 140 110 18.50 1.395349;
2.50 240 65 80 4.00 0.400000;
4.00 280 75 75 4.00 0.400000;
4.50 355 102 95 7.50 1.111111;
4.50 385 102 90 7.50 1.111111;
5.00 385 114 95 7.50 1.000000;
6.00 400 110 90 11.00 1.000000;
6.00 480 110 95 15.00 1.000000;
6.00 440 140 100 18.50 1.200000;
6.00 500 140 100 18.50 1.200000;
5.00 450 125 100 15.00 1.714286;
6.00 500 150 125 18.50 1.714286;
6.00 515 180 140 22.00 2.307692;
7.00 550 200 150 30.00 2.307692;
6.00 500 180 140 15.00 2.307692;
6.00 500 180 140 18.50 2.307692;
6.00 500 180 140 22.00 2.307692;
7.00 500 180 140 30.00 2.307692;
7.00 500 200 140 37.00 2.307692;
7.00 500 200 140 45.00 2.307692;
7.00 500 200 140 55.00 2.307692;
7.00 500 200 140 75.00 2.307692]

df = makeDecisionMatrix(decmat)

weights = [0.1667, 0.1667, 0.1667, 0.1667, 0.1667, 0.1667];

fns = [maximum, maximum, maximum, maximum, maximum, minimum];

result = mairca(df, weights, fns)

max_stars_repo_name: ersagunkuruca/JMcDM

max_issues_repo_name: ersagunkuruca/JMcDM

max_forks_repo_name: ersagunkuruca/JMcDM


text:
using StructArrays: StructArray, replace_storage
using Oceananigans.Grids: on_architecture
using Oceananigans.Fields: AbstractField, indices, boundary_conditions, instantiated_location
using Oceananigans.BoundaryConditions: bc_str, FieldBoundaryConditions, ContinuousBoundaryFunction, DiscreteBoundaryFunction
using Oceananigans.TimeSteppers: QuasiAdamsBashforth2TimeStepper, RungeKutta3TimeStepper
using Oceananigans.LagrangianParticleTracking: LagrangianParticles

#####
##### Output writer utilities
#####

"""
    ext(ow)

Return the file extension for the output writer or output
writer type `ow`.
"""
ext(ow::Type{AbstractOutputWriter}) = throw("Extension for $ow is not implemented.")
ext(ow::AbstractOutputWriter) = ext(typeof(fw))

# TODO: add example to docstring below

"""
    saveproperty!(file, address, obj)

Save data in `obj` to `file[address]` in a "languate-agnostic" way,
thus primarily consisting of arrays and numbers, absent Julia-specific types
or other data that can _only_ be interpreted by Julia.
"""
saveproperty!(file, address, obj) = _saveproperty!(file, address, obj)

# Generic implementation: recursively unwrap an object.
_saveproperty!(file, address, obj) = [saveproperty!(file, address * "/$prop", getproperty(obj, prop)) for prop in propertynames(obj)]

# Some specific things
saveproperty!(file, address, p::Union{Number, Array}) = file[address] = p
saveproperty!(file, address, p::AbstractRange)        = file[address] = collect(p)
saveproperty!(file, address, p::AbstractArray)        = file[address] = Array(parent(p))
saveproperty!(file, address, p::Function)             = nothing
saveproperty!(file, address, p::Tuple)                = [saveproperty!(file, address * "/$i", p[i]) for i in 1:length(p)]
saveproperty!(file, address, grid::AbstractGrid)      = _saveproperty!(file, address, on_architecture(CPU(), grid))

# Special saveproperty! so boundary conditions are easily readable outside julia.
function saveproperty!(file, address, bcs::FieldBoundaryConditions)
    for boundary in propertynames(bcs)
        bc = getproperty(bcs, endpoint)
        file[address * "/$endpoint/type"] = bc_str(bc)

        if bc.condition isa Function || bc.condition isa ContinuousBoundaryFunction
            file[address * "/$boundary/condition"] = missing
        else
            file[address * "/$boundary/condition"] = bc.condition
        end
    end
end

"""
    serializeproperty!(file, address, obj)

Serialize `obj` to `file[address]` in a "friendly" way; i.e. converting
`CuArray` to `Array` so data can be loaded on any architecture,
and not attempting to serialize objects that generally aren't
deserializable, like `Function`.
"""
serializeproperty!(file, address, p)                = file[address] = p
serializeproperty!(file, address, p::AbstractArray) = saveproperty!(file, address, p)

const CantSerializeThis = Union{Function,
                                ContinuousBoundaryFunction,
                                DiscreteBoundaryFunction}

serializeproperty!(file, address, p::CantSerializeThis) = nothing

# Convert to CPU please!
# TODO: use on_architecture for more stuff?
serializeproperty!(file, address, grid::AbstractGrid) = file[address] = on_architecture(CPU(), grid)

function serializeproperty!(file, address, p::FieldBoundaryConditions)
    # TODO: it'd be better to "filter" `FieldBoundaryCondition` and then serialize
    # rather than punting with `missing` instead.
    if has_reference(Function, p)
        file[address] = missing
    else
        file[address] = p
    end
end

function serializeproperty!(file, address, f::Field)
    serializeproperty!(file, address * "/location", instantiated_location(f))
    serializeproperty!(file, address * "/data", parent(f))
    serializeproperty!(file, address * "/indices", indices(f))
    serializeproperty!(file, address * "/boundary_conditions", boundary_conditions(f))
    return nothing
end

# Special serializeproperty! for AB2 time stepper struct used by the checkpointer so
# it only saves the fields and not the tendency BCs or χ value (as they can be
# constructed by the `Model` constructor).
function serializeproperty!(file, address, ts::RungeKutta3TimeStepper)
    serializeproperty!(file, address * "/Gⁿ", ts.Gⁿ)
    serializeproperty!(file, address * "/G⁻", ts.G⁻)
    return nothing
end

function serializeproperty!(file, address, ts::QuasiAdamsBashforth2TimeStepper)
    serializeproperty!(file, address * "/Gⁿ", ts.Gⁿ)
    serializeproperty!(file, address * "/G⁻", ts.G⁻)
    serializeproperty!(file, address * "/previous_Δt", ts.previous_Δt)
    return nothing
end

serializeproperty!(file, address, p::NamedTuple) = [serializeproperty!(file, address * "/$subp", getproperty(p, subp)) for subp in keys(p)]
serializeproperty!(file, address, s::StructArray) = (file[address] = replace_storage(Array, s))
serializeproperty!(file, address, p::LagrangianParticles) = serializeproperty!(file, address, p.properties)

saveproperties!(file, structure, ps) = [saveproperty!(file, "$p", getproperty(structure, p)) for p in ps]
serializeproperties!(file, structure, ps) = [serializeproperty!(file, "$p", getproperty(structure, p)) for p in ps]

# Don't check arrays because we don't need that noise.
has_reference(T, ::AbstractArray{<:Number}) = false

# This is going to be true.
has_reference(::Type{T}, ::NTuple{N, <:T}) where {N, T} = true

# Short circuit on fields.
has_reference(T::Type{Function}, f::Field) =
    has_reference(T, f.data) || has_reference(T, f.boundary_conditions)

"""
    has_reference(has_type, obj)

Check (or attempt to check) if `obj` contains, somewhere among its
subfields and subfields of fields, a reference to an object of type
`has_type`. This function doesn't always work.
"""
function has_reference(has_type, obj)
    if typeof(obj) <: has_type
        return true
    elseif applicable(iterate, obj) && length(obj) > 1
        return any([has_reference(has_type, elem) for elem in obj])
    elseif applicable(propertynames, obj) && length(propertynames(obj)) > 0
        return any([has_reference(has_type, getproperty(obj, p)) for p in propertynames(obj)])
    else
        return typeof(obj) <: has_type
    end
end

""" Returns the schedule for output averaging determined by the first output value. """
function output_averaging_schedule(ow::AbstractOutputWriter)
    first_output = first(values(ow.outputs))
    return output_averaging_schedule(first_output)
end

output_averaging_schedule(output) = nothing # fallback

show_array_type(a::Type{Array{T}}) where T = "Array{$T}"

"""
    auto_extension(filename, ext)

If `filename` ends in `ext`, return `filename`. Otherwise return `filename * ext`.
"""
function auto_extension(filename, ext)
    Next = length(ext)
    filename[end-Next+1:end] == ext || (filename *= ext)
    return filename
end


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

using Markdown
using InteractiveUtils

# ╔═╡ 77b330b5-9fb7-4f74-8306-b147bf052dae
begin
	using CSV, DataFrames
	using MortalityTables, ActuaryUtilities
	using Dates
	using ThreadsX
	using BenchmarkTools
end

# ╔═╡ a7b52cf6-b03d-47e9-818c-22ea8f82f158
using Random

# ╔═╡ 8b86fb4e-2835-4282-8345-6708033423f1
using UnicodePlots

# ╔═╡ c1cacc0f-a789-4fd6-8f1e-a822dd17a66e
md" # Stochastic claims projections demo"

# ╔═╡ 9abe410a-8f6b-4d66-ac0e-570df1e34b47
md" Define a datatype. Not strictly necessary, but will make extending the program with more functions easier."

# ╔═╡ 11f171f8-9137-4e53-9384-f302ad3a773c
md"Type annotations are optional, but providing them is able to coerce the values to be all plain bits (i.e. simple, non-referenced values like arrays are) when the type is constructed. This makes the whole data be stored in the stack and is an example of data-oriented design. It's much slower (~0.5 million policies per second, ~50x slower)"

# ╔═╡ 4310ba76-2a79-49e9-b9c4-78e82871184f
begin
	@enum Sex Female = 1 Male = 2
	@enum Risk Standard = 1 Preferred = 2
end

# ╔═╡ f4d57736-ad94-4139-a372-dc281be9303a
struct Policy
    id::Int
	sex::Sex
    benefit_base::Float64
    COLA::Float64
    mode::Int
    issue_date::Date
    issue_age::Int
    risk::Risk
end

# ╔═╡ be3ae4ef-661c-40b1-acce-4591cc7e6e5f
md"Load the data:"

# ╔═╡ 14901845-d99b-4a26-947d-63f4c8dd8334
sample_csv_data =
IOBuffer(
	raw"id,sex,benefit_base,COLA,mode,issue_date,issue_age,risk
		1,M,100000.0,0.03,12,1999-12-05,30,Std
		2,F,200000.0,0.03,12,1999-12-05,30,Pref"
)

# ╔═╡ 5ee1ca24-45aa-47e7-a948-26b4cc819cdb
policies = let

	# read CSV directly into a dataframe
    # df = CSV.read("sample_inforce.csv",DataFrame) # use local string for notebook
	df = CSV.read(sample_csv_data,DataFrame)

	# map over each row and construct an array of Policy objects
    map(eachrow(df)) do row
        Policy(
            row.id,
			row.sex == "M" ? Male : Female,
            row.benefit_base,
            row.COLA,
            row.mode,
            row.issue_date,
            row.issue_age,
            row.risk == "Std" ? Standard : Preferred,
        )
    end

end

# ╔═╡ 89997227-faa5-45fa-aabb-304dee864fd3
md" Define what mortality gets used:"

# ╔═╡ e8d3578b-560b-491e-8ceb-85057f18373e
mort = Dict(
	Male => MortalityTables.table(988).ultimate,
	Female => MortalityTables.table(992).ultimate,
)

# ╔═╡ febebebd-48e6-4645-9c21-699bfb50eb3a
function mortality(pol::Policy,params)
	return params.mortality[pol.sex]
end

# ╔═╡ 23dec098-dda1-4153-bc3f-e1816354888b
md" This defines the core logic of the policy projection and will write the results to the given `out` container (here, a named tuple of arrays).

This is using a threaded approach where it could be operating on any of the computer's available threads, thus acheiving thread-based parallelism (as opposed to multi-processor (multi-machine) or GPU-based computation which requires formulating the problem a bit differently (array/matrix based). For the scale of computation here, I think I'd apply this model of parallelism."

# ╔═╡ ef0b652f-4f73-463a-be25-2e0466286ce1
function pol_project!(out,policy,params)
	# some starting values for the given policy
	dur = duration(policy.issue_date,params.val_date)
	start_age = policy.issue_age + dur - 1
	COLA_factor = (1+policy.COLA)
	cur_benefit = policy.benefit_base * COLA_factor ^ (dur-1)

	# get the right mortality vector
	qs = mortality(policy,params)

	# grab the current thread's id to write to results container without conflicting with other threads
	tid = Threads.threadid()

	ω = lastindex(qs)

	# inbounds turns off bounds-checking, which makes hot loops faster but first write loop without it to ensure you don't create an error (will crash if you have the error without bounds checking)
    @inbounds for t in 1:min(params.proj_length,ω - start_age)

		q = qs[start_age + t] # get current mortality

		if (rand() < q)
			return # if dead then just return and don't increment the results anymore
		else
			# pay benefit, add a life to the output count, and increment the benefit for next year
			out.benefits[t,tid] += cur_benefit
			out.lives[t,tid] += 1
			cur_benefit *= COLA_factor
		end
    end
end

# ╔═╡ c3e16d9b-af03-4608-b982-c1c99e638e2d
md" Parameters for our projection:"

# ╔═╡ 8ebc2609-576a-4105-aabe-84f1fe51e8de
params = (
    val_date = Date(2021,12,31),
	proj_length = 100,
	mortality = mort,
)

# ╔═╡ b2f183d5-c739-467f-8e77-2546fff33c0c
md" Check the number of threads we're using:"

# ╔═╡ 84b2c368-c1ba-41ed-ab7c-9677a7293f1a
Threads.nthreads()

# ╔═╡ 055c5cc1-0cf3-407a-af4f-057bc2b8d0e8
function project(policies,params)
	threads = Threads.nthreads()
	benefits = zeros(params.proj_length,threads)
	lives = zeros(Int,params.proj_length,threads)
	out = (;benefits,lives)
	ThreadsX.foreach(policies) do pol
		pol_project!(out,pol,params)
	end
	map(x->vec(reduce(+,x,dims=2)),out)
end

# ╔═╡ 51bdd873-32db-494e-a2f2-1975124f8008
md" Example of single projection:"

# ╔═╡ cfe6a86d-a48e-497c-8a7a-837b16a41931
project(repeat(policies,100_000),params)

# ╔═╡ 8c87a09a-c46f-4143-b2c7-87c51a54332c
md" ## Benchmarking"

# ╔═╡ bde3cee6-8b59-42f8-b450-10044636a563
md"

Using a Macbook Air laptop, about 30 million policies able to be stochastically projected per second:
"

# ╔═╡ e087efbc-9a9f-4e09-ac14-2e4067de458b
let
	policies_to_benchmark = 3_000_000
	# adjust the `repeat` depending on how many policies are already in the array
	# to match the target number for the benchmark
	n = policies_to_benchmark ÷ length(policies)

	@benchmark project(p,r) setup=(p=repeat($policies,$n);r=$params)
end

# ╔═╡ 9e45b261-4e29-48d7-99fe-1fc623b5a757
md""" ## Stochastic Set

Loop through and calculate the reults `n` times (this is only running the two policies in the sample data" `n` times).
"""

# ╔═╡ 778f030b-aab1-4191-8902-3f10f402b82e
function stochastic_proj(policies,params,n)

	ThreadsX.map(1:n) do i
		project(policies,params)
	end
end

# ╔═╡ 73ead2b9-733d-470c-a863-9aa4397c35cd
stoch = stochastic_proj(policies,params,1000)

# ╔═╡ 0e8d3fe0-5df3-4db9-88a6-fe4f738211c0
let
	v = [pv(0.03,s.benefits) for s in stoch]
	histogram(v,nbins=15)
end

# ╔═╡ 786312c8-2a40-44db-96cd-a1edc2f29e9a
md" # Further Optimization

In no particular order:
- the RNG could be made faster: https://bkamins.github.io/julialang/2020/11/20/rand.html
- Could make the stochastic set distributed, but at the current speed the overhead of distributed computing is probably more time than it would save. Same thing with GPU projections
- ...

"

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
ActuaryUtilities = "bdd23359-8b1c-4f88-b89b-d11982a786f4"
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
MortalityTables = "4780e19d-04b9-53dc-86c2-9e9aa59b5a12"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
ThreadsX = "ac1d9e8a-700a-412c-b207-f0111f4b6c0d"
UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"

[compat]
ActuaryUtilities = "~3.2.0"
BenchmarkTools = "~1.3.1"
CSV = "~0.10.4"
DataFrames = "~1.3.4"
MortalityTables = "~2.3.0"
ThreadsX = "~0.1.10"
UnicodePlots = "~2.11.2"
"""

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

julia_version = "1.8.0-beta2.85"
manifest_format = "2.0"
project_hash = "00d9a3edb00c3fbe2b994ae8ff9046994b313c67"

[[deps.ActuaryUtilities]]
deps = ["Dates", "Distributions", "ForwardDiff", "QuadGK", "Roots", "StatsBase", "Yields"]
git-tree-sha1 = "59a8e9632a0a69d9931e6e08fa1c5843f24f683a"
uuid = "bdd23359-8b1c-4f88-b89b-d11982a786f4"
version = "3.2.0"

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

[[deps.ArgCheck]]
git-tree-sha1 = "a3a402a35a2f7e0b87828ccabbd5ebfbebe356b4"
uuid = "dce04be8-c92d-5529-be00-80e4d2c0e197"
version = "2.3.0"

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

[[deps.ArrayLayouts]]
deps = ["FillArrays", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "c23473c60476e62579c077534b9643ec400f792b"
uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
version = "0.8.6"

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

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

[[deps.BSplineKit]]
deps = ["ArrayLayouts", "BandedMatrices", "FastGaussQuadrature", "Interpolations", "LazyArrays", "LinearAlgebra", "Random", "Reexport", "SparseArrays", "StaticArrays"]
git-tree-sha1 = "651e79138b30580c5a1586b67c3298be6c7b8afe"
uuid = "093aae92-e908-43d7-9660-e50ee39d5a0a"
version = "0.8.4"

[[deps.BandedMatrices]]
deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra", "Random", "SparseArrays"]
git-tree-sha1 = "019aa88766e2493c59cbd0a9955e1bac683ffbcd"
uuid = "aae01518-5342-5314-be14-df237901396f"
version = "0.16.13"

[[deps.BangBang]]
deps = ["Compat", "ConstructionBase", "Future", "InitialValues", "LinearAlgebra", "Requires", "Setfield", "Tables", "ZygoteRules"]
git-tree-sha1 = "b15a6bc52594f5e4a3b825858d1089618871bf9d"
uuid = "198e06fe-97b7-11e9-32a5-e1d131e6ad66"
version = "0.3.36"

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

[[deps.Baselet]]
git-tree-sha1 = "aebf55e6d7795e02ca500a689d326ac979aaf89e"
uuid = "9718e550-a3fa-408a-8086-8db961cd8217"
version = "0.1.1"

[[deps.BenchmarkTools]]
deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"]
git-tree-sha1 = "4c10eee4af024676200bc7752e536f858c6b8f93"
uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
version = "1.3.1"

[[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 = "eb4cb44a499229b3b8426dcfb5dd85333951ff90"
uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82"
version = "0.4.2"

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

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

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

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

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

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

[[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.CommonSolve]]
git-tree-sha1 = "68a0743f578349ada8bc911a5cbd5a2ef6ed6d1f"
uuid = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2"
version = "0.2.0"

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

[[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 = "b153278a25dd42c65abbf4e62344f9d22e59191b"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.43.0"

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

[[deps.CompositionsBase]]
git-tree-sha1 = "455419f7e328a1a2493cabc6428d79e951349769"
uuid = "a33af91c-f02d-484b-be07-31d278c5ca2b"
version = "0.1.1"

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

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

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

[[deps.DataAPI]]
git-tree-sha1 = "fb5f5316dd3fd4c5e7c30a24d50643b73e37cd40"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.10.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 = "daa21eb85147f72e41f6352a57fccea377e310a9"
uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
version = "1.3.4"

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

[[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.DefineSingletons]]
git-tree-sha1 = "0fba8b706d0178b4dc7fd44a96a92382c9065c2c"
uuid = "244e2a9f-e319-4986-a169-4d1fe445cd52"
version = "0.1.2"

[[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.DiffResults]]
deps = ["StaticArrays"]
git-tree-sha1 = "c18e98cba888c6c25d1c3b048e4b3380ca956805"
uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5"
version = "1.0.3"

[[deps.DiffRules]]
deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"]
git-tree-sha1 = "28d605d9a0ac17118fe2c5e9ce0fbb76c3ceb120"
uuid = "b552c78f-8df3-52c6-915a-8e097449b14b"
version = "1.11.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 = "8a6b49396a4058771c5c072239b2e0a76e2e898c"
uuid = "31c24e10-a181-5473-b8eb-7969acd0382f"
version = "0.25.58"

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

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

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

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

[[deps.EzXML]]
deps = ["Printf", "XML2_jll"]
git-tree-sha1 = "0fa3b52a04a4e210aeb1626def9c90df3ae65268"
uuid = "8f5d6c58-4d21-5cfd-889c-e3ad7ee6a615"
version = "1.1.0"

[[deps.FastGaussQuadrature]]
deps = ["LinearAlgebra", "SpecialFunctions", "StaticArrays"]
git-tree-sha1 = "58d83dd5a78a36205bdfddb82b1bb67682e64487"
uuid = "442a2c76-b920-505d-bb47-c5924d526838"
version = "0.4.9"

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

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

[[deps.FileWatching]]
uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"

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

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

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

[[deps.ForwardDiff]]
deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions", "StaticArrays"]
git-tree-sha1 = "89cc49bf5819f0a10a7a3c38885e7c7ee048de57"
uuid = "f6369f11-7733-5829-9624-2563aa707210"
version = "0.10.29"

[[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"]
git-tree-sha1 = "b5c7fe9cea653443736d264b85466bad8c574f4a"
uuid = "663a7486-cb36-511b-a19d-713bb74d65c9"
version = "0.9.9"

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

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

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

[[deps.InitialValues]]
git-tree-sha1 = "4da0f88e9a39111c2fa3add390ab15f3a44f3ca3"
uuid = "22cec73e-a1b8-11e9-2c92-598750a2cf9c"
version = "0.3.1"

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

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

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

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

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

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

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

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

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

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

[[deps.LazyArrays]]
deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra", "MacroTools", "MatrixFactorizations", "SparseArrays", "StaticArrays"]
git-tree-sha1 = "721bebe4d0f8581c18fccf272c62000e22a80a2d"
uuid = "5078a376-72f3-5289-bfd5-ec5146d43c02"
version = "0.22.10"

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

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

[[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"
version = "1.10.2+0"

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

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

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

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

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

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

[[deps.MarchingCubes]]
deps = ["StaticArrays"]
git-tree-sha1 = "5f768e0a0c3875df386be4c036f78c8bd4b1a9b6"
uuid = "299715c1-40a9-479a-aaf9-4a633d36f717"
version = "0.1.2"

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

[[deps.MatrixFactorizations]]
deps = ["ArrayLayouts", "LinearAlgebra", "Printf", "Random"]
git-tree-sha1 = "2212d36f97e01347adb1460a6914e20f2feee853"
uuid = "a3b82374-2e81-5b9e-98ce-41277c0e4c87"
version = "0.9.1"

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

[[deps.Memoize]]
deps = ["MacroTools"]
git-tree-sha1 = "2b1dfcba103de714d31c033b5dacc2e4a12c7caa"
uuid = "c03570c3-d221-55d1-a50c-7939bbd78826"
version = "0.4.4"

[[deps.MicroCollections]]
deps = ["BangBang", "InitialValues", "Setfield"]
git-tree-sha1 = "6bb7786e4f24d44b4e29df03c69add1b63d88f01"
uuid = "128add7d-3638-4c79-886c-908ea0c25c34"
version = "0.1.2"

[[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.MortalityTables]]
deps = ["Memoize", "OffsetArrays", "Parsers", "Pkg", "QuadGK", "Requires", "StringDistances", "UnPack", "XMLDict"]
git-tree-sha1 = "8ae1af8a53147c592a95fbce9fd37dda2a50355f"
uuid = "4780e19d-04b9-53dc-86c2-9e9aa59b5a12"
version = "2.3.0"

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

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

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

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

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

[[deps.OpenLibm_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "05823500-19ac-5b8b-9628-191a04bc5112"
version = "0.8.1+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.OrderedCollections]]
git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.1"

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

[[deps.Parsers]]
deps = ["Dates"]
git-tree-sha1 = "1285416549ccfcdf0c50d4997a94331e88d68413"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.3.1"

[[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"
version = "1.8.0"

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

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

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

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

[[deps.Profile]]
deps = ["Printf"]
uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"

[[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 = "dc84268fe0e3335a62e315a3a7cf2afa7178a734"
uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439"
version = "0.4.3"

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

[[deps.Referenceables]]
deps = ["Adapt"]
git-tree-sha1 = "e681d3bfa49cd46c3c161505caddf20f0e62aaa9"
uuid = "42d2dcc6-99eb-4e98-b66c-637b7d73030e"
version = "0.1.2"

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

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

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

[[deps.Roots]]
deps = ["CommonSolve", "Printf", "Setfield"]
git-tree-sha1 = "838b60ee62bebc794864c880a47e331e00c47505"
uuid = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
version = "1.4.1"

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

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

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

[[deps.Setfield]]
deps = ["ConstructionBase", "Future", "MacroTools", "Requires"]
git-tree-sha1 = "38d88503f695eb0301479bc9b0d4320b378bafe5"
uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46"
version = "0.8.2"

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

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

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

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

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

[[deps.SplittablesBase]]
deps = ["Setfield", "Test"]
git-tree-sha1 = "39c9f91521de844bad65049efd4f9223e7ed43f9"
uuid = "171d559e-b47b-412a-8079-5efa626c420e"
version = "0.1.14"

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

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

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

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

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

[[deps.StringDistances]]
deps = ["Distances", "StatsAPI"]
git-tree-sha1 = "ceeef74797d961aee825aabf71446d6aba898acb"
uuid = "88034a9c-02f8-509d-84a9-84ec65e18404"
version = "0.11.2"

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

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

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

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

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

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

[[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.ThreadsX]]
deps = ["ArgCheck", "BangBang", "ConstructionBase", "InitialValues", "MicroCollections", "Referenceables", "Setfield", "SplittablesBase", "Transducers"]
git-tree-sha1 = "d223de97c948636a4f34d1f84d92fd7602dc555b"
uuid = "ac1d9e8a-700a-412c-b207-f0111f4b6c0d"
version = "0.1.10"

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

[[deps.Transducers]]
deps = ["Adapt", "ArgCheck", "BangBang", "Baselet", "CompositionsBase", "DefineSingletons", "Distributed", "InitialValues", "Logging", "Markdown", "MicroCollections", "Requires", "Setfield", "SplittablesBase", "Tables"]
git-tree-sha1 = "c76399a3bbe6f5a88faa33c8f8a65aa631d95013"
uuid = "28d57a85-8fef-5791-bfe6-a80928e7c999"
version = "0.4.73"

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

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

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

[[deps.UnicodePlots]]
deps = ["ColorTypes", "Contour", "Crayons", "Dates", "FileIO", "FreeTypeAbstraction", "LinearAlgebra", "MarchingCubes", "NaNMath", "Printf", "SparseArrays", "StaticArrays", "StatsBase", "Unitful"]
git-tree-sha1 = "4b18663db312f47f9729935066a377e5c6a9bdfb"
uuid = "b8865327-cd53-5732-bb35-84acbb429228"
version = "2.11.2"

[[deps.Unitful]]
deps = ["ConstructionBase", "Dates", "LinearAlgebra", "Random"]
git-tree-sha1 = "b649200e887a487468b71821e2644382699f1b0f"
uuid = "1986cc42-f94f-5a68-af5c-568840ba703d"
version = "1.11.0"

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

[[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.XMLDict]]
deps = ["EzXML", "IterTools", "OrderedCollections"]
git-tree-sha1 = "d9a3faf078210e477b291c79117676fca54da9dd"
uuid = "228000da-037f-5747-90a9-8195ccbf91a5"
version = "0.4.1"

[[deps.Yields]]
deps = ["BSplineKit", "ForwardDiff", "LinearAlgebra", "Roots", "UnicodePlots"]
git-tree-sha1 = "dc6d9a1c5e315bca48846095c4b969869735f38b"
uuid = "d7e99b2f-e7f3-4d9e-9f01-2338fc023ad3"
version = "1.1.1"

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

[[deps.ZygoteRules]]
deps = ["MacroTools"]
git-tree-sha1 = "8c1a8e4dfacb1fd631745552c8db35d0deb09ea0"
uuid = "700de1a5-db45-46bc-99cf-38207098b444"
version = "0.2.2"

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

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

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

# ╔═╡ Cell order:
# ╟─c1cacc0f-a789-4fd6-8f1e-a822dd17a66e
# ╠═77b330b5-9fb7-4f74-8306-b147bf052dae
# ╟─9abe410a-8f6b-4d66-ac0e-570df1e34b47
# ╟─11f171f8-9137-4e53-9384-f302ad3a773c
# ╠═4310ba76-2a79-49e9-b9c4-78e82871184f
# ╠═f4d57736-ad94-4139-a372-dc281be9303a
# ╟─be3ae4ef-661c-40b1-acce-4591cc7e6e5f
# ╠═14901845-d99b-4a26-947d-63f4c8dd8334
# ╠═5ee1ca24-45aa-47e7-a948-26b4cc819cdb
# ╟─89997227-faa5-45fa-aabb-304dee864fd3
# ╠═e8d3578b-560b-491e-8ceb-85057f18373e
# ╠═febebebd-48e6-4645-9c21-699bfb50eb3a
# ╟─23dec098-dda1-4153-bc3f-e1816354888b
# ╠═ef0b652f-4f73-463a-be25-2e0466286ce1
# ╟─c3e16d9b-af03-4608-b982-c1c99e638e2d
# ╠═a7b52cf6-b03d-47e9-818c-22ea8f82f158
# ╠═8ebc2609-576a-4105-aabe-84f1fe51e8de
# ╟─b2f183d5-c739-467f-8e77-2546fff33c0c
# ╠═84b2c368-c1ba-41ed-ab7c-9677a7293f1a
# ╠═055c5cc1-0cf3-407a-af4f-057bc2b8d0e8
# ╟─51bdd873-32db-494e-a2f2-1975124f8008
# ╠═cfe6a86d-a48e-497c-8a7a-837b16a41931
# ╟─8c87a09a-c46f-4143-b2c7-87c51a54332c
# ╟─bde3cee6-8b59-42f8-b450-10044636a563
# ╠═e087efbc-9a9f-4e09-ac14-2e4067de458b
# ╟─9e45b261-4e29-48d7-99fe-1fc623b5a757
# ╠═778f030b-aab1-4191-8902-3f10f402b82e
# ╠═73ead2b9-733d-470c-a863-9aa4397c35cd
# ╠═8b86fb4e-2835-4282-8345-6708033423f1
# ╠═0e8d3fe0-5df3-4db9-88a6-fe4f738211c0
# ╟─786312c8-2a40-44db-96cd-a1edc2f29e9a
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002

max_stars_repo_name: JuliaActuary/JuliaActuaryLearn

max_issues_repo_name: JuliaActuary/JuliaActuaryLearn

max_forks_repo_name: JuliaActuary/JuliaActuaryLearn


text:
using Documenter
using Memento

makedocs(
    modules=[Memento, Memento.TestUtils],
    format=Documenter.HTML(
        prettyurls=get(ENV, "CI", nothing) == "true",
        assets=["assets/invenia.css"],
    ),
    repo="https://github.com/invenia/Memento.jl/blob/{commit}{path}#L{line}",
    sitename="Memento.jl",
    authors="Invenia Technical Computing Corporation and contributors.",
    pages=Any[
        "Home" => "index.md",
        "Manual" => Any[
            "man/intro.md",
            "man/loggers.md",
            "man/handlers.md",
            "man/formatters.md",
            "man/records.md",
            "man/io.md",
            "man/conclusion.md",
        ],
        "FAQ" => Any[
            "faq/another-logging-lib.md",
            "faq/change-colors.md",
            "faq/logging-to-syslog.md",
            "faq/json-formatting.md",
            "faq/pkg-usage.md",
        ],
        "API" => Any[
            "api/public.md",
            "api/private.md",
        ],
        "Contributing" => "contributing.md",
    ],
)

deploydocs(repo="github.com/invenia/Memento.jl.git", target="build")


text:
using Documenter, ComponentArrays

makedocs(;
    modules=[ComponentArrays],
    format=Documenter.HTML(
        canonical="https://jonniedie.github.io/ComponentArrays.jl/stable",
        ),
    pages=[
        "Home" => "index.md",
        "Quick Start" => "quickstart.md",
        "Indexing Behavior" => "indexing_behavior.md",
        "Examples" => [
            "examples/DiffEqFlux.md",
            "examples/adaptive_control.md",
            "examples/ODE_jac.md",
        ],
        "API" => "api.md",
    ],
    repo="https://github.com/jonniedie/ComponentArrays.jl/blob/{commit}{path}#L{line}",
    sitename="ComponentArrays.jl",
    authors="Jonnie Diegelman",
    assets=String[],
)

deploydocs(;
    repo="github.com/jonniedie/ComponentArrays.jl.git",
)


text:
module Day4

using StatsBase

a = 124075
b = 580769

function solve(a, b)
    numfound = 0
    for i in a:b
        i = string(i)
        cond = true
        cond2 = false
        for j in 2:length(i)
            if i[j - 1] > i[j]
                cond = false
                break
            end
        end

        if cond
            m = countmap(Vector{Char}(i))
            (2 in values(m)) && (numfound += 1)
        end
    end

    numfound
end

end

max_stars_repo_name: AnAverageHuman/competitive

max_issues_repo_name: AnAverageHuman/competitive

max_forks_repo_name: AnAverageHuman/competitive


text:
func(x) = exp(-x)
int_func(a,b) = -exp(-b)+exp(-a)
#%%
function rect_quad(func, a, b, n)::Float64
    dx = (b-a)/n
    res = 0.
    for i in 0:(n-1)
        x = a + dx * i
        res += func(x)
    end
    return res * dx
end

function mid_quad(func::Function, a::Real, b::Real, n::Int)::Float64
    dx = (b-a)/n
    res = 0.
    for i in 0:(n-1)
        x = a + dx * (i+0.5)
        res += func(x)
    end
    return res * dx
end

function simps(func::Function, a::Real, b::Real, n::Int)::Float64
    if n % 2 !=0
         throw(ArgumentError("The number of intervals n must be even! You have choosen $n"))
     end
    dx = (b-a)/n
    res = func(a)

    w = 4
    x = 0.
    for i in 1:(n-1)
        x = a + dx*i
        res += func(x)*w
        w = 6 - w
    end
    res += func(b)
    return res * dx/3
end

function simps(func::Function, a::Real, b::Real; tol=1e-5, limit=100)
    n = 2
    iter=0
    res=0.

    while true
        res=simps(func, a, b, n)
        res1=simps(func, a, b, n*2)
        if abs(res1-res)<tol
            res=res1
            return res, n*2
        end
        n*=2
        iter+=1
        if iter>limit
            print("limit reached!")
            return NaN
        end
    end
    return NaN
end

#%%
rect_quad(func, 1., 4., 1000)
mid_quad(func, 1., 4., 1000)
simps(func, 0,10,12)
simps(func, 0, 100; tol=1e-5, limit=3)

? Dict

max_stars_repo_name: aurelio-amerio/corso-cpp


text:
# test various page configuration
@testset "configurations" begin
    root = joinpath("assets", "configurations")
    @testset "notebook" begin
        src_page_dir = joinpath(root, "without_notebook")
        page = DemoPage(src_page_dir)

        sec1 = page.sections[1]
        @test sec1.title == "Sec1"
        @test sec1.properties["notebook"] == "true"
        sec2 = page.sections[2]
        @test sec2.title == "Sec2"
        @test isempty(sec2.properties)

        @test isnothing(sec1.cards[1].notebook) # This might become `true` in the future
        @test sec1.cards[2].notebook == false

        page_dir = @suppress_err preview_demos(src_page_dir, require_html=false)
        if basename(page_dir) == "without_notebook"
            sec1_files = readdir(joinpath(page_dir, "sec1"))
            @test Set(filter(x->startswith(x, "demo1"), sec1_files)) == Set(["demo1.ipynb", "demo1.jl", "demo1.md"])
            @test Set(filter(x->startswith(x, "demo2"), sec1_files)) == Set(["demo2.jl", "demo2.md"])
            @test filter(x->startswith(x, "demo3"), sec1_files) == ["demo3.md"]

            sec2_files = readdir(joinpath(page_dir, "sec2"))
            @test Set(filter(x->startswith(x, "demo4"), sec2_files)) == Set(["demo4.jl", "demo4.md"])
            @test Set(filter(x->startswith(x, "demo5"), sec2_files)) == Set(["demo5.ipynb", "demo5.jl", "demo5.md"])
        else
            @warn "Inferred page dir for $src_page_dir is no longer \"without_notebook/\""
            @test_broken false
        end
    end

    @testset "stylesheet" begin
        src_page_dir = joinpath(root, "stylesheet")
        page = DemoPage(src_page_dir)

        @test page.stylesheet == abspath(src_page_dir, "assets", "emptystyle.css")
        html_file = @suppress_err preview_demos(src_page_dir, require_html=true)
        @test occursin("emptystyle.css", read(html_file, String))
        @test "emptystyle.css" in readdir(joinpath(dirname(html_file), "stylesheet", "assets"))
    end
end


text:
plotBelief(mkd::ManifoldKernelDensity,w...;kw...) = plotKDE(mkd.belief, w...;kw...)
plotBelief(arr::AbstractVector{<:ManifoldKernelDensity},w...;kw...) = plotKDE((x->x.belief).(arr), w...;kw...)

"""
    $(SIGNATURES)

A peneric KDE plotting function that allows marginals of higher dimensional beliefs and various keyword options.

Example for `Position2`:
-----------------------
```julia

p = manikde!(Position2, [randn(2) for _ in 1:100])
q = manikde!(Position2, [randn(2).+[5;0] for _ in 1:100])

plotBelief(p)
plotBelief(p, dims=[1;2], levels=3)
plotBelief(p, dims=[1])

plotBelief([p;q])
plotBelief([p;q], dims=[1;2], levels=3)
plotBelief([p;q], dims=[1])
```

Example for `Pose2`:
--------------------
```julia
# TODO
```
"""
function plotBelief(fgl::AbstractDFG,
                    sym::Symbol;
                    solveKey::Symbol=:default,
                    dims=nothing,
                    title="",
                    levels::Int=5,
                    fill::Bool=false,
                    layers::Bool=false,
                    c=nothing,
                    overlay=nothing )
  #
  p = getBelief(getVariable(fgl,sym), solveKey)
  # mmarg = length(marg) > 0 ? marg : collect(1:Ndim(p))
  # mp = marginal(p,mmarg)
  bel = p isa BallTreeDensity ? p : p.belief
  plotKDE(bel, levels=levels, dims=dims, title=string(sym, "  ", title), fill=fill, layers=layers, c=c, overlay=overlay )
end

function plotBelief(fgl::AbstractDFG,
                    syms::AbstractVector{Symbol};
                    solveKey::Symbol=:default,
                    addt::Union{<:AbstractVector{<:BallTreeDensity},AbstractVector{<:ManifoldKernelDensity}}=BallTreeDensity[],
                    dims=nothing,
                    title=nothing,
                    levels=3,
                    layers::Bool=false,
                    c=getColorsByLength(length(syms)),
                    overlay=nothing  )
  #
  # TODO -- consider automated rotisary of color
  # colors = ["black";"red";"green";"blue";"cyan";"deepskyblue"; "yellow"]
  # COLORS = repmat(colors, 10)
  # COLORS = getColorsByLength(length(syms))
  MP = BallTreeDensity[]
  LEG = String[]
  # mmarg = Int[]
  for sym in syms
    p = getBelief(getVariable(fgl,sym), solveKey)
    # mmarg = length(marg) > 0 ? marg : collect(1:Ndim(p))
    # mp = marginal(p,mmarg)
    if p isa BallTreeDensity
      push!(MP, p)
    else
      push!(MP, p.belief)
    end
    push!(LEG, string(sym))
  end
  for p in addt
    # mp = marginal(p,mmarg)
    push!(MP, p)
    push!(LEG, "add")
  end
  plotKDE(MP; c, levels, dims, legend=LEG, title, layers, overlay)
end

#


text:
# GCM Boundary Conditions
# This file contains helpers and lists currely avaiable options

# Helper for parsing `--surface-flux` command line argument
function parse_surface_flux_arg(
    arg,
    ::Type{FT},
    param_set,
    orientation,
    moisture,
) where {FT}
    if arg === nothing || arg == "default"
        boundaryconditions = (AtmosBC(), AtmosBC())
    elseif arg == "bulk"
        if !isa(moisture, EquilMoist)
            error("need a moisture model for surface-flux: bulk")
        end
        _C_drag = C_drag(param_set)::FT
        bulk_flux = Varying_SST_TJ16(param_set, orientation, moisture) # GCM-specific function for T_sfc, q_sfc = f(latitude, height)
        #bulk_flux = (T_sfc, q_sfc) # prescribed constant T_sfc, q_sfc
        boundaryconditions = (
            AtmosBC(
                energy = BulkFormulaEnergy(
                    (bl, state, aux, t, normPu_int) -> _C_drag,
                    (bl, state, aux, t) -> bulk_flux(state, aux, t),
                ),
                moisture = BulkFormulaMoisture(
                    (state, aux, t, normPu_int) -> _C_drag,
                    (state, aux, t) -> begin
                        _, q_tot = bulk_flux(state, aux, t)
                        q_tot
                    end,
                ),
            ),
            AtmosBC(),
        )
    else
        error("unknown surface flux: " * arg)
    end

    return boundaryconditions
end

# Current options for GCM boundary conditions:

"""
struct Varying_SST_TJ16{PS, O, MM}
    param_set::PS
    orientation::O
    moisture::MM

Defines analytical function for prescribed T_sfc and q_sfc, following
Thatcher and Jablonowski (2016), used to calculate bulk surface fluxes.
T_sfc_pole = SST at the poles (default: 271 K), specified above
"""
struct Varying_SST_TJ16{PS, O, MM}
    param_set::PS
    orientation::O
    moisture::MM
end
function (st::Varying_SST_TJ16)(state, aux, t)
    FT = eltype(state)
    φ = latitude(st.orientation, aux)

    T_sfc_pole = FT(271.0)              # surface polar temperature
    Δφ = FT(26) * FT(π) / FT(180)       # latitudinal width of Gaussian function
    ΔSST = FT(29)                       # Eq-pole SST difference in K
    T_sfc = ΔSST * exp(-φ^2 / (2 * Δφ^2)) + T_sfc_pole

    eps = FT(0.622)
    ρ = state.ρ

    q_tot = state.moisture.ρq_tot / ρ
    q = PhasePartition(q_tot)

    e_int = internal_energy(st.moisture, st.orientation, state, aux)
    T = air_temperature(st.param_set, e_int, q)
    p = air_pressure(st.param_set, T, ρ, q)

    _T_triple = T_triple(st.param_set)::FT          # triple point of water
    _press_triple = press_triple(st.param_set)::FT  # sat water pressure at T_triple
    _LH_v0 = LH_v0(st.param_set)::FT                # latent heat of vaporization at T_triple
    _R_v = R_v(st.param_set)::FT                    # gas constant for water vapor

    q_sfc =
        eps / p *
        _press_triple *
        exp(-_LH_v0 / _R_v * (FT(1) / T_sfc - FT(1) / _T_triple))

    return T_sfc, q_sfc
end

max_forks_repo_name: jm-c/CLIMA


text:
function rpbc_quad(p1, p2, side)

	rx = (p1[1] - p2[1]) % side
	ry = (p1[2] - p2[2]) % side

	if rx > side/2
		rx -= side
	elseif rx < -side/2
		rx += side
	end

	if ry > side/2
		ry -= side
	elseif ry < -side/2
		ry += side
	end

	return rx, ry, rx^2 + ry^2
end


text:
########################################
# STABLE POPULATION PARAMETERS
########################################

# Load required packages
using FishEBM, Distributions

# Specify stock assumptions:
# * s_a.naturalmortality = Age specific mortality
# * s_a.halfmature = Age at 50% maturity
# * s_a.broodsize = Age specific fecundity
# * s_a.fecunditycompensation = Compensatory strength - fecundity
# * s_a.maturitycompensation = Compensatory strength - age at 50% maturity
# * s_a.mortalitycompensation = Compensatory strength - adult natural mortality
# * s_a.catchability = Age specific catchability
adult_a = AdultAssumptions([0.0045, 0.0055, 0.0065, 0.0075, 0.0085, 0.0095, 0.0105], #[0.006, 0.005, 0.005, 0.0045, 0.006, 0.008, 0.0105]
                       5,
                       [2500, 7500, 15000, 20000, 22500, 27500, 32500],
                       2,
                       0.25,
                       1,
                       [0.00001, 0.00002, 0.000025, 0.000025, 0.000025, 0.000025, 0.000025])

# Specify environment assumptions:
# * e_a.spawning = Spawning areas
# * e_a.habitat = Habitat types
# * e_a.risk = Risk areas
spawnPath = string(split(Base.source_path(), "FishEBM.jl")[1], "FishEBM.jl/maps/LakeHuron_1km_spawning.csv")
habitatPath = string(split(Base.source_path(), "FishEBM.jl")[1], "FishEBM.jl/maps/LakeHuron_1km_habitat.csv")
riskPath = string(split(Base.source_path(), "FishEBM.jl")[1], "FishEBM.jl/maps/LakeHuron_1km_risk.csv")
harvestPath = string(split(Base.source_path(), "FishEBM.jl")[1], "FishEBM.jl/maps/LakeHuron_1km_harvest.csv")

enviro_a = initEnvironment(spawnPath, habitatPath, riskPath, harvestPath)

# Specify agent assumptions:
# * a_a.naturalmortality =  Weekly natural mortality rate (by habitat type in the rows, and stage in the columns)
# * a_a.extramortality = Weekly risk mortality (by stage)
# * a_a.growth = Stage length (in weeks)
# * a_a.movement = Movement weight matrices
# * a_a.autonomy =  Movement autonomy

agent_a = AgentAssumptions([[0.15 0.10 0.05 0.0015]
                            [0.13 0.05 0.03 0.001]
                            [0.40 0.20 0.10 0.002]
                            [0.60 0.30 0.15 0.004]
                            [0.80 0.40 0.20 0.006]
                            [0.90 0.50 0.25 0.0095]],
                        [0.0, 0.0, 0.0, 0.0],
                       [19, 52, 104, 0],
                       Array[[[0. 0. 0.]
                              [0. 1. 0.]
                              [0. 0. 0.]], [[1. 2. 1.]
                                            [1. 2. 1.]
                                            [1. 1. 1.]], [[1. 2. 1.]
                                                          [1. 1. 1.]
                                                          [1. 1. 1.]], [[1. 2. 1.]
                                                                        [1. 1. 1.]
                                                                        [1. 1. 1.]]],
                       [0., 0.25, 0.5, 0.75])

# Begin life cycle simulation, specifying:
# * Year specific carrying capacity (vector length determines simulation length)
# * Annual fishing effort
# * Population bump

k = rand(Normal(500000, 50000), 100)
effortVar = [0.0]

# stock = [stage 1 (0 weeks old), stage 2 (first week of stage 2),
# stage 3 (first week of stage 3), stage 4 (2 years), stage 4 (4 years),
# stage 4 (8 years)]
initialStock = [15000, 12500, 10000, 7000, 5000, 2000]
stockAge = [0, -agent_a.growth[1], -agent_a.growth[2], -agent_a.growth[3],-4*52,-8*52] # In weeks

# simulate
adb = simulate(k, effortVar, initialStock, stockAge, enviro_a, adult_a, agent_a)


text:
@testset "Tokenizer" begin
  @test bert_uncased_tokenizer(" \tHeLLo!how  \n Are yoU?  ") == ["hello", "!", "how", "are", "you", "?"]
  @test bert_uncased_tokenizer("H\u00E9llo") == ["hello"]
  @test bert_uncased_tokenizer("ah\u535A\u63A8zz") == ["ah", "\u535A", "\u63A8", "zz"]

  @test bert_cased_tokenizer(" \tHeLLo!how  \n Are yoU?  ") == ["HeLLo", "!", "how", "Are", "yoU", "?"]

  #check space definition consistent with bert
  @test isspace(' ')
  @test isspace('\t')
  @test isspace('\r')
  @test isspace('\n')
  @test isspace('\u00A0')
  @test !isspace('A')
  @test !isspace('-')

  @test BidirectionalEncoder.isinvalid('\u0005')
  @test !BidirectionalEncoder.isinvalid('A')
  @test !BidirectionalEncoder.isinvalid(' ')
  @test !BidirectionalEncoder.isinvalid('\t')
  @test !BidirectionalEncoder.isinvalid('\r')
  @test !BidirectionalEncoder.isinvalid('\U0001F4A9')

  @test BidirectionalEncoder.isbertpunct('-')
  @test BidirectionalEncoder.isbertpunct('$')
  @test BidirectionalEncoder.isbertpunct('`')
  @test BidirectionalEncoder.isbertpunct('.')
  @test !BidirectionalEncoder.isbertpunct('A')
  @test !BidirectionalEncoder.isbertpunct(' ')
end