text:
using Graphs:
    AbstractGraph,
    DiGraph,
    add_edge!,
    add_vertices!,
    nv,
    is_cyclic,
    is_connected,
    edges,
    topological_sort_by_dfs,
    src,
    dst

export Workflow, dependencies, chain, lfork, rfork, diamond, ▷, ⋲, ⋺, ⋄

const DEPENDENCIES = Dict{Job,Vector{AtomicJob}}()

struct Workflow
    graph::DiGraph{Int}
    jobs::Vector{AtomicJob}
    function Workflow(graph, jobs)
        @assert !is_cyclic(graph) "`graph` must be an acyclic graph!"
        @assert is_connected(graph) "`graph` is not connected!"
        if nv(graph) != length(jobs)
            throw(DimensionMismatch("`graph`'s size is different from `jobs`!"))
        end
        @assert unique(jobs) == jobs "at least two jobs are identical!"
        return new(graph, jobs)
    end
end
function Workflow(jobs::Job...)
    graph = DiGraph(length(jobs))
    dict = Dict(zip(jobs, 1:length(jobs)))
    for (i, job) in enumerate(jobs)
        for dependency in dependencies(job)
            j = dict[dependency]
            add_edge!(graph, j, i)
        end
    end
    order = topological_sort_by_dfs(graph)
    new = collect(jobs[order])
    graph = DiGraph(length(jobs))
    dict = Dict(zip(jobs, 1:length(jobs)))
    for (i, job) in enumerate(jobs)
        for dependency in dependencies(job)
            j = dict[dependency]
            add_edge!(graph, j, i)
        end
    end
    return Workflow(graph, new)
end

dependencies(job::Job) = get(DEPENDENCIES, job, AtomicJob[])

function chain(a::Job, b::Job)
    if a == b
        throw(ArgumentError("a job cannot have itself as a dependency!"))
    else
        if haskey(DEPENDENCIES, b)
            if a ∉ DEPENDENCIES[b]  # Duplicate running will push the same job multiple times
                push!(DEPENDENCIES[b], a)
            end
        else
            push!(DEPENDENCIES, b => [a])  # Initialization
        end
        return b
    end
end
function chain(xs::AbstractVector{<:Job}, ys::AbstractVector{<:Job})
    for (x, y) in zip(xs, ys)
        x ▷ y
    end
    return ys
end
const ▷ = chain

function lfork(x::Job, ys::AbstractVector{<:Job})
    if x in ys
        throw(ArgumentError("a job cannot have itself as a dependency!"))
    else
        for y in ys
            x ▷ y
        end
    end
    return ys
end
const ⋲ = lfork

function rfork(xs::AbstractVector{<:Job}, y::Job)
    if y in xs
        throw(ArgumentError("a job cannot have itself as a dependency!"))
    else
        for x in xs
            x ▷ y
        end
    end
    return y
end
const ⋺ = rfork

diamond(x::Job, ys::AbstractVector{<:Job}, z::Job) = (x ⋲ ys) ⋺ z
const ⋄ = diamond

function run!(w::Workflow; nap_job = 3, attempts = 5, nap = 3)
    @assert isinteger(attempts) && attempts >= 1
    for _ in 1:attempts
        inner_run!(w; nap_job = nap_job)
        if any(!issucceeded(job) for job in w.jobs)
            inner_run!(w; nap_job = nap_job)
            all(issucceeded(job) for job in w.jobs) ? break : sleep(nap)
        end
    end
    return w
end
function inner_run!(w::Workflow; nap_job)
    for job in w.jobs  # The nodes have been topologically sorted.
        if !issucceeded(job)
            if isrunning(job)
                wait(job)
                sleep(nap_job)
            else
                run!(job; attempts = 1)
                wait(job)
                sleep(nap_job)
            end
        end
    end
    return w
end

function initialize!()
    empty!(DEPENDENCIES)
    empty!(JOB_REGISTRY)
    return
end
function initialize!(w::Workflow)
    for node in w.jobs
        initialize!(node)
    end
    return w
end

function Base.show(io::IO, w::Workflow)
    if get(io, :compact, false) || get(io, :typeinfo, nothing) == typeof(w)
        Base.show_default(IOContext(io, :limit => true), w)  # From https://github.com/mauro3/Parameters.jl/blob/ecbf8df/src/Parameters.jl#L556
    else
        println(io, summary(w))
        println(io, " ", w.graph)
        println(io, "jobs:")
        for (i, job) in enumerate(w.jobs)
            println(io, " (", i, ") ", "id: ", job.id)
            if !isempty(job.desc)
                print(io, ' '^5, "description: ")
                show(io, job.desc)
                println(io)
            end
            print(io, ' '^5, "def: ")
            show(io, job.def)
            print(io, '\n', ' '^5, "status: ")
            printstyled(io, getstatus(job); bold = true)
            if !ispending(job)
                println(
                    io,
                    '\n',
                    ' '^5,
                    "from: ",
                    format(starttime(job), "dd-u-YYYY HH:MM:SS.s"),
                )
                print(io, ' '^5, "to: ")
                if isrunning(job)
                    print(io, "still running...")
                else
                    println(io, format(stoptime(job), "dd-u-YYYY HH:MM:SS.s"))
                    print(io, ' '^5, "uses: ", elapsed(job))
                end
            end
            println(io)
        end
    end
end


text:
using JuliaDB
using OnlineStats
using Base.Test

@testset "online stats" begin
global dt
    t = NDSparse(Columns([1,1,1,2,2,2,3,3,3], [1,2,3,1,2,3,1,2,3]), [0.5,1,1.5,1,2,3,2,3,4])
    dt = distribute(t,[3,2,4])
    @test value(reduce(Mean(), t))[1] ≈ 2
    @test value(reduce(Mean(), dt))[1] ≈ 2

    means = groupreduce(Series(Mean()), dt, 1)
    @test collect(values(map(x->x.stats[1].μ, means))) == [1.0, 2.0, 3.0]
   # @test length(means.chunks) == 2
   # @test Series((keys(dt), values(dt)), LinReg(2)).stats[1].β |> string == string([0.615385, 0.448718])

   # regs = aggregate_stats(Series(LinReg(2)), keys(dt, 1), keys(dt), values(dt))
   # @test isapprox(values(map(x->coef(x.stats[1]), regs)) |> collect, [[0, 0.5], [0.0, 1.0], [0.3333333, 1.0]], rtol=10e-5) |> all
end

ext: jl


text:
using DSGE, ModelConstructors, JLD2, FileIO, Test, Dates, Random

writing_output = false
if VERSION < v"1.5"
    ver = "111"
else
    ver = "150"
end

path = dirname(@__FILE__())

# Set up arguments
m = AnSchorfheide(testing = true)
m <= Setting(:date_forecast_start, quartertodate("2015-Q4"))

forecast_args = load("$path/../reference/forecast_args.jld2")
df = forecast_args["df"]
system = forecast_args["system"]

# Read expected output
smooth_out = load("$path/../reference/smooth_out_version=" * ver * ".jld2")
exp_states = smooth_out["exp_states"]
exp_shocks = smooth_out["exp_shocks"]
exp_pseudo = smooth_out["exp_pseudo"]

# Smooth without drawing states
states = Dict{Symbol, Matrix{Float64}}()
shocks = Dict{Symbol, Matrix{Float64}}()
pseudo = Dict{Symbol, Matrix{Float64}}()

@testset "Test smoother without drawing states" begin
    for smoother in [:hamilton, :koopman, :carter_kohn, :durbin_koopman]
        m <= Setting(:forecast_smoother, smoother)

        states[smoother], shocks[smoother], pseudo[smoother] =
        smooth(m, df, system; draw_states = false)

        @test @test_matrix_approx_eq exp_states states[smoother]
        @test @test_matrix_approx_eq exp_shocks shocks[smoother]
        @test @test_matrix_approx_eq exp_pseudo pseudo[smoother]
    end
end

# Smooth, drawing states
for smoother in [:carter_kohn, :durbin_koopman]
    m <= Setting(:forecast_smoother, smoother)
    smooth(m, df, system; draw_states = true)
end

# Now check for regime switching
custom_settings = Dict{Symbol, Setting}(
                                        :data_vintage             => Setting(:data_vintage, "160812"),
                                        :cond_vintage             => Setting(:cond_vintage, "160812"),
                                        :cond_id                  => Setting(:cond_id, 0),
                                        :use_population_forecast  => Setting(:use_population_forecast, true),
                                        :date_presample_start     => Setting(:date_presample_start, Date(1959, 9, 30)),
                                        :date_forecast_start      => Setting(:date_forecast_start, DSGE.quartertodate("2016-Q3")),
                                        :date_conditional_end     => Setting(:date_conditional_end, DSGE.quartertodate("2016-Q3")),
                                        :n_mon_anticipated_shocks => Setting(:n_mon_anticipated_shocks, 6))

m = Model1002("ss10", custom_settings = custom_settings, testing = true)
m <= Setting(:rate_expectations_source, :ois)
# df = load_data(m; check_empty_columns = false, verbose = :none, summary_statistics = :none)
df = load("$path/../reference/regime_switch_data.jld2", "none")

m_rs1 = Model1002("ss10", custom_settings = custom_settings) # pseudo regime switching (no values have second/third regimes)
m_rs1 <= Setting(:rate_expectations_source, :ois)
m_rs1 <= Setting(:regime_switching, true)
m_rs1 <= Setting(:n_regimes, 3)
m_rs1 <= Setting(:regime_dates, Dict{Int, Date}(1 => date_presample_start(m_rs1), 2 => Date(2010, 3, 31),
                                                3 => Date(2012, 3, 31)))
setup_regime_switching_inds!(m_rs1)

m_rs2 = Model1002("ss51v", custom_settings = custom_settings) # pseudo regime switching (identical values for standard deviations)
m_rs2 <= Setting(:rate_expectations_source, :ois)
m_rs2 <= Setting(:regime_switching, true)
m_rs2 <= Setting(:n_regimes, 3)
m_rs2 <= Setting(:regime_dates, Dict{Int, Date}(1 => date_presample_start(m_rs1), 2 => Date(2010, 3, 31),
                                                3 => Date(2012, 3, 31)))
setup_regime_switching_inds!(m_rs2)

m_rs3 = Model1002("ss51v", custom_settings = custom_settings) # non-trivial regime switching
m_rs3 <= Setting(:rate_expectations_source, :ois)
m_rs3 <= Setting(:regime_switching, true)
m_rs3 <= Setting(:n_regimes, 3)
m_rs3 <= Setting(:regime_dates, Dict{Int, Date}(1 => date_presample_start(m_rs1), 2 => Date(2010, 3, 31),
                                                3 => Date(2012, 3, 31)))
setup_regime_switching_inds!(m_rs3)

# Need to set shocks for second and third regimes
prop = 1.
prop3 = .95
for i in 1:3
    if i == 1
        oldprop3 = prop3
        prop3 = prop
    end
    ModelConstructors.set_regime_val!(m_rs2[:σ_g], i, prop * m[:σ_g].value)
    ModelConstructors.set_regime_val!(m_rs2[:σ_b], i, prop * m[:σ_b].value)
    ModelConstructors.set_regime_val!(m_rs2[:σ_μ], i, prop * m[:σ_μ].value)
    ModelConstructors.set_regime_val!(m_rs2[:σ_ztil], i, prop * m[:σ_ztil].value)
    ModelConstructors.set_regime_val!(m_rs2[:σ_λ_f], i, prop * m[:σ_λ_f].value)
    ModelConstructors.set_regime_val!(m_rs2[:σ_λ_w], i, prop * m[:σ_λ_w].value)
    ModelConstructors.set_regime_val!(m_rs2[:σ_r_m], i, prop * m[:σ_r_m].value)
    ModelConstructors.set_regime_val!(m_rs2[:σ_σ_ω], i, prop * m[:σ_σ_ω].value)
    ModelConstructors.set_regime_val!(m_rs2[:σ_μ_e], i, prop * m[:σ_μ_e].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs2[:σ_γ], i, prop * m[:σ_γ].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs2[:σ_π_star], i, prop * m[:σ_π_star].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs2[:σ_lr], i, prop * m[:σ_lr].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs2[:σ_z_p], i, prop * m[:σ_z_p].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs2[:σ_tfp], i, prop * m[:σ_tfp].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs2[:σ_gdpdef], i, prop * m[:σ_gdpdef].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs2[:σ_corepce], i, prop * m[:σ_corepce].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs2[:σ_gdp], i, prop * m[:σ_gdp].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs2[:σ_gdi], i, prop * m[:σ_gdi].value, override_bounds = true)

    for j = 1:DSGE.n_mon_anticipated_shocks(m_rs2)
        ModelConstructors.set_regime_val!(m_rs2[Symbol("σ_r_m$(j)")], i, prop * m[Symbol("σ_r_m$(i)")])
    end

    ModelConstructors.set_regime_val!(m_rs3[:σ_g], i, prop3 * m[:σ_g].value)
    ModelConstructors.set_regime_val!(m_rs3[:σ_b], i, prop3 * m[:σ_b].value)
    ModelConstructors.set_regime_val!(m_rs3[:σ_μ], i, prop3 * m[:σ_μ].value)
    ModelConstructors.set_regime_val!(m_rs3[:σ_ztil], i, prop3 * m[:σ_ztil].value)
    ModelConstructors.set_regime_val!(m_rs3[:σ_λ_f], i, prop3 * m[:σ_λ_f].value)
    ModelConstructors.set_regime_val!(m_rs3[:σ_λ_w], i, prop3 * m[:σ_λ_w].value)
    ModelConstructors.set_regime_val!(m_rs3[:σ_r_m], i, prop3 * m[:σ_r_m].value)
    ModelConstructors.set_regime_val!(m_rs3[:σ_σ_ω], i, prop3 * m[:σ_σ_ω].value)
    ModelConstructors.set_regime_val!(m_rs3[:σ_μ_e], i, prop3 * m[:σ_μ_e].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs3[:σ_γ], i, prop3 * m[:σ_γ].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs3[:σ_π_star], i, prop3 * m[:σ_π_star].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs3[:σ_lr], i, prop3 * m[:σ_lr].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs3[:σ_z_p], i, prop3 * m[:σ_z_p].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs3[:σ_tfp], i, prop3 * m[:σ_tfp].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs3[:σ_gdpdef], i, prop3 * m[:σ_gdpdef].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs3[:σ_corepce], i, prop3 * m[:σ_corepce].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs3[:σ_gdp], i, prop3 * m[:σ_gdp].value, override_bounds = true)
    ModelConstructors.set_regime_val!(m_rs3[:σ_gdi], i, prop3 * m[:σ_gdi].value, override_bounds = true)

    for j = 1:DSGE.n_mon_anticipated_shocks(m_rs3)
        ModelConstructors.set_regime_val!(m_rs3[Symbol("σ_r_m$(j)")], i, prop3 * m[Symbol("σ_r_m$(i)")])
    end

    if i == 1
        global prop3 = oldprop3
    end
end

states = Dict{Symbol, Matrix{Float64}}()
shocks = Dict{Symbol, Matrix{Float64}}()
pseudo = Dict{Symbol, Matrix{Float64}}()
states_rs1 = Dict{Symbol, Matrix{Float64}}()
shocks_rs1 = Dict{Symbol, Matrix{Float64}}()
pseudo_rs1 = Dict{Symbol, Matrix{Float64}}()
states_rs2 = Dict{Symbol, Matrix{Float64}}()
shocks_rs2 = Dict{Symbol, Matrix{Float64}}()
pseudo_rs2 = Dict{Symbol, Matrix{Float64}}()
states_rs3 = Dict{Symbol, Matrix{Float64}}()
shocks_rs3 = Dict{Symbol, Matrix{Float64}}()
pseudo_rs3 = Dict{Symbol, Matrix{Float64}}()

states_sv = Matrix{Float64}[]
shocks_sv = Matrix{Float64}[]
pseudo_sv = Matrix{Float64}[]

@info "The following warnings about smoothers being called with draw_states = true are expected."
@testset "Smoothing with regime switching" begin
    system = compute_system(m)
    system_rs1 = compute_system(m_rs1)
    system_rs2 = compute_system(m_rs2)
    system_rs3 = compute_system(m_rs3)
    for smoother in [:durbin_koopman, :hamilton, :koopman, :carter_kohn#=, :durbin_koopman=#]
        m <= Setting(:forecast_smoother, smoother)
        m_rs1 <= Setting(:forecast_smoother, smoother)
        m_rs2 <= Setting(:forecast_smoother, smoother)
        m_rs3 <= Setting(:forecast_smoother, smoother)
        states[smoother], shocks[smoother], pseudo[smoother] =
        smooth(m, df, system; draw_states = false)
        states_rs1[smoother], shocks_rs1[smoother], pseudo_rs1[smoother] =
        smooth(m_rs1, df, system_rs1; draw_states = false)
        states_rs2[smoother], shocks_rs2[smoother], pseudo_rs2[smoother] =
        smooth(m_rs2, df, system_rs2; draw_states = false)
        states_rs3[smoother], shocks_rs3[smoother], pseudo_rs3[smoother] =
        smooth(m_rs3, df, system_rs3; draw_states = false)

        @test @test_matrix_approx_eq states_rs1[smoother] states[smoother]
        @test @test_matrix_approx_eq shocks_rs1[smoother] shocks[smoother]
        @test @test_matrix_approx_eq pseudo_rs1[smoother] pseudo[smoother]
        @test @test_matrix_approx_eq states_rs1[smoother] states_rs2[smoother]
        @test @test_matrix_approx_eq shocks_rs1[smoother] shocks_rs2[smoother]
        @test @test_matrix_approx_eq pseudo_rs1[smoother] pseudo_rs2[smoother]
        @test !(states_rs3[smoother] ≈ states_rs2[smoother])
        @test !(shocks_rs3[smoother] ≈ shocks_rs2[smoother])
        @test !(pseudo_rs3[smoother] ≈ pseudo_rs2[smoother])

        if writing_output && smoother == :durbin_koopman
            jldopen("$path/../reference/smooth_out_draw_states=false_version="
                    * ver * ".jld2", "w") do file
                write(file, "exp_states_regime_switch", states_rs3[:durbin_koopman])
                write(file, "exp_shocks_regime_switch", shocks_rs3[:durbin_koopman])
                write(file, "exp_pseudo_regime_switch", pseudo_rs3[:durbin_koopman])
            end
        end

        exp_states_regime_switch = load("$path/../reference/smooth_out_draw_states=false_version=" * ver * ".jld2", "exp_states_regime_switch")
        exp_shocks_regime_switch = load("$path/../reference/smooth_out_draw_states=false_version=" * ver * ".jld2", "exp_shocks_regime_switch")
        exp_pseudo_regime_switch = load("$path/../reference/smooth_out_draw_states=false_version=" * ver * ".jld2", "exp_pseudo_regime_switch")

        if smoother == :durbin_koopman
            @test @test_matrix_approx_eq states_rs3[smoother] exp_states_regime_switch
            @test @test_matrix_approx_eq shocks_rs3[smoother] exp_shocks_regime_switch
            @test @test_matrix_approx_eq pseudo_rs3[smoother] exp_pseudo_regime_switch[1:21, :] # extra rows b/c used more pseudo-obs when generating the test file
        else # the other smoothers should generate similar output, but may not be the exact same thing
            @test maximum(abs.(states_rs3[smoother] - exp_states_regime_switch))  < 6e-1
            @test maximum(abs.(shocks_rs3[smoother] - exp_shocks_regime_switch))  < 2e-1
            @test maximum(abs.(pseudo_rs3[smoother] - exp_pseudo_regime_switch[1:21, :])) < 3e-1
        end
    end

    @info "The following warnings about calling smoothers with draw_states = true are expected."
    for smoother in [:durbin_koopman, :hamilton, :koopman, :carter_kohn]
        m <= Setting(:forecast_smoother, smoother)
        m_rs1 <= Setting(:forecast_smoother, smoother)
        m_rs2 <= Setting(:forecast_smoother, smoother)
        m_rs3 <= Setting(:forecast_smoother, smoother)

        Random.seed!(1793)
        states[smoother], shocks[smoother], pseudo[smoother] =
        smooth(m, df, system; draw_states = true)
        Random.seed!(1793)
        states_rs1[smoother], shocks_rs1[smoother], pseudo_rs1[smoother] =
        smooth(m_rs1, df, system_rs1; draw_states = true)
        Random.seed!(1793)
        states_rs2[smoother], shocks_rs2[smoother], pseudo_rs2[smoother] =
        smooth(m_rs2, df, system_rs2; draw_states = true)
        Random.seed!(1793)
        states_rs3[smoother], shocks_rs3[smoother], pseudo_rs3[smoother] =
        smooth(m_rs3, df, system_rs3; draw_states = true)

        @test @test_matrix_approx_eq states_rs1[smoother] states[smoother]
        @test @test_matrix_approx_eq shocks_rs1[smoother] shocks[smoother]
        @test @test_matrix_approx_eq pseudo_rs1[smoother] pseudo[smoother]
        @test @test_matrix_approx_eq states_rs1[smoother] states_rs2[smoother]
        @test @test_matrix_approx_eq shocks_rs1[smoother] shocks_rs2[smoother]
        @test @test_matrix_approx_eq pseudo_rs1[smoother] pseudo_rs2[smoother]
        @test !(states_rs3[smoother] ≈ states_rs2[smoother])
        @test !(shocks_rs3[smoother] ≈ shocks_rs2[smoother])
        @test !(pseudo_rs3[smoother] ≈ pseudo_rs2[smoother])

        if writing_output && smoother == :durbin_koopman
            jldopen("$path/../reference/smooth_out_draw_states=true_version="
                    * ver * ".jld2", "w") do file
                write(file, "exp_states_regime_switch_draw", states_rs3[:durbin_koopman])
                write(file, "exp_shocks_regime_switch_draw", shocks_rs3[:durbin_koopman])
                write(file, "exp_pseudo_regime_switch_draw", pseudo_rs3[:durbin_koopman])
            end
        end

        exp_states_regime_switch_draw = load("$path/../reference/smooth_out_draw_states=true_version=" * ver * ".jld2", "exp_states_regime_switch_draw")
        exp_shocks_regime_switch_draw = load("$path/../reference/smooth_out_draw_states=true_version=" * ver * ".jld2", "exp_shocks_regime_switch_draw")
        exp_pseudo_regime_switch_draw = load("$path/../reference/smooth_out_draw_states=true_version=" * ver * ".jld2", "exp_pseudo_regime_switch_draw")

        if smoother == :durbin_koopman
            @test maximum(abs.(states_rs3[smoother] - exp_states_regime_switch_draw)) < 3e-5
            # @test @test_matrix_approx_eq states_rs3[smoother] exp_states_regime_switch_draw
            @test @test_matrix_approx_eq shocks_rs3[smoother] exp_shocks_regime_switch_draw
            #    @test @test_matrix_approx_eq pseudo_rs3[smoother] exp_pseudo_regime_switch_draw
        end
    end

    if writing_output
        jldopen("$path/../reference/smooth_out_version=" * ver * ".jld2", "w") do file
            file["exp_states"] = exp_states
            file["exp_shocks"] = exp_shocks
            file["exp_pseudo"] = exp_pseudo
        end
    end
end

nothing


text:
using FileIO
using Yao
using YaoExtensions
using BetaVQE
using LinearAlgebra

function build_key(nx, ny, Γ, β, depth, nsamples, nhiddens, lr; folder="data/")
    mkpath(folder)
    key = folder*"/tfim"
    key *= "_nx$nx"
    key *= "_ny$ny"
    key *= "_Gamma$Γ"
    key *= "_beta$β"
    key *= "_d$depth"
    key *= "_batch$nsamples"
    key *= "_lr$lr"
    key *= "_nhiddens"

    for h in nhiddens
        key = key * "_$h"
    end
    key
end

function exact_spectra(nx::Int, ny::Int, Γ::Real; folder="data/exact/")
    mkpath(folder)
    h = hamiltonian(TFIM(nx, ny; Γ=Γ, periodic=false))
    H = mat(h)
    w, _ = eigen(Matrix(H))
    save(folder*"/nx$nx"*"ny$ny"*"Gamma$Γ"*".jld2", "spectra", w)
end


text:
#############################################################################
# type SCOPEProblem{M}
#   head::Symbol                      # :minimize or :maximize
#   objective::AbstractExpr
#   status::Symbol                    # the status of the problem
#   optval::Float64OrNothing
#   model::T                          # a subtype of PrimalModel or DualModel, see models.jl
#   solution::Solution
#############################################################################

export SCOPEProblem, SCOPEminimize, SCOPEmaximize, satisfy, add_constraints!

const Float64OrNothing = Union{Float64, Nothing}

mutable struct SCOPEProblem{T <: SCOPEModel}
  head::Symbol
  objective::AbstractExpr
  constraints::AbstractArray
  status::String
  optval::Float64OrNothing
  model::T
  # solution::Solution
end

function SCOPEProblem(head::Symbol, objective::AbstractExpr, model::SCOPEModel,
                 constraints::Array=Constraint[])
  if sign(objective) == ComplexSign()
    error("Objective can not be a complex expression")
  else
    return SCOPEProblem(head, objective, constraints, "not yet solved", nothing, model)
  end
end

# constructor if model is not specified
function SCOPEProblem(head::Symbol, objective::AbstractExpr,
                 constraints::AbstractArray=Constraint[],
                 model::SCOPEModel = get_model(objective, constraints))
  SCOPEProblem(head, objective, model, constraints)
end

SCOPEProblem(head::Symbol, objective::AbstractExpr, constraints::Constraint...) =
  SCOPEProblem(head, objective, [constraints...])

# Allow users to simply type minimize
SCOPEminimize(objective::AbstractExpr, constraints::Constraint...) =
  SCOPEProblem(:minimize, objective, collect(constraints))
SCOPEminimize(objective::AbstractExpr, constraints::Array{<:Constraint}=Constraint[]) =
  SCOPEProblem(:minimize, objective, constraints)
SCOPEminimize(objective::Values, constraints::Constraint...) =
  minimize(convert(AbstractExpr, objective), collect(constraints))
SCOPEminimize(objective::AbstractExpr, constraints::Array{<:Constraint}=Constraint[]) =
  minimize(convert(AbstractExpr, objective), constraints)

# Allow users to simply type maximize
SCOPEmaximize(objective::AbstractExpr, constraints::Constraint...) =
  SCOPEProblem(:maximize, objective, collect(constraints))
SCOPEmaximize(objective::AbstractExpr, constraints::Array{<:Constraint}=Constraint[]) =
  SCOPEProblem(:maximize, objective, constraints)
SCOPEmaximize(objective::Values, constraints::Constraint...) =
  maximize(convert(AbstractExpr, objective), collect(constraints))
SCOPEmaximize(objective::AbstractExpr, constraints::Array{<:Constraint}=Constraint[]) =
  maximize(convert(AbstractExpr, objective), constraints)

# # Allow users to simply type satisfy (if there is no objective)
# satisfy(constraints::Constraint...) = SCOPEProblem(:minimize, Constant(0), [constraints...])
# satisfy{T<:Constraint}(constraints::Array{T}=Constraint[]) =
#   SCOPEProblem(:minimize, Constant(0), constraints)
# satisfy(constraint::Constraint) = satisfy([constraint])

# +(constraints, constraints) is defined in constraints.jl
add_constraints!(objective::AbstractExpr, constraints::Array{<:Constraint}=Constraint[]) = +(p.constraints, constraints)
add_constraints!(p::SCOPEProblem, constraint::Constraint) = add_constraints!(p, [constraint])
add_constraint! = add_constraints!


text:
"""
Name of resource bundle used for string messages.
"""
const MESSAGES = "messages"

"""
    tr"string_with_interpolation"

Return translated string accoring to string database and a default locale.
The interpolated values are embedded into the translated string.
Multiple plural forms are supported. The multiplicity is determined by the primary
interpolation value, which must be an integer.
"""
macro tr_str(p)
    src, mod = VERSION < v"0.7-DEV" ?
        (LineNumberNode(0),  current_module()) : (__source__, __module__)
    tr_macro_impl(src, mod, p)
end

"""
    string_to_key(text::AbstractString)

Convert text to key. Replace interpolation syntax with standardized interpoleated integers.
Example without explicit primarity:
    `string_to_key("text\$var \$(expr) \$(77)") == "text$(1) $(2) $(3)"`
Example with explicit primarity:
    `string_to_key("text\$var \$(!(expr)) \$(77)") == "text$(2) $(1) $(3)"`
(The first interpolation annotated with '`!`' gets number 1).
The interpolation must not be a literal string.
"""
string_to_key(p::AbstractString) = _string2ex1(p)[3]

function tr_macro_impl(::LineNumberNode, mod::Module, p::Any)
    ex1, arg, s1 = _string2ex1(p)
    arg = Expr(:tuple, arg...)
    :(eval(translate($s1, $mod, $ex1, $(esc(arg)))))
end

#
function translate(s1::AbstractString, mod::Module, ex1, arg)
    mb = resource_bundle(mod, MESSAGES)
    resource = get_resource_by_key(mb, s1)
    s2 = resource != nothing ? get(resource.dict, s1, s1) : s1
    _translate(s1, s2, resource, ex1, arg)
end

# translate in case of single translation text
function _translate(s1::AbstractString, s2::AbstractString, resource, ex1::Any, arg)
    ex2, ind2 = _string2ex(s2, arg)
    if length(ind2) > 0
        m1, m2 = extrema(ind2)
        m1 >= 1 && m2 <= length(arg) || return ex1
    end
    ex2
end

#translate in case of multiple translation texts (plural forms)
function _translate(s1::AbstractString, s2::Vector{S}, resource, ex1::Any, arg) where S<:AbstractString
    length(arg) >= 1 || throw(ArgumentError("tr needs at least one argument: '$s1'"))
    mp = arg[1]
    n = isinteger(mp) ? abs(Int(mp)) : 999 # if arg not integer numerically use plural form
    ix = resource != nothing ? resource.plural(n) + 1 : 1
    m = length(s2)
    ix = ifelse(ix <= m, ix, m)
    str = ix > 0 ? s2[ix] : s1 # fall back to key if vector is empty
    _translate(s1, str, resource, ex1, arg)
end

# produce modified Expr, list of interpolation arguments, and key string
function _string2ex1(p::AbstractString)
    ex = Meta.parse(string(TQ, p, TQ)) # parsing text argument of str_tr
    args = isa(ex, Expr) ? ex.args : [ex]
    ea = []
    i = 1
    multi = false
    for j in 1:length(args)
        a = args[j]
        if ! ( a isa String )
            if !multi && a isa Expr && a.head == :call && a.args[1] == SPRIME
                multi = true
                pushfirst!(ea, a.args[2]) # this argument goes to index 1
                args[j] = 1
                for k = 1:j-1
                    if args[k] isa Int  # previous arguments shift index
                        args[k] += 1
                    end
                end
                i += 1
            else
                args[j] = i
                push!(ea, a)
                i += 1
            end
        end
    end

    io = IOBuffer()
    for j in 1:length(args)
        a = args[j]
        if a isa String
            print(io, a)
        else
            print(io, "\$(", a, ")")
        end
    end
    ex, ea, String(take!(io))
end

# produce Expr with interpolation arguments replaced, and original list of positions
function _string2ex(p::AbstractString, oldargs)
    ex = Meta.parse(string(TQ, p, TQ)) # parsing translated text
    args = isa(ex, Expr) ? ex.args : [ex]
    i = 0
    ea = Int[]
    n = oldargs == nothing ? 0 : length(oldargs)
    for j in 1:length(args)
        a = args[j]
        if a isa Int
            i += 1
            args[j] = 0 < a <= n ? oldargs[a] : a
            push!(ea, a)
        end
    end
    ex, ea
end

TQ = "\"\"\""   # three quote characters in a string
SPRIME = :!     # multiplicity indicator in tr-string    tr"... $(!count) ..."
SCONTEXT = "§"  # context separator in tr-string         tr"§ctxname§..."


text:
using Pkg
Pkg.activate(".")

using Reproduce

function main()

    as = ArgParseSettings()
    @add_arg_table as begin
        "config"
        arg_type=String
        "--numworkers"
        arg_type=Int
        default=4
    end
    parsed = parse_args(as)

    experiment = Experiment(parsed["config"])

    create_experiment_dir(experiment; tldr="")
    add_experiment(experiment)
    ret = job(experiment; num_workers=parsed["numworkers"])
    post_experiment(experiment, ret)

end

main()

max_stars_repo_name: MatthewMcLeod/curiosity

max_issues_repo_name: MatthewMcLeod/curiosity

max_forks_repo_name: MatthewMcLeod/curiosity


text:
### ImageGrid

using Colors: RGB

struct ImageGrid{T<:AbstractArray{<:Number}}
    data::T
end

function ImageGrid(data::AbstractMatrix{<:Number})
    local shape
    try
        d = size(data, 1)
        if d == 28 * 28         # MNIST-like
            shape = (28, 28)
        elseif d == 32 * 32 * 3 # CIFAR-like
            shape = (32, 32, 3)
        else
            l = convert(Int, sqrt(d))
            shape = (l, l)
        end
    catch
        @error "Cannot automatically convert an image which is not squared."
    end
    return ImageGrid(data, shape)
end

function ImageGrid(data::AbstractMatrix{<:Number}, shape::Tuple{Vararg{Int,N}}) where {N}
    @assert N == 2 || N == 3
    data = reshape(data, shape..., last(size(data)))
    return ImageGrid(data)
end

image(data::AbstractMatrix) = Matrix{RGB}(data)

function image(data::AbstractArray)
    w, h, c = size(data)
    img = Matrix{RGB}(undef, w, h)
    for i in 1:w, j in 1:h
        img[i,j] = RGB(data[i,j,:]...)
    end
    return img
end

"""
    make_imggrid(data::AbstractArray{<:Number,4}, nrows, ncols; gap::Int=1)

Create a nrows by ncols image grid.
"""
function make_imggrid(data::AbstractArray{<:Number,4}, nrows, ncols; gap::Int=1)
    w, h, c, n = size(data)
    @assert c == 1 || c == 3
    imggrid = 0.5 * ones(nrows * (w + gap) + gap, ncols * (h + gap) + gap, c)
    i = 1
    for row = 1:nrows, col = 1:ncols
        if i <= n
            i_row = (row - 1) * (w + gap) + 1
            i_col = (col - 1) * (h + gap) + 1
            imggrid[i_row+1:i_row+w,i_col+1:i_col+h,:] .= data[:,:,:,i]
        else
            break
        end
        i += 1
    end
    if c == 1  # imshow supports gray as 3D tensor
        imggrid = dropdims(imggrid; dims=3)
    end
    return imggrid
end

function make_imggrid(data::AbstractArray{<:Number,3}, args...; kwargs...)
    w, h, n = size(data)
    data = reshape(data, w, h, 1, n)
    return make_imggrid(data, args...; kwargs...)
end

"""
    make_imggrid(data; kwargs...)

Create an approximately squared image grid based on the number of images.
For example, if last(size(data)) is 100, the grid will be 10 by 10.
"""
function make_imggrid(data; kwargs...)
    n = last(size(data))
    nrows = ceil(Int, sqrt(n))
    ncols = nrows * (nrows - 1) > n ? nrows - 1 : nrows
    return make_imggrid(data, nrows, ncols; kwargs...)
end

@recipe function f(ig::ImageGrid, args::Int...)
    imggrid = make_imggrid(ig.data, args...)

    seriestype --> :image

    image(imggrid)
end

### FeatureActivations

struct FeatureActivations{T<:AbstractMatrix{Bool}}
    Z::T
end

function FeatureActivations(Z::Matrix{Int})
    @assert Set(unique(Z)) == Set((0, 1))
    return FeatureActivations(Matrix{Bool}(Z))
end

function count_leadingzeros(z::Vector)
    # Iterate until the frist non-zero item
    n = 1
    while n <= length(z) && z[n] == 0
        n = n + 1
    end
    return n - 1
end

@recipe function f(fa::FeatureActivations; sort=false)
    Z = fa.Z

    if sort
        col_sort_idcs = sortperm(vec([count_leadingzeros(Z[:,k]) for k = 1:size(Z, 2)]))
        Z = Z[:,col_sort_idcs]
    end

    image(Z)
end


text:
using Ramnet.Encoders
using Ramnet

using Random
using StaticArrays

using ..Approximators:QDiscriminator
using ..Buffers: MultiStepDynamicBuffer, add!
using ..Environments

mutable struct SARSADiscountedDiscriminatorAgent{AS,OS,T <: Real,O <: StaticArray{Tuple{OS},T,1},A <: Real,E <: AbstractEncoder{T}} <: AbstractAgent{O,A}
    steps::Int
    actions::SVector{AS,A}
    discount::Float64
    ϵ_start::Float64
    ϵ_end::Float64
    ϵ_decay::Int
    update_count::Int
    Q̂::QDiscriminator{AS,OS,T,O,A,E}
    buffer::MultiStepDynamicBuffer{O,A}
    observation::Union{Nothing,O}
    done::Bool
    action::Union{Nothing,A}
    rng::MersenneTwister
end

function SARSADiscountedDiscriminatorAgent(::Type{O}, actions::StaticArray{Tuple{AS},A,1}, steps, n, forgetting_factor, discount, ϵ_start, ϵ_end, ϵ_decay, encoder::E; seed::Union{Nothing,UInt}=nothing) where {AS,OS,T,O <: StaticArray{Tuple{OS},T,1},A,E <: AbstractEncoder{T}}
    !isnothing(seed) && seed < 0 && throw(DomainError(seed, "Seed must be non-negative"))
    rng = isnothing(seed) ? MersenneTwister() : MersenneTwister(seed)

    n < 1 && throw(DomainError(n, "Tuple size must be at least 1"))
    # size < n && throw(DomainError(size, "Input size may not be smaller then tuple size"))
    !(0 ≤ discount ≤ 1) && throw(DomainError(regressor_discount, "Discount must lie in the [0, 1] interval"))

    Q̂ = QDiscriminator(O, actions, n, forgetting_factor, encoder, seed)
    buffer = MultiStepDynamicBuffer{O,A}()

    SARSADiscountedDiscriminatorAgent{AS,OS,T,O,A,E}(steps, actions, discount, ϵ_start, ϵ_end, ϵ_decay, 0, Q̂, buffer, nothing, false, nothing, rng)
end

function SARSADiscountedDiscriminatorAgent(
    env, encoder::E; steps, tuple_size, forgetting_factor::Float64=1.0, discount::Float64=1.0, epsilon_start::Float64=0.01, epsilon_end::Float64=0.0, epsilon_decay::Int=1000, seed::Union{Nothing,UInt}=nothing) where {T <: Real,E <: AbstractEncoder{T}}
    # SARSADiscountedDiscriminatorAgent{observation_type(env),action_type(env),T,E}(steps, action_set(env), n, observation_length(env), forget, gamma, epsilon, encoder; seed)
    SARSADiscountedDiscriminatorAgent(observation_type(env), action_set(env), steps, tuple_size, forgetting_factor, discount, epsilon_start, epsilon_end, epsilon_decay, encoder; seed)
end

function observe!(agent::SARSADiscountedDiscriminatorAgent{AS,OS,T,O,A,E}, observation::O) where {AS,OS,T,O,A,E} # {O,A <: Real,T <: Real,E <: AbstractEncoder{T}}
    agent.observation = observation
    agent.done = false
    agent.action = _select_action(agent, observation)

    nothing
end

# TODO: All observe! methods are the same for all agents. Generalize.
# TODO: This method does not need to take in the action
function observe!(agent::SARSADiscountedDiscriminatorAgent{AS,OS,T,O,A,E}, action::A, reward::Float64, observation::O, done::Bool) where {AS,OS,T,O,A,E} # {O,A <: Real,T <: Real,E <: AbstractEncoder{T}}
    add!(agent.buffer, agent.observation, agent.action, reward)

    if !done
        agent.action = _select_action(agent, observation)
    end

    agent.observation = observation
    agent.done = done
    nothing
end

function epsilon(agent::SARSADiscountedDiscriminatorAgent)
    α = agent.update_count / agent.ϵ_decay
    (1 - α) * agent.ϵ_start + α * agent.ϵ_end
end

function _select_action(agent::SARSADiscountedDiscriminatorAgent{AS,OS,T,O,A,E}, observation::O) where {AS,OS,T,O,A,E}
    if rand(agent.rng) < epsilon(agent)
        return rand(agent.rng, agent.actions)
    end

    return select_action(agent.Q̂, observation)
end

function select_action!(agent::SARSADiscountedDiscriminatorAgent{AS,OS,T,O,A,E}, observation::O) where {AS,OS,T,O,A,E}
    if !isnothing(agent.action)
        return agent.action
    end

    return _select_action(agent, observation)
end

function update!(agent::SARSADiscountedDiscriminatorAgent)
    if agent.done
        G = 0.0
        for transition in Iterators.reverse(agent.buffer)
            G = transition.reward + agent.discount * G

            update!(agent.Q̂, transition.observation, transition.action, G)
        end

        reset!(agent.buffer)
    elseif length(agent.buffer) == agent.steps
        # next_action = select_action!(agent, agent.observation)

        G = agent.Q̂(agent.observation, agent.action)

        for transition in Iterators.reverse(agent.buffer)
            G = transition.reward + agent.discount * G
        end

        t = popfirst!(agent.buffer)

        update!(agent.Q̂, t.observation, t.action, G)
    end

    # agent.action = nothing

    nothing
end

function reset!(agent::SARSADiscountedDiscriminatorAgent; seed::Union{Nothing,UInt}=nothing)
    if !isnothing(seed)
        if seed ≥ 0
        Random.seed!(agent.rng, seed)
        else
            throw(DomainError(seed, "Seed must be non-negative"))
        end
    end

    reset!(agent.Q̂; seed)
    reset!(agent.buffer)

    nothing
end


text:
@testset "GroupBy" begin

    using DataFrames

    df = DataFrame(Chrom = repeat(["chr1"], 10),
                   Pos = 1:10,
                   Gene = ["a", "b", "c", "a", "b", "c", "a", "b", "c", "d"],
                   Value = 1:10)

    di = Tables.namedtupleiterator(df)

    g = di |> GOR.groupby(1, [:Gene]; sum = Sum(:Value), count = Count())

    @test g |> eltype ==
        NamedTuple{(:Chrom, :bpStart, :bpEnd, :Gene, :sum, :count),Tuple{String,Int64,Int64,String,Float64,Int64}}

    @test g |> DataFrame |> size == (10, 6)

    @test Tables.istable(g)
    @test Tables.rowaccess(g)
    @test Tables.schema(g) == Tables.Schema{(:Chrom, :bpStart, :bpEnd, :Gene, :sum, :count),
                                           Tuple{String,Int64,Int64,String,Float64,Int64}}()

end


text:
using Dates

const FIRST_YEAR = 2015

function hfun_posts()
    curyear = year(Dates.today())
    io = IOBuffer()
    for year in curyear:-1:FIRST_YEAR
        ys = "$year"
        isdir(joinpath("posts", ys)) || continue
        write(io, "\n\n### $year\n\n")
        write(io, "@@list,mb-5\n")
        for month in 12:-1:1
            ms = "0"^(month < 10) * "$month"
            base = joinpath("posts", ys, ms)
            isdir(base) || continue
            posts = filter!(p -> endswith(p, ".md"), readdir(base))
            days  = zeros(Int, length(posts))
            lines = Vector{String}(undef, length(posts))
            for (i, post) in enumerate(posts)
                ps  = splitext(post)[1]
                url = "/posts/$ys/$ms/$ps/"
                surl = strip(url, '/')
                title = pagevar(surl, :title)
                days[i] = parse(Int, first(ps, 2))
                pubdate = Dates.format(
                    Date(year, month, days[i]), "U d")

                tmp = "* ~~~$pubdate$title"
                descr = pagevar(surl, :descr)
                if descr !== nothing
                    tmp *= ": $descr"
                end
                lines[i] = tmp * "~~~\n"
            end
            # sort by day
            foreach(line -> write(io, line), lines[sortperm(days, rev=true)])
        end
        write(io, "@@\n")
    end
    return Franklin.fd2html(String(take!(io)), internal=true)
end

@delay function hfun_list_tags()
    tagpages = globvar("fd_tag_pages")
    if tagpages === nothing
        return ""
    end
    tags = tagpages |> keys |> collect |> sort
    tags_count = [length(tagpages[t]) for t in tags]
    io = IOBuffer()
    for (t, c) in zip(tags, tags_count)
        write(io, """
            <nobr>
              $(replace(t, "_" => " "))
               ($c)
            </nobr>
            """)
    end
    return String(take!(io))
end

# doesn't need to be delayed because it's generated at tag generation, after everything else
function hfun_tag_list()
    tag = locvar(:fd_tag)::String
    items = Dict{Date,String}()
    for rpath in globvar("fd_tag_pages")[tag]
        title = pagevar(rpath, "title")
        url = Franklin.get_url(rpath)
        surl = strip(url, '/')

        ys, ms, ps = split(surl, '/')[end-2:end]
        date = Date(parse(Int, ys), parse(Int, ms), parse(Int, first(ps, 2)))
        date_str = Dates.format(date, "U d, Y")

        tmp = "* ~~~$date_str<nobr>$title</nobr>"
        descr = pagevar(rpath, :descr)
        if descr !== nothing
            tmp *= ": $descr"
        end
        tmp *= "~~~\n"
        items[date] = tmp
    end
    sorted_dates = sort!(items |> keys |> collect, rev=true)
    io = IOBuffer()
    write(io, "@@posts-container,mx-auto,px-3,py-5,list,mb-5\n")
    for date in sorted_dates
        write(io, items[date])
    end
    write(io, "@@")
    return Franklin.fd2html(String(take!(io)), internal=true)
end

function hfun_current_tag()
    return replace(locvar("fd_tag"), "_" => " ")
end

hfun_svg_linkedin() = """<svg width="30" height="30" viewBox="0 50 512 512"><path fill="currentColor" d="M150.65 100.682c0 27.992-22.508 50.683-50.273 50.683-27.765 0-50.273-22.691-50.273-50.683C50.104 72.691 72.612 50 100.377 50c27.766 0 50.273 22.691 50.273 50.682zm-7.356 86.651H58.277V462h85.017V187.333zm135.901 0h-81.541V462h81.541V317.819c0-38.624 17.779-61.615 51.807-61.615 31.268 0 46.289 22.071 46.289 61.615V462h84.605V288.085c0-73.571-41.689-109.131-99.934-109.131s-82.768 45.369-82.768 45.369v-36.99z"/></svg>"""

hfun_svg_github() = """<svg width="30" height="30" viewBox="0 0 25 25" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>"""

hfun_svg_twitter() = """<svg width="30" height="30" viewBox="0 0 335 276" fill="currentColor"><path d="M302 70A195 195 0 0 1 3 245a142 142 0 0 0 97-30 70 70 0 0 1-58-47 70 70 0 0 0 31-2 70 70 0 0 1-57-66 70 70 0 0 0 28 5 70 70 0 0 1-18-90 195 195 0 0 0 141 72 67 67 0 0 1 116-62 117 117 0 0 0 43-17 65 65 0 0 1-31 38 117 117 0 0 0 39-11 65 65 0 0 1-32 35"/></svg>"""

hfun_svg_tag() = """<svg width="20" height="20" viewBox="0 0 512 512"><defs></defs><path class="cls-1" d="M215.8 512a76.1 76.1 0 0 1-54.17-22.44L22.44 350.37a76.59 76.59 0 0 1 0-108.32L242 22.44A76.11 76.11 0 0 1 296.2 0h139.2A76.69 76.69 0 0 1 512 76.6v139.19A76.08 76.08 0 0 1 489.56 270L270 489.56A76.09 76.09 0 0 1 215.8 512zm80.4-486.4a50.69 50.69 0 0 0-36.06 14.94l-219.6 219.6a51 51 0 0 0 0 72.13l139.19 139.19a51 51 0 0 0 72.13 0l219.6-219.61a50.67 50.67 0 0 0 14.94-36.06V76.6a51.06 51.06 0 0 0-51-51zm126.44 102.08A38.32 38.32 0 1 1 461 89.36a38.37 38.37 0 0 1-38.36 38.32zm0-51a12.72 12.72 0 1 0 12.72 12.72 12.73 12.73 0 0 0-12.72-12.76z"/><path class="cls-1" d="M217.56 422.4a44.61 44.61 0 0 1-31.76-13.16l-83-83a45 45 0 0 1 0-63.52L211.49 154a44.91 44.91 0 0 1 63.51 0l83 83a45 45 0 0 1 0 63.52L249.31 409.24a44.59 44.59 0 0 1-31.75 13.16zm-96.7-141.61a19.34 19.34 0 0 0 0 27.32l83 83a19.77 19.77 0 0 0 27.31 0l108.77-108.7a19.34 19.34 0 0 0 0-27.32l-83-83a19.77 19.77 0 0 0-27.31 0l-108.77 108.7z"/><path class="cls-1" d="M294.4 281.6a12.75 12.75 0 0 1-9-3.75l-51.2-51.2a12.8 12.8 0 0 1 18.1-18.1l51.2 51.2a12.8 12.8 0 0 1-9.05 21.85zM256 320a12.75 12.75 0 0 1-9.05-3.75l-51.2-51.2a12.8 12.8 0 0 1 18.1-18.1l51.2 51.2A12.8 12.8 0 0 1 256 320zM217.6 358.4a12.75 12.75 0 0 1-9-3.75l-51.2-51.2a12.8 12.8 0 1 1 18.1-18.1l51.2 51.2a12.8 12.8 0 0 1-9.05 21.85z"/></svg>"""

@delay function hfun_page_tags()
    pagetags = globvar("fd_page_tags")
    pagetags === nothing && return ""
    io = IOBuffer()
    tags = pagetags[splitext(locvar("fd_rpath"))[1]] |> collect |> sort
    several = length(tags) > 1
    write(io, """
$(hfun_svg_tag())""")
    for tag in tags[1:end-1]
        t = replace(tag, "_" => " ")
        write(io, """$t, """)
    end
    tag = tags[end]
    t = replace(tag, "_" => " ")
    write(io, """$t
""")
    return String(take!(io))
end


text:
# padded coefs
function padded_coefs(::Type{TC}, A::AbstractArray, it) where {TC}
    indsA = axes(A)
    indspad = Interpolations.padded_axes(indsA, it)
    return Interpolations.padded_similar(TC, indspad)
end
padded_coefs(A,it) = padded_coefs(Interpolations.tcoef(A), A, it)

# padded coefs
struct InPlaceInterp{T, TC, N, A<:AbstractArray{T,N}, TCoefs<:AbstractArray{TC,N}, IT<:Interpolations.DimSpec{BSpline}, RT<:NTuple{N,AbstractRange},ITP<:Interpolations.BSplineInterpolation,SITP<:ScaledInterpolation}
    x::A
    coef::TCoefs
    it::IT
    ranges::RT
    itp::ITP
    sitp::SITP

    function InPlaceInterp(x::A, it::IT, ranges::RT) where {T, N, A<:AbstractArray{T,N}, IT, RT}
        Interpolations.check_ranges(it, axes(x), ranges)
        TC = Interpolations.tcoef(x)
        coef = padded_coefs(TC, x, it)
        TCoefs = typeof(coef)

        tw = Interpolations.tweight(x)
        itp = Interpolations.BSplineInterpolation(tw, coef, it, axes(x))
        sitp = Interpolations.scale(itp, ranges...)
        ITP = typeof(itp)
        SITP = typeof(sitp)
        return new{T, TC, N, A, TCoefs, IT, RT, ITP, SITP}(x, coef, it, ranges, itp, sitp)
    end
end

data(x::InPlaceInterp) = x.x
coefficients(x::InPlaceInterp) = x.coef
itpflag(x::InPlaceInterp) = x.it
ranges(x::InPlaceInterp) = x.ranges
size(x::InPlaceInterp) = size(data(x))

function update_interpolation!(x::InPlaceInterp)
    A = data(x)
    coefs = coefficients(x)
    it = itpflag(x)
    tw = Interpolations.tweight(A)

    indsA = axes(A)
    indspad = Interpolations.padded_axes(indsA, it)
    @assert indspad == axes(coefs) "coefs axes != padded_axes(x.x, x.it)"

    if indspad == indsA
        copyto!(coefs, A)
    else
        fill!(coefs, 0)
        Interpolations.ct!(coefs, indsA, A, indsA)
    end
    Interpolations.prefilter!(tw, coefs, it)
end

interpolation(x::InPlaceInterp) = x.itp
scaled_interpolation(x::InPlaceInterp) = x.sitp

# function interpolation(x::InPlaceInterp)
#     A = data(x)
#     tw = Interpolations.tweight(A)
#     return Interpolations.BSplineInterpolation(tw, coefficients(x), itpflag(x), axes(A))
# end
#
# function scaled_interpolation(x::InPlaceInterp)
#     itp = interpolation(x)
#     return Interpolations.scale(itp, ranges(x)...)
# end


text:
function rand_pdist(n::Integer)
    collect(partitions(100,n))[rand(1:end)]/100
end

prod_time = 0
div_time = 0

amount_of_operations = 10000

for i=1:amount_of_operations
    q = rand_pdist(3)''

    pd1 = ProbabilityDistribution(["x1", "x2"], hcat(ones(Float64, length(q), 1) - q, q), ["y1", "y2", "y3"])
    pd2 = ProbabilityDistribution(["y1","y3", "y2"],rand_pdist(3))

    prod_time += @elapsed res = pd1*pd2
    div_time += @elapsed res/pd2
end

println("Average time to compute the multiplication product between a 3x2 PD and a 3x1 PD: $(prod_time/amount_of_operations*1000)ms")
println("Average time to compute divition product between a 3x2 PD and a 3x1 PD: $(div_time/amount_of_operations*1000)ms")


text:
# This file contains the necessary ingredients to create a PackageManager for BinDeps
using BinDeps

type Manager <: BinDeps.PackageManager
    packages::Vector{Compat.ASCIIString}
end

function Base.show(io::IO, manager::Manager)
    write(io, "Conda packages: ", join(manager.packages, ", "))
end

BinDeps.can_use(::Type{Manager}) = true

function BinDeps.package_available(manager::Manager)
    pkgs = manager.packages
    # For each package, see if we can get info about it. If not, fail out
    for pkg in pkgs
        if !exists(pkg)
            return false
        end
    end
    return true
end

if is_unix()
    BinDeps.libdir(::Manager, ::Any) = joinpath(PREFIX, "lib")
end
if is_windows()
    function BinDeps.libdir(m::Manager, ::Any)
        package = m.packages[1]
        if package in _installed_packages()
            joinpath(PREFIX, "pkgs", version(package), "Library", "bin")
        else
            # Return a default path, as we can not call version() on package.
            joinpath(PREFIX, "lib")
        end
    end
end

BinDeps.bindir(m::Manager, ::Any) = BINDIR

BinDeps.provider{T<:String}(::Type{Manager}, packages::Vector{T}; opts...) = Manager(packages)
BinDeps.provider(::Type{Manager}, packages::String; opts...) = Manager([packages])

function BinDeps.generate_steps(dep::BinDeps.LibraryDependency, manager::Manager, opts)
    pkgs = manager.packages
    if isa(pkgs, AbstractString)
        pkgs = [pkgs]
    end
    ()->install(pkgs)
end

function install(pkgs)
    for pkg in pkgs
        add(pkg)
    end
end


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

using Markdown
using InteractiveUtils

# ╔═╡ 67e41500-261d-11eb-2c0a-a73f5fa0b717
begin
	import Pkg
	Pkg.activate(mktempdir())
	Pkg.add(["Images", "ImageIO", "ImageMagick", "TestImages"])
	Pkg.add("ColorTypes")
	using Images, ColorTypes, Colors
end

# ╔═╡ d74d4100-2622-11eb-15ea-5d5b62231ac6
md""""https://juliaimages.org/stable/tutorials/arrays_colors/"""

# ╔═╡ c4ce73a0-2622-11eb-0429-f30ed1a33adc
md"""## Arrays"""

# ╔═╡ 623030f0-261b-11eb-1b0f-2dac8ca7ec47
md""" Create a simple Array - and notice, how you create the values defines its structure aswell INT vs FLOAT """

# ╔═╡ 6215cb20-261b-11eb-0e10-4126a5ceca5e
a = [1,2,3,4,5,6]

# ╔═╡ ecd11532-261b-11eb-384e-9b55e367b0b5
b = [1.0,2.0,3.0,4.0]

# ╔═╡ 372fa060-261c-11eb-2388-67483442e0e4
c = [rand(3)]

# ╔═╡ fa80ca20-2622-11eb-3d55-4dda95db6540
md"""## Gray"""

# ╔═╡ 75082ff0-261d-11eb-289e-6fc19c439eb5
md"""Create Random image for 4by4"""

# ╔═╡ 74ed2de0-261d-11eb-1bcf-e39d81baa116
imc = rand(4,4)

# ╔═╡ 74d475c0-261d-11eb-190b-59c46feeba2f
typeof(imc)

# ╔═╡ 74b8fe80-261d-11eb-337a-ef4a01e023e4
size(imc)

# ╔═╡ ef0105d0-2621-11eb-1510-95272847ae5d
sizeof(imc)

# ╔═╡ 749f0de2-261d-11eb-1965-1debd418009b
imc0 = Gray.(imc)

# ╔═╡ facac0e0-2621-11eb-3e86-351d639411cb
sizeof(imc)

# ╔═╡ 3979f6d0-2622-11eb-2445-4b7c71a0bd97
sizeof(imc0)

# ╔═╡ 3ed14de0-2622-11eb-3c91-7704e9f9e175
md"""imc and imc0 are still the same, Gray in imc0 is just saying to interprate it as colors hence below is true aswell"""

# ╔═╡ 5dc7f09e-2622-11eb-1311-7fed95367a66
imc == imc0

# ╔═╡ 63da5720-261e-11eb-372d-0389d2da3480
md"""Under the hood, what is Gray doing? It's informative to see the "raw" object, displayed as text:"""

# ╔═╡ 63c2d780-261e-11eb-0664-cda7f36a91a7
display(MIME("text/plain"),imc0)

# ╔═╡ 63aa1f60-261e-11eb-2cfa-81e2e8b5ff91
md"""so the above command will show result on command line or REPL , what it will show is, with every value in float in the array, it will show its true form as Gray{Float64}"""

# ╔═╡ 639278b0-261e-11eb-03f8-03c675bfac17
dump(imc0[1,1])

# ╔═╡ 61fac910-261b-11eb-1e3c-37a44569b98c
md""" above command again only works either on ijulia, or repl or command line - o/p would be like:::
- julia> dump(imc2[1,1])
- Gray{Float64}
- val: Float64 0.26014202162736244"""

# ╔═╡ 61df9ff0-261b-11eb-1a66-39eee1b59bb7
md"""dump shows the "internal" representation of an object. You can see that Gray is a type (technically, an immutable struct) with a single field val; for Gray{Float64}, val is a 64-bit floating point number. Using val directly is not recommended: you can extract the Float64 value with the accessor functions real or gray (the reason for the latter name will be clearer when we discuss RGB colors).  """

# ╔═╡ 61c33e50-261b-11eb-2626-872a0a6ca404
md"""## Color  """

# ╔═╡ 61aa5f20-261b-11eb-3d88-5d6aee1887a8
md""" Just like Gray above, lets create Colors """

# ╔═╡ 1ba4ad20-2623-11eb-389b-6dcae19e4231
imgCo = rand(RGB{Float32}, 4,4)

# ╔═╡ 618bb38e-261b-11eb-22d4-0103c306cd44
md""" just like gray in REPL or ijulia, you can see actual value by 2 below ways::
-
- julia> imgc
- 2×2 Array{ColorTypes.RGB{Float32},2}:
- RGB{Float32}(0.75509,0.965058,0.65486)     RGB{Float32}(0.696203,0.142474,0.783316)
- RGB{Float32}(0.705195,0.953892,0.0744661)  RGB{Float32}(0.571945,0.42736,0.548254)
-
-julia> size(imgc)
-(2,2)
-
-julia> dump(imgc[1,1])
-ColorTypes.RGB{Float32}
-  r: Float32 0.7550899
-  g: Float32 0.9650581
-  b: Float32 0.65485954  """

# ╔═╡ 61708a70-261b-11eb-297b-fd97c2c077ce
md""" ## Changing the Color System
 - Gray to RGB to single 32 bit integer to Hexadecmimal"""

# ╔═╡ 52455f10-2843-11eb-265b-c1322c5ca60c
typeof(imgCo)

# ╔═╡ d504c5b0-2624-11eb-186c-3bbcf1fb6646
Z = imgCo[1,1]

# ╔═╡ 4267b3b0-2625-11eb-193e-a7df86622626
typeof(Z)

# ╔═╡ d4eeccb0-2624-11eb-16eb-a3ef4a77dae8
md"""into a single 32-bit integer:"""

# ╔═╡ d4d4dc0e-2624-11eb-33d6-79244672bd17
Z32 = RGB24(Z)

# ╔═╡ d4ba9d50-2624-11eb-3229-396f5dbe1c2b
typeof(Z32)

# ╔═╡ 61564bb0-261b-11eb-10c5-bf695b1057be
md"""the above operation was for just one pixel, can we do for all the image at once, without using any loop, lets try  """

# ╔═╡ acf47740-2625-11eb-2e08-0b417cd3168d
Zz = imgCo

# ╔═╡ acdbbf20-2625-11eb-1dbf-5b3c9500349a
size(Zz)

# ╔═╡ acc3551e-2625-11eb-186d-2fba05178818
typeof(Zz)

# ╔═╡ c9532720-2840-11eb-17f8-c1e7c3c40bc4
h24 = (ColorTypes.RGB24,4,4)

# ╔═╡ 8a457620-2843-11eb-3523-5d9e02a7be18
 YAY9 = parse.(UInt32, hex.(Zz, :RRGGBBAA), base=16)

# ╔═╡ ac6e3980-2a05-11eb-2943-ab113feb9d24
YAY9_chop = parse.(UInt32, hex.(Zz, :RRGGBB), base=16)

# ╔═╡ 38e18a40-29fa-11eb-3207-bfc24ffd9794
YAY91 = reshape(YAY9, (1,16))

# ╔═╡ 38c6fd60-29fa-11eb-16dc-71c3addb6d1e
YAY92 = chomp(str)

# ╔═╡ 38ad33d0-29fa-11eb-0963-75596aa85cac

# ╔═╡ 38ace5b0-29fa-11eb-3d71-09e0b16dce31

# ╔═╡ 387d7140-29fa-11eb-00ff-abdaad584701

# ╔═╡ 613b2290-261b-11eb-163a-716d474caac2
md"""## Our Numbers 0-9 makes the basic Base 10 number system  """

# ╔═╡ 612131f0-261b-11eb-1531-6151f1d6b715
md"""  """

# ╔═╡ 61074150-261b-11eb-02d1-f93b12397a68
md"""  """

# ╔═╡ 60eb06c0-261b-11eb-2f83-adeeaa2d6a62
md"""  """

# ╔═╡ 60cfdda0-261b-11eb-2e5b-81d9cfc01784
md"""  """

# ╔═╡ 60a3eba0-261b-11eb-29d8-75120afc6142
md"""  """

# ╔═╡ Cell order:
# ╟─d74d4100-2622-11eb-15ea-5d5b62231ac6
# ╟─c4ce73a0-2622-11eb-0429-f30ed1a33adc
# ╠═67e41500-261d-11eb-2c0a-a73f5fa0b717
# ╟─623030f0-261b-11eb-1b0f-2dac8ca7ec47
# ╠═6215cb20-261b-11eb-0e10-4126a5ceca5e
# ╠═ecd11532-261b-11eb-384e-9b55e367b0b5
# ╠═372fa060-261c-11eb-2388-67483442e0e4
# ╟─fa80ca20-2622-11eb-3d55-4dda95db6540
# ╟─75082ff0-261d-11eb-289e-6fc19c439eb5
# ╠═74ed2de0-261d-11eb-1bcf-e39d81baa116
# ╠═74d475c0-261d-11eb-190b-59c46feeba2f
# ╠═74b8fe80-261d-11eb-337a-ef4a01e023e4
# ╠═ef0105d0-2621-11eb-1510-95272847ae5d
# ╠═749f0de2-261d-11eb-1965-1debd418009b
# ╠═facac0e0-2621-11eb-3e86-351d639411cb
# ╠═3979f6d0-2622-11eb-2445-4b7c71a0bd97
# ╟─3ed14de0-2622-11eb-3c91-7704e9f9e175
# ╠═5dc7f09e-2622-11eb-1311-7fed95367a66
# ╟─63da5720-261e-11eb-372d-0389d2da3480
# ╠═63c2d780-261e-11eb-0664-cda7f36a91a7
# ╟─63aa1f60-261e-11eb-2cfa-81e2e8b5ff91
# ╠═639278b0-261e-11eb-03f8-03c675bfac17
# ╟─61fac910-261b-11eb-1e3c-37a44569b98c
# ╟─61df9ff0-261b-11eb-1a66-39eee1b59bb7
# ╟─61c33e50-261b-11eb-2626-872a0a6ca404
# ╟─61aa5f20-261b-11eb-3d88-5d6aee1887a8
# ╠═1ba4ad20-2623-11eb-389b-6dcae19e4231
# ╟─618bb38e-261b-11eb-22d4-0103c306cd44
# ╟─61708a70-261b-11eb-297b-fd97c2c077ce
# ╠═52455f10-2843-11eb-265b-c1322c5ca60c
# ╠═d504c5b0-2624-11eb-186c-3bbcf1fb6646
# ╠═4267b3b0-2625-11eb-193e-a7df86622626
# ╟─d4eeccb0-2624-11eb-16eb-a3ef4a77dae8
# ╠═d4d4dc0e-2624-11eb-33d6-79244672bd17
# ╠═d4ba9d50-2624-11eb-3229-396f5dbe1c2b
# ╟─61564bb0-261b-11eb-10c5-bf695b1057be
# ╠═acf47740-2625-11eb-2e08-0b417cd3168d
# ╠═acdbbf20-2625-11eb-1dbf-5b3c9500349a
# ╠═acc3551e-2625-11eb-186d-2fba05178818
# ╠═c9532720-2840-11eb-17f8-c1e7c3c40bc4
# ╠═8a457620-2843-11eb-3523-5d9e02a7be18
# ╠═ac6e3980-2a05-11eb-2943-ab113feb9d24
# ╠═38e18a40-29fa-11eb-3207-bfc24ffd9794
# ╠═38c6fd60-29fa-11eb-16dc-71c3addb6d1e
# ╠═38ad33d0-29fa-11eb-0963-75596aa85cac
# ╠═38ace5b0-29fa-11eb-3d71-09e0b16dce31
# ╠═387d7140-29fa-11eb-00ff-abdaad584701
# ╠═613b2290-261b-11eb-163a-716d474caac2
# ╠═612131f0-261b-11eb-1531-6151f1d6b715
# ╠═61074150-261b-11eb-02d1-f93b12397a68
# ╠═60eb06c0-261b-11eb-2f83-adeeaa2d6a62
# ╠═60cfdda0-261b-11eb-2e5b-81d9cfc01784
# ╠═60a3eba0-261b-11eb-29d8-75120afc6142


text:
using MCMCChains
using Distributions

using Random
using Test

Random.seed!(20)

ProjDir = mktempdir()

@testset "serialization read and write test" begin
    # Consider the model
    # ```math
    # s ~ IG(2, 3)
    # m ~ Normal(0, √s)
    # x ~ Normal(m, √s)
    # ```
    # for variable ``x``. Given observations ``x₁ = 1.5`` and ``x₂ = 2``, sample one chain
    # with 500 samples from the posterior
    # ```math
    # m, s ~ Normal-IG(7/6, 3, 3, 49/12)
    # ```
    vals = Matrix{Float64}(undef, 500, 2)
    rand!(InverseGamma(3, 49/12), view(vals, :, 2))
    for i in 1:size(vals, 1)
        vals[i, 1] = rand(Normal(7/6, sqrt(vals[i, 2] / 3)))
    end
    chn1 = Chains(vals, ["m", "s"])

    write(joinpath(ProjDir, "chn1.jls"), chn1)
    chn2 = read(joinpath(ProjDir, "chn1.jls"), Chains)

    open(joinpath(ProjDir, "chn1.txt"), "w") do io
        describe(io, chn1);
    end

    open(joinpath(ProjDir, "chn2.txt"), "w") do io
        describe(io, chn2);
    end

    @test open(f->read(f, String), joinpath(ProjDir, "chn1.txt")) ==
        open(f->read(f, String), joinpath(ProjDir, "chn2.txt"))
end

rm(ProjDir, force=true, recursive=true)


text:
# disk-phantom.jl

using MIRT: disk_phantom_params, ellipse_im, jim
using Test: @inferred

ig = image_geom(nx = 128, fov = 240)
params = @inferred disk_phantom_params( ; minsep = ig.dx*8)
@test params isa Matrix{Float32}

tmp = ellipse_im(ig, params, oversample=3)
jim(ig.x, ig.y, tmp)


text:
include("./util.jl")

struct On end
struct Off end
struct Toggle end

Op = Union{On,Off,Toggle}

parse_op(str::AbstractString)::Op =
    if str == "turn on"
        On()::Op
    elseif str == "turn off"
        Off()::Op
    elseif str == "toggle"
        Toggle()::Op
    else
        throw(DomainError("Unknown operation $str"))
    end

struct Instruction{T<:Op}
    op::T
    start::Tuple{Int,Int}
    finish::Tuple{Int,Int}
end

function process!(ins::Instruction{On}, arr::Array{Bool,2})::Nothing
    x0, y0 = ins.start
    x1, y1 = ins.finish
    arr[x0:x1, y0:y1] .= true
    nothing
end

function process!(ins::Instruction{Off}, arr::Array{Bool,2})::Nothing
    x0, y0 = ins.start
    x1, y1 = ins.finish
    arr[x0:x1, y0:y1] .= false
    nothing
end

function process!(ins::Instruction{Toggle}, arr::Array{Bool,2})::Nothing
    x0, y0 = ins.start
    x1, y1 = ins.finish
    arr[x0:x1, y0:y1] = broadcast(!, arr[x0:x1, y0:y1])
    nothing
end

function process!(ins::Instruction{On}, arr::Array{Int,2})::Nothing
    x0, y0 = ins.start
    x1, y1 = ins.finish
    arr[x0:x1, y0:y1] .+= 1
    nothing
end

function process!(ins::Instruction{Off}, arr::Array{Int,2})::Nothing
    x0, y0 = ins.start
    x1, y1 = ins.finish
    arr[x0:x1, y0:y1] .-= 1
    arr[x0:x1, y0:y1] = broadcast(v -> max(v, 0), arr[x0:x1, y0:y1])
    nothing
end

function process!(ins::Instruction{Toggle}, arr::Array{Int,2})::Nothing
    mod_ins = Instruction(On(), ins.start, ins.finish)
    process!(mod_ins, arr)
    process!(mod_ins, arr)
    nothing
end

function Instruction(str::AbstractString)::Instruction
    re =
        r"(?<op>turn on|turn off|toggle) (?<source_x>\d+),(?<source_y>\d+) through (?<target_x>\d+),(?<target_y>\d+)"
    m = match(re, str)
    if isnothing(m)
        throw(DomainError("No match for $str"))
    end
    Instruction(
        parse_op(m[:op]),
        (parse(Int, m[:source_x]), parse(Int, m[:source_y])),
        (parse(Int, m[:target_x]), parse(Int, m[:target_y])),
    )
end

instructions = map(Instruction, split(util.load_input(6), '\n'))

state = zeros(Bool, (1000, 1000))

for instruction in instructions
    process!(instruction, state)
end

println("Part 1: $(sum(state))")

new_state = zeros(Int, (1000, 1000))
for instruction in instructions
    process!(instruction, new_state)
end
println("Part 2: $(sum(new_state))")


text:
@everywhere using ArcadeLearningEnvironment
@everywhere using CGP
@everywhere using Logging
@everywhere using Printf
@everywhere using Random
@everywhere import Images
using ArgParse

@everywhere CGP.Config.init("cfg/atari.yaml")
include("../graphing/graph_utils.jl")

@everywhere function play_atari(c::Chromosome, id::String, seed::Int64;
                    render::Bool=false, folder::String=".", max_frames=18000)
    game = Game(id, seed)

    if get_float(game, "repeat_action_probability") != 0.0
        # We implement action repeating already, so we don't want it enabled in A.L.E. too.
        error("A.L.E. is configured with non-zero repeat_action_probability")
    end

    seed_reset = rand(0:100000)
    Random.seed!(seed)
    reward = 0.0
    frames = 0
    p_action = game.actions[1]
    outputs = zeros(Int64, c.nout)
    while ~game_over(game.ale)
        frames += 1
        output = process(c, get_rgb(game))
        outputs[argmax(output)] += 1
        action = game.actions[argmax(output)]
        reward += act(game.ale, action)
        if rand() < 0.25
            reward += act(game.ale, action) # repeat action here for seeding
        end
        if render
            screen = draw(game)
            filename = string(folder, "/", @sprintf("frame_%06d.png", frames))
            Images.save(filename, screen)
        end
        if frames > max_frames
            @debug(string("Termination due to frame count on ", id))
            break
        end
    end
    # Using println rather than @info here so the output is included
    # with the "From worker N" prefix in the logs
    println("Frames: ", frames, " Reward: ", reward)
    close!(game)
    Random.seed!(seed_reset)
    reward, outputs
end

function get_args()
    s = ArgParseSettings()

    @add_arg_table(
        s,
        "--seed", arg_type = Int, default = 0,
        "--log", arg_type = String, default = "atari.log",
        "--id", arg_type = String, default = "centipede",
        "--ea", arg_type = String, default = "oneplus",
        "--chromosome", arg_type = String, default = "CGPChromo",
        "--frames", arg_type = Int, default = 18000,
        "--render", action = :store_const, constant = true, default = false,
    )

    parse_args(CGP.Config.add_arg_settings!(s))
end

function get_bests(logfile::String)
    bests = []
    for line in readlines(logfile)
        if occursin("C:", line)
            genes = eval(Meta.parse(split(line, "C: ")[2]))
            append!(bests, [genes])
        end
    end
    bests
end

function get_params(args::Dict)
    game = Game(args["id"], args["seed"])
    nin = 3 # r g b
    nout = length(game.actions)
    close!(game)
    nin, nout
end

function render_genes(genes::Array{Float64}, args::Dict;
                    ctype::DataType=CGPChromo, id::Int64=0)
    nin, nout = get_params(args)
    chromo = ctype(genes, nin, nout)
    folder = joinpath("frames", string(args["id"], "_", args["seed"], "_", id))
    mkpath(folder)
    reward, out_counts = play_atari(chromo, args["id"], args["seed"];
                                    render=true, folder=folder,
                                    max_frames=args["frames"])
    println(@sprintf("R: %s %d %d %0.5f %d %d",
                     args["id"], args["seed"], id, reward,
                     sum([n.active for n in chromo.nodes]),
                     length(chromo.nodes)))
    new_genes = deepcopy(chromo.genes)
    for o in 1:nout
        if out_counts[o] == 0.0
            # disable this section of the graph by forcing
            # the output to connect to an input node
            new_genes[nin+o] = 0.00001
        end
    end
    active_outputs = out_counts .> 0
    chromo2 = ctype(new_genes, nin, nout)
    mkpath("graphs")
    filename = string(args["id"], "_", args["seed"], "_", id, ".pdf");
    file = abspath(joinpath("graphs", filename))
    chromo_draw(chromo2, file; active_outputs=active_outputs)
end

if ~isinteractive()
    args = get_args()
    CGP.Config.init(Dict([k=>args[k] for k in setdiff(
        keys(args), ["seed", "log", "id", "ea", "chromosome"])]...))

    Random.seed!(args["seed"])
    global_logger(SimpleLogger(open(args["log"], "a+")))
    nin, nout = get_params(args)
    ea = eval(Meta.parse(args["ea"]))
    ctype = eval(Meta.parse(args["chromosome"]))

    fit = x->play_atari(x, args["id"], args["seed"];
                        max_frames=args["frames"])[1]
    maxfit, best = ea(nin, nout, fit;
                      seed=args["seed"], id=args["id"], ctype=ctype)

    # Note: -maxfit is returned, being the "cost" to be minimized by irace
    @info(@sprintf("Z%0.6f", -maxfit))
    if args["render"]
        render_genes(best, args; ctype=ctype)
    end
end


text:
using Test
using Forecast

import DataFrames: DataFrame

@testset "d" begin

    x = [1,2,3,4,5]
    dx = d(x,center=true)
    mdx = ismissing.(dx)
    @test mdx == [0,0,0,0,1]
    @test dx[.!Bool.(mdx)] == [1,1,1,1]

    dx = d(x,2,center=true)
    mdx = ismissing.(dx)
    @test mdx == [1,0,0,0,1]
    @test dx[.!Bool.(mdx)] == [0,0,0]

    dx = d(x,1,2)
    mdx = ismissing.(dx)
    @test mdx == [0,0,0]
    @test dx[.!Bool.(mdx)] == [2,2,2]

    x = reshape(collect(1:20),10,2)
    dx = d(x,2,2)
    @test dx == repeat([0],6,2)

end


text:
# Julia code
# Copyright (c) 2022 the SLICOTMath.jl developers
# Portions extracted from SLICOT-Reference distribution:
# Copyright (c) 2002-2020 NICONET e.V.

function run_mb04od(datfile, io=stdout)
    ZERO  = 0.0e0
    NIN = 5
    NOUT = 6
    MMAX = 20
    NMAX = 20
    PMAX = 20
    LDA = PMAX
    LDB = NMAX
    LDC = PMAX
    LDR = NMAX
    LDWORK = max( NMAX-1,MMAX )
    R = Array{Float64,2}(undef, LDR,NMAX)
    A = Array{Float64,2}(undef, LDA,NMAX)
    B = Array{Float64,2}(undef, LDB,MMAX)
    C = Array{Float64,2}(undef, LDC,MMAX)
    TAU = Array{Float64,1}(undef, NMAX)
    DWORK = Array{Float64,1}(undef, LDWORK)
    f = open(datfile,"r")
    readline(f)
    vs = split(readline(f))
    N = parse(BlasInt, vs[1])
    M = parse(BlasInt, vs[2])
    P = parse(BlasInt, vs[3])
    UPLO =  vs[4][1]
if ( N<0 || N>NMAX )
else
if ( M<0 || M>MMAX )
else
if ( P<0 || P>PMAX )
else

    vs = String[]
    _isz,_jsz = (N,N)
    while length(vs) < _isz*_jsz
        append!(vs, replace.(split(readline(f)),'D'=>'E'))
    end
    for i in 1:_isz
       _i0 = (i-1)*_jsz
       R[i,1:_jsz] .= parsex.(Float64, vs[_i0+1:_i0+_jsz])
    end

    vs = String[]
    _isz,_jsz = (P,N)
    while length(vs) < _isz*_jsz
        append!(vs, replace.(split(readline(f)),'D'=>'E'))
    end
    for i in 1:_isz
       _i0 = (i-1)*_jsz
       A[i,1:_jsz] .= parsex.(Float64, vs[_i0+1:_i0+_jsz])
    end

    vs = String[]
    _isz,_jsz = (N,M)
    while length(vs) < _isz*_jsz
        append!(vs, replace.(split(readline(f)),'D'=>'E'))
    end
    for i in 1:_isz
       _i0 = (i-1)*_jsz
       B[i,1:_jsz] .= parsex.(Float64, vs[_i0+1:_i0+_jsz])
    end

    vs = String[]
    _isz,_jsz = (P,M)
    while length(vs) < _isz*_jsz
        append!(vs, replace.(split(readline(f)),'D'=>'E'))
    end
    for i in 1:_isz
       _i0 = (i-1)*_jsz
       C[i,1:_jsz] .= parsex.(Float64, vs[_i0+1:_i0+_jsz])
    end
# interp call 1

    SLICOT.mb04od!(UPLO, N, M, P, R, A, B, C, TAU)

    triu!(R)
# interp output 1
    println(io,"R:")
    _nc = N
    _nr = N
    show(io,"text/plain",R[1:_nr,1:_nc])
    println(io,)

if ( M>0 )
# interp output 2
    println(io,"B:")
    _nc = M
    _nr = N
    show(io,"text/plain",B[1:_nr,1:_nc])
    println(io,)

if ( P>0 )
# interp output 3
    println(io,"C:")
    _nc = M
    _nr = P
    show(io,"text/plain",C[1:_nr,1:_nc])
    println(io,)

end # if
end # if
end # if
end # if
end # if
    close(f)
end # run_X()


text:
module Random

export uniform32, SplitMix64, Xoshiro256pp, UniformRNG, next, uniformfromindex, choose

@inline function uniform32(x::UInt64) :: Float32
    fract = UInt32((x >> 41) & 0b0_0000_0000_1111_1111_1111_1111_1111_111)
    k = (fract | 0b0_0111_1111_0000_0000_0000_0000_0000_000)
    reinterpret(Float32, k) - 1.0f0
end

# SplitMix64 is based on the description in http://prng.di.unimi.it/splitmix64.c
# and validated against 200 test vectors produced by that code.

mutable struct SplitMix64
    x::UInt64
end

@inline function next(sm::SplitMix64) :: UInt64
    sm.x += 0x9e3779b97f4a7c15
    z = sm.x
    z = (xor(z, z >> 30)) * 0xbf58476d1ce4e5b9
    z = (xor(z, z >> 27)) * 0x94d049bb133111eb

    xor(z, z >> 31)
end

# Xoshiro256++ is based on the description in http://prng.di.unimi.it/xoshiro256plusplus.c
# and validated against 200 test vectors produced by that code.

mutable struct Xoshiro256pp
    s0::UInt64
    s1::UInt64
    s2::UInt64
    s3::UInt64
end

@inline function rotl(x::UInt64, k::Int) :: UInt64
    (x << k) | (x >> (64 - k))
end

@inline function next(r::Xoshiro256pp) :: UInt64
    result = rotl(r.s0 + r.s3, 23) + r.s0

    t = r.s1 << 17
    r.s2 = xor(r.s2, r.s0)
    r.s3 = xor(r.s3, r.s1)
    r.s1 = xor(r.s1, r.s2)
    r.s0 = xor(r.s0, r.s3)

    r.s2 = xor(r.s2, t)
    r.s3 = rotl(r.s3, 45)

    result
end

# A wrapper around Xoshiro256pp to generate Float32s in the range
# 0.0 <= r < 1.0

struct UniformRNG
    x::Xoshiro256pp
end

@inline function next(r::UniformRNG) :: Float32
    uniform32(next(r.x))
end

# Factory function to create a UniformRNG from an index, which is
# normally the CUDA thread index.
@inline function uniformfromindex(index) :: UniformRNG
    seedgen = SplitMix64(index)
    s0 = next(seedgen)
    s1 = next(seedgen)
    s2 = next(seedgen)
    s3 = next(seedgen)
    UniformRNG(Xoshiro256pp(s0, s1, s2, s3))
end

end


text:
# module for drawing object

using Plots
pyplot()

mutable struct Object
    pose
    id
    shape
    color
    size

    # init
    function Object(x::Float64, y::Float64; shape=:star,
                    color=:orange, size=15, id=-1)
        self = new()
        self.pose = [x, y]
        self.id = id
        self.shape = shape
        self.color = color
        self.size = size
        return self
    end
end

function draw!(self::Object)
    scatter!([self.pose[1]], [self.pose[2]], markershape=self.shape,
             markercolor=self.color, markersize=self.size)
    if self.id !== -1
        annotate!(self.pose[1], self.pose[2],
                  text("id:$(self.id)", :black, :left, 10))
    end
end

max_stars_repo_name: ShisatoYano/JuliaAutonomy

max_issues_repo_name: ShisatoYano/JuliaAutonomy

max_forks_repo_name: ShisatoYano/JuliaAutonomy