text:
__precompile__()

module RemoteFiles

using HTTP: URI

import Base: rm, isfile, getindex, download, rm

export DownloadError, RemoteFile, @RemoteFile, path, rm, isfile,
    RemoteFileSet, @RemoteFileSet, files, paths, download, load

include("backends.jl")

const BACKENDS = AbstractBackend[Http()]

_iscurl(curl) = occursin("libcurl", read(`$curl --version`, String))

function __init__()
    Sys.which("wget") !== nothing && pushfirst!(BACKENDS, Wget())
    curl = Sys.which("curl")
    curl !== nothing && _iscurl(curl) && pushfirst!(BACKENDS, CURL())
end

struct DownloadError <: Exception
    msg::String
end

Base.show(io::IO, ex::DownloadError) = print(io, ex.msg)

struct RemoteFile
    uri::URI
    file::String
    dir::String
    updates::Symbol
    retries::Int
    try_backends::Bool
    wait::Int
    failed::Symbol
end

function getdir(src)
    file = string(src.file)
    file = startswith(file, "REPL") ? "." : file
    file = abspath(dirname(file), "..", "data")
    :($file)
end

function RemoteFile(uri::URI;
    file::String="",
    dir::String=".",
    updates::Symbol=:never,
    retries::Int=3,
    try_backends::Bool=true,
    wait::Int=5,
    failed::Symbol=:error,
)
    isempty(uri.scheme) && throw(ArgumentError("File URI '$uri' does not seem to be valid."))

    if isempty(file)
        file = filename(uri)
        if isempty(file)
            error("File name could not be extracted from URI '$uri'. "
                * "Try setting it manually.")
        end
    end

    RemoteFile(uri, file, abspath(dir), updates, retries, try_backends, wait, failed)
end
RemoteFile(uri::String; kwargs...) = RemoteFile(URI(uri); kwargs...)

filename(uri::URI) = split(split(uri.path, ';')[1], '/')[end]

macro RemoteFile(uri, args...)
    dir = getdir(__source__)
    kw = Expr[]
    found_dir = false
    for arg in args
        if isa(arg, Expr) && arg.head in (:(=), :kw)
            push!(kw, Expr(:kw, arg.args[1], Expr(:escape, arg.args[end])))
            if arg.args[1] == :dir
                found_dir = true
            end
        end
    end
    if !found_dir
        push!(kw, Expr(:kw, :dir, Expr(:escape, dir)))
    end
    :(RemoteFile($(esc(uri)); $(kw...)))
end

"""
    @RemoteFile name url [key=value...]

Assign the `RemoteFile` located at `url` to the variable `name`.

The following keyword arguments are available:
- `file`: Set a different local file name.
- `dir`: The download directory. If `dir` is not set RemoteFiles will create
    a new directory `data` under the root of the current package and save the
    file there.
- `updates` (default: `:never`): Indicates with which frequency the
    remote file is updated. Possible values are:
    - `:never`
    - `:daily`
    - `:monthly`
    - `:yearly`
    - `:mondays`/`:weekly`, `:tuesdays`, etc.
- `retries` (default: 3): How many retries should be attempted.
- `try_backends` (default: `true`): Whether to retry with different backends.
- `wait` (default: 5): How many seconds to wait between retries.
- `failed` (default: `:error`): What to do if the download fails. Either throw
    an exception (`:error`) or display a warning (`:warn`).
"""
macro RemoteFile(name::Symbol, uri, args...)
    dir = getdir(__source__)
    kw = Expr[]
    found_dir = false
    for arg in args
        if isa(arg, Expr) && arg.head in (:(=), :kw)
            push!(kw, Expr(:kw, arg.args[1], Expr(:escape, arg.args[end])))
            if arg.args[1] == :dir
                found_dir = true
            end
        end
    end
    if !found_dir
        push!(kw, Expr(:kw, :dir, Expr(:escape, dir)))
    end
    :($(esc(name)) = RemoteFile($(esc(uri)); $(kw...)))
end

"""
    path(rf::RemoteFile)

Get the local path of `rf`.
"""
path(rf::RemoteFile) = joinpath(rf.dir, rf.file)

"""
    rm(rf::RemoteFile; force=false)

Remove the downloaded file `rf`.
"""
rm(rf::RemoteFile; force=false) = rm(path(rf), force=force)

"""
    isfile(rf::RemoteFile)

Check whether `rf` has been downloaded.
"""
isfile(rf::RemoteFile) = isfile(path(rf))

struct RemoteFileSet
    name::String
    files::Dict{Symbol,RemoteFile}
end

function RemoteFileSet(name; kwargs...)
    files = Dict{Symbol,RemoteFile}()
    for (k,v) in kwargs
        if isa(v, RemoteFile)
            merge!(files, Dict(k=>v))
        end
    end
    RemoteFileSet(name, files)
end

"""
    @RemoteFileSet name description begin
        file1 = @RemoteFile ...
        file2 = @RemoteFile ...
        ...
    end

Collect several `RemoteFile`s in the `RemoteFileSet` saved under `name` with a
`description`.
"""
macro RemoteFileSet(name, description::String, ex)
    if !isa(ex, Expr) && ex.head == :block
        error("@RemoteFileSet must be used on a code block.")
    end
    kw = Expr[]
    for arg in ex.args
        if isa(arg, Expr) && arg.head in (:(=), :kw)
            lhs = arg.args[1]
            rhs = arg.args[2]
            if (isa(rhs, Expr) && rhs.head == :macrocall && rhs.args[1] ==
                Symbol("@RemoteFile"))
                push!(kw, Expr(:kw, lhs, Expr(:escape, rhs)))
            end
        end
    end
    return :($(esc(name)) = RemoteFileSet($description, $(kw...)))
end

"""
    getindex(rfs::RemoteFileSet, key)

Get the `RemoteFile` identified by `key` from `rfs`.
"""
getindex(rfs::RemoteFileSet, key::Symbol) = rfs.files[key]
getindex(rfs::RemoteFileSet, key::String) = rfs.files[Symbol(key)]

"""
    files(rfs::RemoteFileSet)

Get the (unsorted) list of file identifiers from a `RemoteFileSet`.
"""
files(rfs::RemoteFileSet) = collect(values(rfs.files))

"""
    isfile(rfs::RemoteFileSet, file)

Check whether a specific `file` contained in `rfs` has been downloaded.
"""
isfile(rfs::RemoteFileSet, file) = isfile(rfs[file])

"""
    isfile(rfs::RemoteFileSet)

Check whether all files contained in `rfs` have been downloaded.
"""
isfile(rfs::RemoteFileSet) = all(isfile.(files(rfs)))

"""
    rm(rfs::RemoteFileSet, file; force=false)

Remove a specific downloaded `file` contained in `rfs`.
"""
rm(rfs::RemoteFileSet, file; force=false) = rm(rfs[file], force=force)

"""
    rm(rfs::RemoteFileSet; force=false)

Remove all downloaded files contained in `rfs`.
"""
rm(rfs::RemoteFileSet; force=false) = foreach(x->rm(x, force=force), files(rfs))

"""
    path(rfs::RemoteFileSet, file)

Get the path to a specific downloaded `file` contained in `rfs`.
"""
path(rfs::RemoteFileSet, file) = path(rfs[file])

"""
    paths(rfs::RemoteFileSet, files...)

Get the paths to specific downloaded `files` contained in `rfs`.
"""
paths(rfs::RemoteFileSet, files...) = map(x->path(rfs[x]), files)

include("updates.jl")
include("download.jl")

"""
    download(rfs::RemoteFileSet;
        quiet::Bool=false, verbose::Bool=false, force::Bool=false)

Download all files contained in `rfs`.

- `quiet`: Do not print messages.
- `verbose`: Print all messages.
- `force`: Force download and overwrite existing files.
"""
function download(rfs::RemoteFileSet; quiet::Bool=false, verbose::Bool=false, force::Bool=false)
    verbose && @info "Downloading file set '$(rfs.name)'."
    @sync for file in values(rfs.files)
        @async download(file, quiet=verbose, verbose=verbose, force=force)
    end
end

import FileIO: load

"""
    load(rf::RemoteFile)

Load the contents of a remote file, downloading the file if
it has not been done previously, reading the file from disk
and trying to infer the format from filename and/or magic
bytes in the file via [FileIO.jl](https://github.com/JuliaIO/FileIO.jl).
"""
function load(rf::RemoteFile)
    if !isfile(rf)
        download(rf)
    end
    load(path(rf))
end

end # module


text:
import Unicode

mouthsize(animal) = Unicode.normalize(animal, casefold=true) == "alligator" ? "small" : "wide"

ext: jl

max_stars_repo_name: UlrichBerntien/Codewars-Katas

max_issues_repo_name: UlrichBerntien/Codewars-Katas

max_forks_repo_name: UlrichBerntien/Codewars-Katas


text:
"""
$TYPEDEF

This is but one incarnation for how radar alignment factor could work, treat it as a starting point.

Example
-------
```julia
using LinearAlgebra
arp2 = AlignRadarPose2(sweep[10], sweep[11], MvNormal(zeros(3), diagm([5;5;pi/4])))
```

"""

using TensorCast

import IncrementalInference: getSample
import Base: convert

struct AlignRadarPose2{T <: Real, P <: SamplableBelief} <: FunctorPairwise
  im1::Matrix{T}
  im2::Matrix{T}
  PreSampler::P
  p2p2::Pose2Pose2
end

AlignRadarPose2(im1::Matrix{T}, im2::Matrix{T}, pres::P) where {T <: Real, P <: SamplableBelief} = AlignRadarPose2{T,P}(im1, im2, pres, Pose2Pose2(pres))

function getSample(rp2::AlignRadarPose2, N::Int=1)

  # closure on inner function
  cost(x::AbstractVector) = evaluateTransform(rp2.im1,rp2.im2,x...)

  pres = rand(rp2.PreSampler, N)
  out = zeros(3, N)
  TASKS = Vector{Task}(undef, N)
  for i in 1:N
    # ignoring failures
      TASKS[i] = Threads.@spawn optimize(cost, pres[:, $i], NelderMead()).minimizer
    # out[:,i] = optimize(cost, pres[:,i], NelderMead()).minimizer
  end
    # retrieve threaded results
    @sync for i in 1:N
      @async out[:,$i] .= fetch(TASKS[$i])
    end

  # only using out, but return pres if user wants to look at it.
  return (out, pres)
end

function (rp2::AlignRadarPose2)(res::Vector{Float64},
                           userdata::FactorMetadata,
                           idx::Int,
                           meas::Tuple,
                           wXi::Array{Float64,2},
                           wXj::Array{Float64,2})
  #
  rp2.p2p2(res, userdata, idx, meas, wXi, wXj)
  res
end

struct PackedAlignRadarPose2 <: PackedInferenceType
  im1::Vector{Vector{Float64}}
  im2::Vector{Vector{Float64}}
  PreSampler::String
  p2p2::PackedPose2Pose2
end

function convert(::Type{PackedAlignRadarPose2}, arp2::AlignRadarPose2)
  TensorCast.@cast pim1[row][col] := arp2.im1[row,col]
  TensorCast.@cast pim1[row] := collect(pim1[row])
  TensorCast.@cast pim2[row][col] := arp2.im2[row,col]
  TensorCast.@cast pim2[row] := collect(pim2[row])
  PackedAlignRadarPose2(
    pim1,
    pim2,
    string(arp2.PreSampler),
    convert(PackedPose2Pose2, arp2.p2p2))
end

function convert(::Type{AlignRadarPose2}, parp2::PackedAlignRadarPose2)
  TensorCast.@cast im1[row,col] := parp2.im1[row][col]
  TensorCast.@cast im2[row,col] := parp2.im2[row][col]
  AlignRadarPose2(
    collect(im1),
    collect(im2),
    extractdistribution(parp2.PreSampler),
    convert(Pose2Pose2, parp2.p2p2))
end


text:
using Test

include("util.jl")
include("original.jl")
include("continuous.jl")
include("test_continuous.jl")
include("metadata.jl")


text:
using SparseArrays

"""
    σ⁰

The 2×2 unit matrix.

# Examples
```julia-repl
julia> σ⁰
2×2 SparseMatrixCSC{Complex{Float64},Int64} with 2 stored entries:
 [1, 1]  =  1.0+0.0im
 [2, 2]  =  1.0+0.0im
```
"""
const σ⁰ = sparse([1.0+0.0im 0.0; 0.0 1.0+0.0im])

"""
    σˣ

``x``-component of the Pauli matrix, ``\\sigma^x``.

# Examples
```julia-repl
julia> σˣ
2×2 SparseMatrixCSC{Complex{Float64},Int64} with 2 stored entries:
  [2, 1]  =  1.0+0.0im
  [1, 2]  =  1.0+0.0im
```
"""
const σˣ = sparse([0.0 1.0+0.0im; 1.0+0.0im 0.0])

"""
    σʸ

``y``-component of the Pauli matrix, ``\\sigma^y``.

# Examples
```julia-repl
julia> σʸ
2×2 SparseMatrixCSC{Complex{Float64},Int64} with 2 stored entries:
  [2, 1]  =  0.0+1.0im
  [1, 2]  =  -0.0-1.0im
```
"""
const σʸ = sparse([0.0 -1.0im; 1.0im 0.0])

"""
    σᶻ

``z``-component of the Pauli matrix, ``\\sigma^z``.

# Examples
```julia-repl
julia> σᶻ
2×2 SparseMatrixCSC{Complex{Float64},Int64} with 2 stored entries:
  [1, 1]  =  1.0+0.0im
  [2, 2]  =  -1.0+0.0im
```
"""
const σᶻ = sparse([1.0+0.0im 0.0; 0.0 -1.0+0.0im])


text:
module Articles

export Article, save, find

using ...Database, MySQL, JSON

struct Article
  content::String
  links::Vector{String}
  title::String
  image::String
  url::String

  Article(; content = "", links = String[], title = "", image = "", url = "") = new(content, links, title, image, url)
  Article(content, links, title, image, url) = new(content, links, title, image, url)
end

function find(url) :: Vector{Article}
  articles = Article[]

  result = MySQL.query(CONN, "SELECT * FROM `articles` WHERE url = '$url'")

  isempty(result.url) && return articles

  for i in eachindex(result.url)
    push!(articles, Article(result.content[i],
                            JSON.parse(result.links[i]),
                            result.title[i],
                            result.image[i],
                            result.url[i]))
  end

  articles
end

function save(a::Article)
  sql = "INSERT IGNORE INTO articles
            (title, content, links, image, url) VALUES (?, ?, ?, ?, ?)"
  stmt = MySQL.Stmt(CONN, sql)
  result = MySQL.execute!(stmt,
                          [ a.title,
                            a.content,
                            JSON.json(a.links),
                            a.image,
                            a.url]
                        )
end

function createtable()
  sql = """
    CREATE TABLE `articles` (
      `title` varchar(1000),
      `content` text,
      `links` text,
      `image` varchar(500),
      `url` varchar(500),
      UNIQUE KEY `url` (`url`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
  """

  MySQL.execute!(CONN, sql)
end

end

max_stars_repo_name: PacktPublishing/Julia-Projects

max_issues_repo_name: PacktPublishing/Julia-Projects

max_forks_repo_name: PacktPublishing/Julia-Projects


text:
using DataFrames, JLD2

# Here we define the parameters we want to try (define the grid)
# We will try every possible combination of these parameters
depths = collect(2:2:20)
maxfeatures = collect(2:2:10)
numestimators = [20, 40, 80, 160]

"""
	This function is going to create a DataFrame,
	where each row corresponds to the parameters for one experiment
"""
function getparameters(depths, maxfeatures, numestimators)
	df = DataFrame(experiment_id = [], max_depth = [],
	               max_features = [], n_estimators = [])
	experiment_id = 0
	# loop through all combinations
	for depth in depths, mf in maxfeatures, nest in numestimators
		experiment_id += 1
		# append a new row to the dataframe
		df = [df;
			  DataFrame(experiment_id = [experiment_id],
			            max_depth = [depth],
	           			max_features = [mf],
	           			n_estimators = [nest])]
	end
	return df
end

# Let's get these parameters into the right format
params = getparameters(depths, maxfeatures, numestimators)
# and now let's save them to a JLD file
@save "params.jld2" params

# Let's make a folder to save the results (if necessary)
try mkdir("results") catch e end
try mkdir("logs") catch e end


text:
"Holds the tableau of an Specialised Partitioned Additive Runge-Kutta method for Variational systems."
struct AbstractTableauSPARK{IT,DT} <: AbstractTableau{DT}
    name::Symbol
    o::Int
    s::Int
    r::Int
    ρ::Int

    q::CoefficientsARK{DT}
    p::CoefficientsARK{DT}

    q̃::CoefficientsPRK{DT}
    p̃::CoefficientsPRK{DT}

    λ::CoefficientsMRK{DT}

    ω::Matrix{DT}
    δ::Matrix{DT}
    d::Vector{DT}

    function AbstractTableauSPARK{IT,DT}(name, o, s, r, ρ, q, p, q̃, p̃, λ, ω, δ, d) where {IT,DT}
        @assert isa(name, Symbol)
        @assert isa(s, Integer)
        @assert isa(r, Integer)
        @assert isa(ρ, Integer)
        @assert isa(o, Integer)

        @assert s > 0 "Number of stages s must be > 0"
        @assert r > 0 "Number of stages r must be > 0"
        @assert ρ > 0 && ρ ≤ r

        @assert s==q.s==p.s==q̃.s==p̃.s==length(d)
        @assert r==q.r==p.r==q̃.r==p̃.r==λ.r
        @assert size(ω, 1)==r-ρ
        @assert size(δ, 1)==ρ

        new(name, o, s, r, ρ, q, p, q̃, p̃, λ, ω, δ, d)
    end

    function AbstractTableauSPARK{IT,DT}(name, o, s, r, ρ, q, p, q̃, p̃, λ, ω, δ) where {IT,DT}
        @assert isa(name, Symbol)
        @assert isa(s, Integer)
        @assert isa(r, Integer)
        @assert isa(ρ, Integer)
        @assert isa(o, Integer)

        @assert s > 0 "Number of stages s must be > 0"
        @assert r > 0 "Number of stages r must be > 0"
        @assert ρ ≥ 0 && ρ ≤ r

        @assert s==q.s==p.s==q̃.s==p̃.s
        @assert r==q.r==p.r==q̃.r==p̃.r==λ.r
        @assert size(ω, 1)==r-ρ
        @assert size(δ, 1)==ρ

        new(name, o, s, r, ρ, q, p, q̃, p̃, λ, ω, δ)
    end
end

function AbstractTableauSPARK{IT}(name::Symbol, order::Int,
                         a_q::Matrix{DT}, a_p::Matrix{DT},
                         α_q::Matrix{DT}, α_p::Matrix{DT},
                         a_q̃::Matrix{DT}, a_p̃::Matrix{DT},
                         α_q̃::Matrix{DT}, α_p̃::Matrix{DT},
                         b_q::Vector{DT}, b_p::Vector{DT},
                         β_q::Vector{DT}, β_p::Vector{DT},
                         c_q::Vector{DT}, c_p::Vector{DT},
                         c_λ::Vector{DT}, d_λ::Union{Vector{DT},Matrix{DT}},
                         ω_λ::Matrix{DT}, δ_λ::Matrix{DT}, d::Vector{DT}) where {IT, DT <: Real}

    s = length(c_q)
    r = length(c_λ)
    ρ = size(δ_λ, 1)

    @assert s > 0 "Number of stages s must be > 0"
    @assert r > 0 "Number of stages r must be > 0"

    @assert s==size(a_q,1)==size(a_q,2)==length(b_q)==length(c_q)
    @assert s==size(a_p,1)==size(a_p,2)==length(b_p)==length(c_p)
    @assert s==size(α_q,1)==size(α_p,1)
    @assert r==size(α_q,2)==size(α_p,2)
    @assert s==length(d)
    @assert r==length(c_λ)==length(d_λ)
    @assert r==size(a_q̃,1)==size(a_p̃,1)
    @assert s==size(a_q̃,2)==size(a_p̃,2)
    @assert r==size(α_q̃,1)==size(α_q̃,2)==length(β_q)
    @assert r==size(α_p̃,1)==size(α_p̃,2)==length(β_p)

    q = CoefficientsARK{DT}(name, order, s, r, a_q, b_q, c_q, α_q, β_q)
    p = CoefficientsARK{DT}(name, order, s, r, a_p, b_p, c_p, α_p, β_p)
    q̃ = CoefficientsPRK{DT}(name, order, s, r, a_q̃, c_λ, α_q̃)
    p̃ = CoefficientsPRK{DT}(name, order, s, r, a_p̃, c_λ, α_p̃)
    λ = CoefficientsMRK{DT}(name, r, d_λ, c_λ)

    AbstractTableauSPARK{IT,DT}(name, order, s, r, ρ, q, p, q̃, p̃, λ, ω_λ, δ_λ, d)
end

function AbstractTableauSPARK{IT}(name::Symbol, order::Int,
                         a_q::Matrix{DT}, a_p::Matrix{DT},
                         α_q::Matrix{DT}, α_p::Matrix{DT},
                         a_q̃::Matrix{DT}, a_p̃::Matrix{DT},
                         α_q̃::Matrix{DT}, α_p̃::Matrix{DT},
                         b_q::Vector{DT}, b_p::Vector{DT},
                         β_q::Vector{DT}, β_p::Vector{DT},
                         c_q::Vector{DT}, c_p::Vector{DT},
                         c_λ::Vector{DT}, d_λ::Union{Vector{DT},Matrix{DT}},
                         ω_λ::Matrix{DT}, δ_λ::Matrix{DT}) where {IT, DT <: Real}

    s = length(c_q)
    r = length(c_λ)
    ρ = size(δ_λ, 1)

    @assert s > 0 "Number of stages s must be > 0"
    @assert r > 0 "Number of stages r must be > 0"

    @assert s==size(a_q,1)==size(a_q,2)==length(b_q)==length(c_q)
    @assert s==size(a_p,1)==size(a_p,2)==length(b_p)==length(c_p)
    @assert s==size(α_q,1)==size(α_p,1)
    @assert r==size(α_q,2)==size(α_p,2)
    @assert r==length(c_λ)==length(d_λ)
    @assert r==size(a_q̃,1)==size(a_p̃,1)
    @assert s==size(a_q̃,2)==size(a_p̃,2)
    @assert r==size(α_q̃,1)==size(α_q̃,2)==length(β_q)
    @assert r==size(α_p̃,1)==size(α_p̃,2)==length(β_p)

    q = CoefficientsARK{DT}(name, order, s, r, a_q, b_q, c_q, α_q, β_q)
    p = CoefficientsARK{DT}(name, order, s, r, a_p, b_p, c_p, α_p, β_p)
    q̃ = CoefficientsPRK{DT}(name, order, s, r, a_q̃, c_λ, α_q̃)
    p̃ = CoefficientsPRK{DT}(name, order, s, r, a_p̃, c_λ, α_p̃)
    λ = CoefficientsMRK{DT}(name, r, d_λ, c_λ)

    AbstractTableauSPARK{IT,DT}(name, order, s, r, ρ, q, p, q̃, p̃, λ, ω_λ, δ_λ)
end

# TODO function readAbstractTableauSPARKFromFile(dir::AbstractString, name::AbstractString)

"Holds the tableau of an Specialised Partitioned Additive Runge-Kutta method."
const TableauSPARK{DT} = AbstractTableauSPARK{:spark,DT}


text:
using Distributions

@testset "less_than_lower_bound" begin
    nworkers = 9
    nsubpartitions = 160.0
    θs = fill(1/nworkers, nworkers)
    ps = fill(nsubpartitions, nworkers)

    # values recorded on eX3 with low variance and very low comm. latency relative to comp.
    comp_mcs = [255.07814185599995, 235.33940168554452, 253.72451957702958, 116.82766857029705, 116.75048824871284, 116.63288112475249, 126.99890071128709, 126.4382596942574, 117.12455760475244]
    comp_vcs = [0.0027557071631392205, 0.003592251480945663, 0.002281988669487589, 0.0007248118462346298, 0.0005408877863892769, 0.0005133790987450482, 0.0005865578758950107, 0.0006378358097673953, 0.0005586345559702721]
    comm_mcs = [3.373097029702779e-5, 3.189267326732839e-5, 3.427457425742762e-5, 3.50826633663372e-5, 3.664775247524789e-5, 3.760737623762412e-5, 3.5680287128712425e-5, 3.737996039603971e-5, 3.6443900990098125e-5]
    comm_vcs = [1.4755830783262175e-12, 1.5582646160146614e-12, 1.3494372741908877e-12, 2.0233815302431064e-12, 2.7092806020993726e-12, 2.554836195077552e-12, 1.7668490363708934e-12, 1.5867281370452314e-12, 1.8507092575245513e-12]

    dzs = CodedComputing.distribution_from_mean_variance.(Gamma, comp_mcs .* θs ./ ps, comp_vcs .* θs ./ ps)
    dys = CodedComputing.distribution_from_mean_variance.(Gamma, comm_mcs, comm_vcs)

    correct = [-6787.780734619605, -5997.6993965555075, -7030.083983125667, -4542.376367667996, -4266.766708613465, -4204.885092182273, -4709.103013914913, -4746.332511515265, -4315.852500222745]
    @test CodedComputing.fastest_lower_bound(dzs, dys) ≈ correct
end

@testset "optimizer (comp. higher than comm.)" begin
    nworkers = 10
    nslow = 3
    nwait = nworkers - nslow
    nsubpartitions = 160.0
    θs = fill(1/nworkers, nworkers)
    ps = fill(nsubpartitions, nworkers)

    # per-worker compute latency
    comp_ms = fill(1.0, nworkers)
    comp_ms[1:nslow] .*= 2
    comp_vs = comp_ms ./ 100
    comp_mcs = comp_ms ./ (θs ./ ps)
    comp_vcs = comp_vs ./ (θs ./ ps).^2

    # per-worker communication latency
    comm_mcs = fill(1e-2, nworkers)
    comm_vcs = comm_mcs ./ 100

    sim_nwait = floor(Int, nworkers/2)
    comp_distributions = [Gamma() for _ in 1:nworkers]
    comm_distributions = [Gamma() for _ in 1:nworkers]
    sim = EventDrivenSimulator(;nwait=sim_nwait, nworkers, comm_distributions, comp_distributions)
    min_processed_fraction = sim_nwait / nworkers / nsubpartitions

    # balanced mode
    ps, latency0, contrib0, loss0, latency, contrib, loss = CodedComputing.optimize!(ps, ps, sim; θs, comp_mcs, comp_vcs, comm_mcs, comm_vcs)
    println("ps: $ps")
    @test loss < Inf

    # check that the slow workers have about twice as many partitions
    slows = ps[1:nslow]
    slows_mean = mean(slows)
    fasts = ps[nslow+1:end]
    fasts_mean = mean(fasts)
    @test 2 / mean(slows) ≈ 1 / mean(fasts) rtol=0.1

    # check that all slow and all fast workers were given approx. the same number of partitions as each other
    for v in slows
        @test v ≈ slows_mean rtol=0.1
    end
    for v in fasts
        @test v ≈ fasts_mean rtol=0.1
    end

    # check that the avg. latency is uniform (within some margin)
    ms = comp_mcs .* θs ./ ps .+ comm_mcs
    println("ms: $ms")
    μ = mean(ms)
    for i in 1:nworkers
        @test ms[i] ≈ μ rtol=0.1
    end
end

@testset "optimizer (comp. much higher than comm.)" begin
    nworkers = 9
    nwait = nworkers
    nsubpartitions = 160.0
    θs = fill(1/nworkers, nworkers)
    ps = fill(nsubpartitions, nworkers)

    # values recorded on eX3 with low variance and very low comm. latency relative to comp.
    comp_mcs = [255.07814185599995, 235.33940168554452, 253.72451957702958, 116.82766857029705, 116.75048824871284, 116.63288112475249, 126.99890071128709, 126.4382596942574, 117.12455760475244]
    comp_vcs = [0.0027557071631392205, 0.003592251480945663, 0.002281988669487589, 0.0007248118462346298, 0.0005408877863892769, 0.0005133790987450482, 0.0005865578758950107, 0.0006378358097673953, 0.0005586345559702721]
    comm_mcs = [3.373097029702779e-5, 3.189267326732839e-5, 3.427457425742762e-5, 3.50826633663372e-5, 3.664775247524789e-5, 3.760737623762412e-5, 3.5680287128712425e-5, 3.737996039603971e-5, 3.6443900990098125e-5]
    comm_vcs = [1.4755830783262175e-12, 1.5582646160146614e-12, 1.3494372741908877e-12, 2.0233815302431064e-12, 2.7092806020993726e-12, 2.554836195077552e-12, 1.7668490363708934e-12, 1.5867281370452314e-12, 1.8507092575245513e-12]

    sim_nwait = floor(Int, nworkers/2)
    comp_distributions = [Gamma() for _ in 1:nworkers]
    comm_distributions = [Gamma() for _ in 1:nworkers]
    sim = EventDrivenSimulator(;nwait=sim_nwait, nworkers, comm_distributions, comp_distributions)
    min_processed_fraction = sim_nwait / nworkers / nsubpartitions

    # balanced mode
    ps, loss, loss0 = CodedComputing.optimize!(ps, ps, sim; θs, comp_mcs, comp_vcs, comm_mcs, comm_vcs)
    println("ps: $ps")
    @test loss < Inf

    # check that the avg. latency is uniform (within some margin)
    ms = comp_mcs .* θs ./ ps .+ comm_mcs
    println("ms: $ms")
    μ = mean(ms)
    for i in 1:nworkers
        @test ms[i] ≈ μ rtol=0.1
    end
end

@testset "optimizer (comp. same as comm.)" begin
    nworkers = 9
    nwait = nworkers
    nsubpartitions = 160.0
    θs = fill(1/nworkers, nworkers)
    ps = fill(nsubpartitions, nworkers)

    # values recorded on eX3 with low variance and very low comm. latency relative to comp.
    comp_mcs = [255.07814185599995, 235.33940168554452, 253.72451957702958, 116.82766857029705, 116.75048824871284, 116.63288112475249, 126.99890071128709, 126.4382596942574, 117.12455760475244]
    comp_vcs = [0.0027557071631392205, 0.003592251480945663, 0.002281988669487589, 0.0007248118462346298, 0.0005408877863892769, 0.0005133790987450482, 0.0005865578758950107, 0.0006378358097673953, 0.0005586345559702721]
    comm_mcs = comp_mcs .* θs ./ nsubpartitions
    comm_vcs = comp_vcs .* θs ./ nsubpartitions

    sim_nwait = floor(Int, nworkers/2)
    comp_distributions = [Gamma() for _ in 1:nworkers]
    comm_distributions = [Gamma() for _ in 1:nworkers]
    sim = EventDrivenSimulator(;nwait=sim_nwait, nworkers, comm_distributions, comp_distributions)
    min_processed_fraction = sim_nwait / nworkers / nsubpartitions

    # balanced mode
    ps, loss, loss0 = CodedComputing.optimize!(ps, ps, sim; θs, comp_mcs, comp_vcs, comm_mcs, comm_vcs)
    println("ps: $ps")
    @test loss < Inf

    # check that the avg. latency is uniform (within some margin)
    ms = comp_mcs ./ ps .+ comm_mcs
    println("ms: $ms")
    μ = mean(ms)
    for i in 1:nworkers
        @test ms[i] ≈ μ rtol=0.5
    end
end

@testset "optimizer (comp. much higher than comm.)" begin
    nworkers = 72
    nwait = nworkers
    nsubpartitions = 80.0
    θs = fill(1/nworkers, nworkers)
    ps = fill(nsubpartitions, nworkers)

    # values recorded on AWS with low variance and low comm. latency relative to comp.
    comp_mcs = [83.83719400727274, 84.56425873454548, 83.24744768000001, 85.09492904727274, 86.62222161454545, 86.56492212363639, 84.18081268363638, 83.2964639418182, 83.63603345454547, 85.52723904, 85.89885661090909, 78.39971525818183, 93.71899182545458, 85.06894481454546, 85.09361448727273, 86.73630545454546, 85.32156596363637, 84.40723630545455, 84.44267933090909, 82.6533564509091, 84.94617053090911, 84.90497064727273, 84.32782423272727, 84.80634338909091, 84.74789800727272, 90.32809192727272, 84.78158516363638, 79.42350749090909, 86.52342138181817, 84.51160738909093, 84.64746606545455, 84.11714967272728, 84.18197172363638, 84.91479365818182, 83.04630289454546, 86.9430754327273, 84.56391953454548, 82.88443828363637, 86.16268706909094, 84.96690315636366, 85.49810461090908, 84.27044596363636, 84.09113727999998, 84.44407127272729, 85.21930240000002, 84.55733469090909, 85.48306798545454, 85.43646283636365, 84.59088482909092, 89.27814429090911, 85.69318813090909, 82.89300008727272, 84.66070068363636, 84.22216052363638, 84.26186385454547, 84.2088694109091, 87.36550842181819, 84.30621387636366, 83.68611566545457, 84.92868846545456, 83.99821399272729, 84.27077440000001, 91.8733388218182, 84.28995083636363, 85.13140084363637, 86.28002333090912, 85.47884549818181, 85.11117451636365, 83.85590574545455, 84.5384607418182, 83.28374976, 84.23413847272728]
    # comp_vcs = [0.0011421443791165577, 0.001965937010903701, 0.001080289134005863, 0.0015147010681869218, 0.0019543853740587075, 0.0018525280119243218, 0.0010717424262526945, 0.0013552023930692842, 0.0013218279306052023, 0.001646853834402909, 0.0011971988786598198, 0.0008171234908152827, 0.0011180002317882714, 0.0014849310589688388, 0.0013503309833066961, 0.002003399670388999, 0.002229045828245602, 0.0016310696849770677, 0.0013699264700789177, 0.001313373340831927, 0.001440510953185439, 0.0015190398374354923, 0.0012164160375029052, 0.0008306335177574833, 0.0011758994786901626, 0.0010003010861745945, 0.0013473881742654802, 0.0007348181667276463, 0.0023673479141235, 0.0012086931203448797, 0.0008219273744405475, 0.0012246601989724356, 0.0011504895403956735, 0.0013126575204895218, 0.0010350639226623624, 0.001785326509537193, 0.0013303620153629623, 0.0009981376354634575, 0.0017964488424443016, 0.001630187729733738, 0.0017519484032818982, 0.001787923696131851, 0.0014579672492872793, 0.001153181321664806, 0.0013350055705060714, 0.0011140041528969352, 0.0011822385440088466, 0.001246437813973071, 0.0009866541269556797, 0.0007728917443144192, 0.0014659113197203564, 0.0013141219658085656, 0.0013415545268761183, 0.001504927399968425, 0.000906065910986086, 0.0010870860165416388, 0.0012550196169302695, 0.0008419391399846764, 0.0010460085177690004, 0.0015293742748779598, 0.0009529932101843303, 0.0014254519016226395, 0.0008692140107794807, 0.0008258379861804196, 0.0017921203526416393, 0.0013239507762105058, 0.001927217880471291, 0.0016084685805719378, 0.0008582012743286067, 0.0014071052024702247, 0.0012597131371129017, 0.0013191295808503373]
    comp_vcs = [0.0866826637144122, 0.14920412858109539, 0.08198818067974525, 0.11495772839425644, 0.14832742098589616, 0.14059699072666618, 0.08133953116784527, 0.10285263006263339, 0.10031968645294634, 0.12498741816227893, 0.09086100645034999, 0.062015312654495294, 0.0848502517691309, 0.11269834355201601, 0.10248291605625519, 0.15204734452943586, 0.16917268382766218, 0.12378948544754058, 0.1039701089376933, 0.09967802820416433, 0.10932709455566815, 0.11528701782787355, 0.0923194862607835, 0.06304065160779755, 0.08924449564957308, 0.07591751467805004, 0.1022595725533149, 0.055768777750289274, 0.17966907414429495, 0.09173335805917977, 0.06237990178738066, 0.09294517412418948, 0.087316016924415, 0.09962370125990476, 0.07855582846755457, 0.13549675529318053, 0.10096737794685308, 0.07575332031358516, 0.13634088101032704, 0.1237225497508226, 0.13296353513918424, 0.13569386789672233, 0.11065193428027933, 0.0875203087589775, 0.1013197990034806, 0.08454697070497867, 0.08972559688102003, 0.09459797889398767, 0.07488178329563717, 0.05865835912257742, 0.11125484683535113, 0.09973484484511158, 0.10181682984571461, 0.11421595913029042, 0.06876556773483387, 0.0825040277949854, 0.09524929194460005, 0.06389868800627808, 0.07938646483408199, 0.11607134648358688, 0.07232709933259336, 0.10818419289949939, 0.06596870515663941, 0.06267669635080282, 0.13601237173180164, 0.10048079910655364, 0.14626555319259404, 0.12207418222620917, 0.06513289722569732, 0.10679177633467911, 0.09560550508110614, 0.1001148961053672]
    comm_mcs = [0.0003480254545454544, 0.0003319341919191919, 0.00026587455555555564, 0.00034138355555555556, 0.00040316833333333324, 0.00039426245454545454, 0.0003415080000000001, 0.0003219556666666666, 0.0003220089191919191, 0.00038495763636363644, 0.0004099111616161616, 0.0002096090606060607, 0.0002259690404040403, 0.00036263934343434346, 0.00039680437373737374, 0.00037868467676767685, 0.00036656339393939405, 0.0003677447070707071, 0.00035856226262626247, 0.0003042973535353536, 0.0003993650808080807, 0.00041439392929292927, 0.00040552959595959587, 0.00040939215151515157, 0.00041946872727272706, 0.0003035104040404039, 0.00041239234343434355, 0.0002445649797979797, 0.0003739147373737374, 0.00042839323232323243, 0.0004370764949494949, 0.00038970366666666657, 0.0004284080202020202, 0.00043861960606060595, 0.00041204406060606067, 0.00039340965656565655, 0.00044712492929292936, 0.0004082409797979797, 0.00039524609090909083, 0.00043600814141414135, 0.0004214690303030302, 0.00044303437373737376, 0.0004123091818181818, 0.000435883898989899, 0.0004593682323232322, 0.0004801075656565655, 0.00043758155555555554, 0.0004502059090909091, 0.0004367451515151514, 0.00026511119191919186, 0.000407111090909091, 0.00044593664646464643, 0.00044228803030303015, 0.000437117595959596, 0.0004675319797979798, 0.0004789977070707069, 0.00035643654545454537, 0.0004665113030303031, 0.00044163787878787893, 0.00040496073737373753, 0.0004637384646464644, 0.0004160973030303031, 0.00020500094949494935, 0.0004884162121212122, 0.0004058337979797981, 0.0003695217171717172, 0.00039872561616161625, 0.00041293092929292917, 0.0004977244747474749, 0.0004509595252525253, 0.00046671063636363655, 0.00047462048484848474]
    comm_vcs = [5.740965332390451e-8, 4.345452720940765e-8, 2.0897826589721686e-8, 3.9728614195903475e-8, 4.783874768185863e-8, 4.746413291931858e-8, 4.628794348258591e-8, 4.656202443670707e-8, 2.7572550612902546e-8, 4.70896132374031e-8, 4.235644613027693e-8, 1.8075039649862175e-9, 8.830231602806428e-9, 3.322531477545785e-8, 5.105769057712298e-8, 3.608274134141073e-8, 3.91950921956125e-8, 4.6208766182308144e-8, 4.083966421352698e-8, 2.4841435527885144e-8, 4.3822700146215706e-8, 4.882312347214655e-8, 4.320883324624073e-8, 3.7677578237199255e-8, 5.280018543405695e-8, 1.924283053094787e-8, 5.917481436683162e-8, 6.488923716141019e-9, 3.19733472787795e-8, 5.665397354431981e-8, 4.2398035149946876e-8, 3.4169793846282844e-8, 4.8652965888928915e-8, 4.50717038498953e-8, 6.389193203478423e-8, 4.8686624690387e-8, 4.9491465989298095e-8, 5.2208408375938995e-8, 3.4346688861133144e-8, 4.8051166583576e-8, 4.31302555697668e-8, 4.834922571694111e-8, 5.623120069057301e-8, 4.2799384903242254e-8, 5.000090975007734e-8, 5.391810740503352e-8, 4.341524975719643e-8, 5.440975129410279e-8, 4.470642305651242e-8, 1.1782371344862134e-8, 4.785839480238568e-8, 6.184400377152143e-8, 5.0141780705342516e-8, 5.53503587409074e-8, 4.327395670434303e-8, 5.5518941104974865e-8, 3.039298803533887e-8, 4.6083321766938514e-8, 4.0201333080389357e-8, 3.993063539980984e-8, 5.314513615560225e-8, 4.481117759217081e-8, 9.494668103913932e-10, 5.5252223501763073e-8, 4.202337081874707e-8, 3.7601071229576554e-8, 4.208200520001426e-8, 3.801127667739909e-8, 5.5409340272451336e-8, 4.8944886495683677e-8, 5.7064170423605156e-8, 5.956194455121953e-8]

    sim_nwait = floor(Int, nworkers/2)
    comp_distributions = [Gamma() for _ in 1:nworkers]
    comm_distributions = [Gamma() for _ in 1:nworkers]
    sim = EventDrivenSimulator(;nwait=sim_nwait, nworkers, comm_distributions, comp_distributions)
    min_processed_fraction = sim_nwait / nworkers / nsubpartitions

    # balanced mode
    @time ps, loss, loss0 = CodedComputing.optimize!(ps, ps, sim; θs, comp_mcs, comp_vcs, comm_mcs, comm_vcs, simulation_niterations=20, simulation_nsamples=5)
    @test loss < Inf

    # # check that the avg. latency is uniform (within some margin)
    ms = comp_mcs .* θs ./ ps .+ comm_mcs
    println("ms: $(sort(ms))")
    println("loss: $loss")
    μ = mean(ms)
    for i in 1:nworkers
        @test ms[i] ≈ μ rtol=0.1
    end
end

@testset "optimizer (comm. much higher than comp.)" begin
    nworkers = 108
    nwait = nworkers
    nsubpartitions = 10.0
    θs = fill(1/nworkers, nworkers)
    ps = fill(nsubpartitions, nworkers)

    # values recorded on AWS
    comp_mcs = [0.2734740654545455, 0.26846762727272727, 0.2845463563636364, 0.2740031672727273, 0.2634315218181818, 0.26994186000000003, 0.27106060909090907, 0.2798729345454545, 0.28341479454545454, 0.2853871036363636, 0.2836058236363636, 0.27191619818181817, 0.27862846363636357, 0.30009834, 0.28472930181818185, 0.2760987272727273, 0.2632338490909091, 0.25189481454545454, 0.2650328836363636, 0.29026781999999995, 0.2674807527272727, 0.26993704909090904, 0.2930921509090909, 0.3350625218181818, 0.2789818527272727, 0.2763738163636364, 0.2970233345454546, 0.2680460509090909, 0.2933524472727272, 0.2827284218181818, 0.28584191454545455, 0.27539689090909086, 0.29311523999999994, 0.27374743636363635, 0.28170124363636356, 0.2803953436363636, 0.28305309272727275, 0.2625814309090909, 0.29355746727272725, 0.25859809636363634, 0.2967710563636363, 0.29052265090909085, 0.2979647345454545, 0.27210110727272724, 0.2958125890909091, 0.2894656581818182, 0.28769851636363636, 0.2896732309090909, 0.29004532363636365, 0.3498175309090909, 0.2807024072727273, 0.28518376909090914, 0.2940749509090909, 0.29421029454545455, 0.2818771527272727, 0.2717669618181818, 0.2763942381818182, 0.27614320363636363, 0.2938787018181818, 0.2789028490909091, 0.2897578145454545, 0.32740329272727275, 0.2759820218181818, 0.2756452581818182, 0.30284679272727266, 0.2772680072727272, 0.27552166363636366, 0.2752212109090909, 0.2862640636363637, 0.2874734018181818, 0.27256158, 0.2803379236363636, 0.28641766909090904, 0.2764120745454545, 0.28016137636363636, 0.27479968363636365, 0.27114876, 0.28538558181818185, 0.2790738, 0.27606078, 0.2808723763636364, 0.26325044181818186, 0.2535018054545454, 0.27958167818181817, 0.26107350545454544, 0.2843727545454545, 0.2946564981818182, 0.2871746836363636, 0.27641760545454547, 0.26881456909090906, 0.27825800727272726, 0.29775402, 0.27394818545454547, 0.2781129109090909, 0.27541431818181816, 0.2910093872727273, 0.3175030145454545, 0.2909555836363636, 0.30573759272727274, 0.26431314545454543, 0.29641686545454543, 0.26787498545454547, 0.3116245909090909, 0.2762499927272727, 0.27801036, 0.2779663581818182, 0.29150448545454544, 0.27839901272727274]
    # comp_vcs = [1.0501207152382053e-8, 1.8851552341768853e-8, 1.4402058029708699e-8, 2.3405295457157977e-8, 2.638062017378223e-8, 2.4902372702763007e-8, 2.2895896432283862e-8, 1.784581824699485e-8, 5.1467660218713495e-8, 2.6399398816119644e-8, 5.603734942342736e-8, 3.220800094833607e-8, 2.08747421069855e-8, 3.391087406999548e-8, 6.866379759466344e-8, 1.4496487788100729e-8, 1.0207004250459934e-8, 2.311123663241633e-8, 1.0722585204271987e-8, 4.094619002995188e-8, 1.806345581353277e-8, 3.0583010315979884e-8, 5.404078337778353e-8, 2.255504260330213e-6, 1.1681289530782635e-8, 2.0953068092480643e-8, 9.139635637783641e-8, 4.3334552962291314e-8, 1.2556529311539416e-7, 1.4494340522011834e-8, 9.797892689875336e-8, 2.898013115506387e-8, 8.553585403636493e-8, 2.606302126606497e-8, 4.026828181881816e-8, 4.990309972878763e-8, 2.776751270896474e-8, 1.7233319992324375e-8, 4.627219009814402e-8, 2.0714855830688455e-8, 4.8294252016182495e-8, 4.135574965681945e-8, 5.2340241061472653e-8, 1.2315476559927418e-8, 2.2713989373247226e-8, 3.46258074784226e-8, 2.1519559709795013e-8, 3.7736981032339585e-8, 2.3948936451656977e-8, 2.643636162747814e-6, 2.772001242448371e-8, 5.054904862138827e-8, 8.592375029784925e-8, 3.748973939609061e-8, 1.1783276102078502e-7, 1.1741683984719782e-8, 3.587265346834882e-8, 3.0589212477011274e-8, 4.1333690772898035e-8, 4.859142309056536e-8, 2.852687305783053e-8, 1.2182591753089278e-6, 2.6262253038258194e-8, 2.5757089518356545e-8, 1.6054884363176866e-7, 1.1885198813551992e-8, 1.833887321969936e-8, 3.0765772773234056e-8, 4.8639808314317233e-8, 2.790228155923264e-8, 1.9238385651782083e-8, 3.6355284924253746e-8, 2.292884028588869e-8, 1.9345854767826545e-8, 3.7693258467125517e-8, 1.615291010969883e-8, 3.25225015635974e-8, 3.3300739038264284e-8, 2.3483716374500876e-8, 2.3926747077241393e-8, 3.184077673611563e-8, 1.692879352293479e-8, 1.9141847218738875e-8, 1.6970901850149405e-8, 1.5633514228725713e-8, 1.0489299169512704e-7, 4.117796704562282e-8, 3.203645819701878e-8, 3.843566151695522e-8, 1.263061943225605e-8, 6.210906807179459e-8, 3.5814323670081954e-8, 9.158946955985735e-9, 2.1743526090528195e-8, 2.8382942824742188e-8, 1.6981834708920803e-8, 8.2366937592348e-8, 3.1505579448857634e-8, 8.224410199538868e-8, 1.4485209050581053e-8, 3.0554752283265974e-8, 2.5605664163286376e-8, 3.483294538138976e-8, 6.92318465008758e-8, 2.0473269970959344e-8, 3.431216753378621e-8, 3.088815558966655e-8, 2.1358846010759353e-8]
    comp_vcs = [3.4510488230365444e-7, 6.195252276945684e-7, 4.7329992344219177e-7, 7.691764972175169e-7, 8.669556450093831e-7, 8.183754758822515e-7, 7.524359370158356e-7, 5.864734326609827e-7, 1.6913999090280391e-6, 8.675727741698344e-7, 1.841575220520617e-6, 1.058462919093087e-6, 6.860140280459326e-7, 1.1144250403712127e-6, 2.256522649593968e-6, 4.7640320196845647e-7, 3.35436388351681e-7, 7.595127381248493e-7, 3.5238010746905445e-7, 1.3456291153978668e-6, 5.936257329341838e-7, 1.0050602775885229e-6, 1.7759613648757362e-6, 7.412343371591174e-5, 3.838863466055152e-7, 6.885880825916034e-7, 3.00359076371533e-6, 1.4241187306109564e-6, 4.126496608742971e-6, 4.7633263560402524e-7, 3.2199161053558146e-6, 9.523842931852037e-7, 2.810995003871183e-6, 8.565182798496383e-7, 1.3233507782485121e-6, 1.6399832046532155e-6, 9.125335845906825e-7, 5.66344686030049e-7, 1.5206593381152399e-6, 6.80759628836129e-7, 1.5871110736261503e-6, 1.3590886181745926e-6, 1.7200758416776028e-6, 4.0472785909790225e-7, 7.464578610396081e-7, 1.137920149665788e-6, 7.072048968380434e-7, 1.240163745813419e-6, 7.870423633698155e-7, 8.687874961040258e-5, 9.109725659527919e-7, 1.6612112514215864e-6, 2.8237425758143965e-6, 1.2320385565337361e-6, 3.872379673451966e-6, 3.8587111089169017e-7, 1.178895690130835e-6, 1.0052641013986531e-6, 1.358363689275564e-6, 1.5968771116788027e-6, 9.374887121316095e-7, 4.003608187226043e-5, 8.630657039977559e-7, 8.464643366930253e-7, 5.27617339430936e-6, 3.905874894369638e-7, 6.026768724994041e-7, 1.011066464818714e-6, 1.5984672123887327e-6, 9.169625409511281e-7, 6.322378674878864e-7, 1.1947565782524764e-6, 7.535185825208662e-7, 6.35769663033448e-7, 1.2387268756990348e-6, 5.308387941861178e-7, 1.0687984639727602e-6, 1.0943739571710144e-6, 7.717536715420541e-7, 7.863131461155549e-7, 1.046394700011375e-6, 5.563369250315241e-7, 6.290652908412485e-7, 5.577207458719793e-7, 5.137697037690632e-7, 3.4471354605373885e-6, 1.353246085385519e-6, 1.0528254490247082e-6, 1.2631247295281766e-6, 4.1508451069858405e-7, 2.0411122565127474e-6, 1.1769787773537058e-6, 3.009937110471998e-7, 7.145651831690646e-7, 9.327586820094418e-7, 5.580800362740061e-7, 2.706853782716956e-6, 1.0353789930846304e-6, 2.7028169930778016e-6, 4.7603254483087407e-7, 1.0041316238716353e-6, 8.414879917280157e-7, 1.1447273957839537e-6, 2.275190641575887e-6, 6.728203073392543e-7, 1.1276128893090667e-6, 1.0150883745713794e-6, 7.019233057423277e-7]
    comm_mcs = [0.020527885893939394, 0.02174878728787879, 0.02347771484848485, 0.01744793277272727, 0.02392204665151515, 0.015964665469696968, 0.020948033484848482, 0.021427584363636364, 0.022120655045454542, 0.021226820984848484, 0.02143560656060606, 0.012112109121212121, 0.021411399409090908, 0.021382727181818186, 0.022065514727272733, 0.020744995636363634, 0.021402168424242425, 0.02080790984848485, 0.022220805590909092, 0.021461548287878787, 0.020770689606060606, 0.02262658468181818, 0.02101595287878788, 0.01980213509090909, 0.021595702318181816, 0.02034816813636364, 0.02038311075757576, 0.021225970893939395, 0.016712652454545455, 0.02109570651515152, 0.02072173459090909, 0.020838297984848486, 0.015310745515151514, 0.014923250893939394, 0.017961288303030305, 0.0245065335, 0.022451245848484847, 0.024583279363636367, 0.020334403924242423, 0.020909498272727273, 0.027300031136363638, 0.02807682133333333, 0.02036326612121212, 0.019520167924242424, 0.019872202606060606, 0.020607004984848482, 0.020716484393939395, 0.020812893606060607, 0.021456629757575757, 0.021312822727272723, 0.021208796227272727, 0.020616452863636364, 0.012650536606060607, 0.020525659954545455, 0.019471103545454543, 0.01993640103030303, 0.020830905181818182, 0.020142426272727276, 0.01970495074242424, 0.019328818954545458, 0.018714486136363635, 0.018564471393939394, 0.011155735303030302, 0.020245134787878784, 0.018659716136363635, 0.020378126727272728, 0.0193235841969697, 0.023301455121212122, 0.019359793196969698, 0.019987275106060604, 0.019756426999999997, 0.019702085484848485, 0.019156225242424243, 0.01857880806060606, 0.020745189757575756, 0.02081883421212121, 0.02491620295454545, 0.019894534893939393, 0.024937468999999997, 0.019543741984848484, 0.012110012515151515, 0.019033852181818182, 0.020151511818181814, 0.016032879621212123, 0.01958354321212121, 0.019207566454545452, 0.019679614545454548, 0.01942848824242424, 0.015353549909090908, 0.019917568378787876, 0.01640477362121212, 0.019002854, 0.016230259272727275, 0.016491157166666666, 0.018922700151515152, 0.018338922454545454, 0.01958322275757576, 0.018752550727272724, 0.020812864318181818, 0.019503761393939393, 0.01868957228787879, 0.014964718151515151, 0.019189075454545457, 0.018914960454545455, 0.023214000878787878, 0.01956908371212121, 0.02031683074242424, 0.019978120424242428]
    comm_vcs = [7.71376002057562e-6, 8.71161570145597e-6, 2.8190724466371103e-5, 3.9719288139365954e-5, 0.0005753248919525802, 4.913796914497026e-5, 1.0755009979606647e-5, 9.727770092796291e-6, 1.9406524720763066e-5, 1.1738858929508642e-5, 3.9992859710382344e-5, 2.4420476825285297e-5, 1.1307005384615719e-5, 8.091123181673847e-6, 8.33634134964512e-6, 1.1639064012289313e-5, 6.178913376882124e-6, 1.0300770298189092e-5, 1.9927417715699365e-5, 8.503712374300211e-6, 9.727399626528385e-6, 2.4153905445686375e-5, 1.2192690738876098e-5, 2.1211294849250088e-5, 4.920057596816802e-6, 8.04111463461655e-6, 5.894557464110946e-6, 8.986336051485736e-6, 3.981947342056384e-5, 9.387594171940351e-6, 1.2595277045219296e-5, 1.0208496245788e-5, 4.5691094966205195e-5, 3.470611993002209e-5, 3.127369436582467e-5, 0.0005724459955333816, 5.3675537422206336e-5, 0.0005742912112955992, 1.1103775987495444e-5, 9.78835314429966e-6, 0.0010936961450293166, 0.0011071212295597449, 1.2934475903265724e-5, 5.67176992603056e-5, 1.139375675464425e-5, 1.0732607304354542e-5, 2.1253496550510014e-5, 9.436299986696219e-6, 1.1573016794500868e-5, 0.0012040727650579344, 9.14350670057259e-6, 8.096401559868282e-6, 4.020896704354129e-5, 1.121314543414486e-5, 1.3904256655469034e-5, 1.0232205467691844e-5, 6.645106038548061e-6, 2.694378026081069e-5, 7.264595740071847e-6, 8.799639514931498e-6, 1.1827449545892489e-5, 1.6925375944290446e-5, 2.8347512611144983e-5, 1.1631444587339502e-5, 1.1470260567731478e-5, 2.8997342849940448e-5, 1.0527820660567852e-5, 0.0005683750190482453, 0.0006254082464278202, 7.439286544803545e-6, 1.5788032986363565e-5, 9.671376483652355e-6, 8.561552872064944e-6, 1.0328151238873516e-5, 7.075935261477472e-6, 9.986104450478942e-6, 0.0011409563453643385, 7.254796014143376e-6, 0.0023614010559375722, 9.310955540719145e-6, 4.271290692019929e-5, 8.595515792484158e-6, 9.069558398619557e-6, 2.7609456304581793e-5, 1.0688735704673523e-5, 8.122673646795736e-6, 8.612749007113078e-6, 5.137047281338785e-6, 4.232986702984597e-5, 8.829800139200142e-6, 4.075932060277948e-5, 1.043649709147026e-5, 3.269164163633998e-5, 3.677718787234945e-5, 7.4610275460705155e-6, 2.698363211767516e-5, 5.51708690221445e-6, 7.502742820639143e-6, 2.772923821453354e-5, 5.991794709083375e-6, 7.957706096316675e-6, 4.419551973399062e-5, 7.004632328505328e-6, 7.520092479142517e-6, 0.0005703265870964341, 9.18612559371463e-6, 7.173339228648773e-6, 6.505005542154429e-6]

    # sim_nwait = floor(Int, nworkers/2)
    comp_distributions = [Gamma() for _ in 1:nworkers]
    comm_distributions = [Gamma() for _ in 1:nworkers]
    sim = EventDrivenSimulator(;nwait, nworkers, comm_distributions, comp_distributions)

    # # balanced mode
    ps, loss, loss0 = CodedComputing.optimize!(ps, ps, sim; θs, comp_mcs, comp_vcs, comm_mcs, comm_vcs, min_comp_fraction=0.01)
    @test loss < Inf

    # the LB can't find a solution here, since the comp. latency is too low relative to comm. latency
    # # check that the avg. latency is uniform (within some margin)
    # ms = comp_mcs .* θs ./ ps .+ comm_mcs
    # println("ms: $(sort(ms))")
    # μ = mean(ms)
    # for i in 1:nworkers
    #     @test ms[i] ≈ μ rtol=0.1
    # end
end

@testset "smoke-test" begin
    chin, chout = CodedComputing.setup_loadbalancer_channels()

    nworkers = 2
    nwait = 1
    time_limit = 1.0 # must be floating-point
    θs = [0.3, 0.7]
    qs = 1 ./ [2, 3]
    ps = round.(Int, 1 ./ qs)

    # put some random values into the load-balancer input
    Random.seed!(123)
    worker = 1
    v1 = CodedComputing.ProfilerOutput(worker, θs[worker], qs[worker], 2.0, 2.0, 0.1, 0.1)
    push!(chin, v1)

    worker = 2
    v2 = CodedComputing.ProfilerOutput(worker, θs[worker], qs[worker], 1.0, 1.0, 0.1, 0.1)
    push!(chin, v2)

    # start the load-balancer
    task = Threads.@spawn CodedComputing.load_balancer(chin, chout; nwait, nsubpartitions=ps, nworkers, min_improvement=1)

    # wait for up to 10 seconds for the input to be consumed
    t0 = time_ns()
    while (time_ns() - t0)/1e9 < 10 && isready(chin)
        sleep(0.1)
    end
    if istaskfailed(task)
        wait(task)
    end
    @test !isready(chin)

    # wait for up to 10 seconds for the subsystem to produce output
    t0 = time_ns()
    while (time_ns() - t0)/1e9 < 10 && !isready(chout)
        sleep(0.1)
    end
    if istaskfailed(task)
        wait(task)
    end

    correct1 = (1, 1)
    correct2 = (2, 7)

    @test isready(chout)
    vout = take!(chout)
    correct = vout.worker == 1 ? correct1 : correct2
    # @test vout == correct
    println(vout)

    @test isready(chout)
    vout = take!(chout)
    correct = vout.worker == 1 ? correct1 : correct2
    # @test vout == correct
    println(vout)

    # stop the profiler
    close(chin)
    close(chout)
    wait(task)
end


text:
# The ids are appended to each row after `.|`. Replace with comma

dataset_path = joinpath(dirname(@__FILE__), "thyroid-disease-sick.data.orig")

data = readstring(dataset_path)
write("$dataset_path.custom", replace(data, ".|", ","))

max_stars_repo_name: CoventryResearch/uci-data

max_issues_repo_name: CoventryResearch/uci-data

max_forks_repo_name: CoventryResearch/uci-data


text:
blockbandwidths(A::AdjOrTrans) = reverse(blockbandwidths(parent(A)))
subblockbandwidths(A::AdjOrTrans) = reverse(subblockbandwidths(parent(A)))
transposelayout(::AbstractBlockBandedLayout) = BlockBandedLayout()
transposelayout(::AbstractBandedBlockBandedLayout) = BandedBlockBandedLayout()
conjlayout(::Type{<:Complex}, ::M) where M<:AbstractBandedBlockBandedLayout = ConjLayout{M}()
conjlayout(::Type{<:Complex}, ::M) where M<:AbstractBlockBandedLayout = ConjLayout{M}()


text:
########## Lookups

function memoized_lookup(rt::Runtime, dependency_key::DependencyKey)
    # NOTE: It is important that the tracing happens around all internal computations for
    # derived functions and input functions, as we want to be sure we record _all_
    # dependencies, even those where the result is already cached.
    #
    # You may at first worry that internal checks such as the "Early Exit Optimization"
    # could cause dependencies on _old_ dependency_keys, which may change once our function
    # is invalidated, but in fact it will not. This is because as soon as an old
    # dependency_key returns a new value, we will stop checking old dependencies, and will
    # switch to a full evaluation, which will necessarily include the dependency_key that
    # returned a new value (it will be the first dependency to change its return value).
    rt = new_trace_runtime!(rt, dependency_key)

    # From now on, we're using the newly branched runtime, unique to that function. We also
    # take advantage of this higher-level stack trace to print nicer stack traces whenever a
    # user function throws an exception within Salsa.
    try
        return _memoized_lookup_internal(rt, dependency_key)
    catch e
        # Wrap all caught exceptions in a Salsa exception, so that we can print a summarized
        # trace when errors are handled. Note that the `DerivedFunctionException`s can be
        # handled and unwrapped via the ExceptionUnwrapping.jl package.
        #
        # NOTE: We use isa here, not has_wrapped_exception() because we want to ensure we
        # throw a DerivedFunctionException for the _current_ salsa stack trace. So even if,
        # e.g., this is a TaskFailedException wrapping a DerivedFunctionException, we still
        # want to wrap that one more time to ensure we pretty print the whole stack. :)
        if !(e isa DerivedFunctionException)
            # Include the current summarized Salsa trace in the exception for improved error
            # reporting.
            rethrow(DerivedFunctionException(e, collect_call_stack(rt)))
        else
            rethrow()
        end
    finally
        destruct_trace!(rt)
    end
end

function memoized_lookup_unwrapped(rt::Runtime, dependency_key::DependencyKey)
    return _unwrap_salsa_value(rt, memoized_lookup(rt, dependency_key))
end

# Delegation when called without a fully assembled `InputKey`.
function unmemoized_input_lookup(rt, input, args...)
    return unmemoized_input_lookup(rt, InputKey{typeof(input)}((args...,)))
end


text:
# Use baremodule to shave off a few KB from the serialized `.ji` file
baremodule LibPQ_jll
using Base
using Base: UUID
import JLLWrappers

JLLWrappers.@generate_main_file_header("LibPQ")
JLLWrappers.@generate_main_file("LibPQ", UUID("08be9ffa-1c94-5ee5-a977-46a84ec9b350"))
end  # module LibPQ_jll


text:
module VideoCaptureWrap

using CxxWrap
using VideoCaptureWrap_jll
const libvideocapture = VideoCaptureWrap_jll.libvideocapture_path

#=
# For those who like to use your shared library
using Libdl
const libvideocapture = joinpath("build", "lib", "libvideocapture.$(Libdl.dlext)")
=#

isfile(libvideocapture) && @wrapmodule(libvideocapture, :define_videoio_module)

function __init__()
    @initcxx
end

end


text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

@doc raw"""FlowSchemaSpec describes how the FlowSchema's specification looks like.

    IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec(;
        distinguisherMethod=nothing,
        matchingPrecedence=nothing,
        priorityLevelConfiguration=nothing,
        rules=nothing,
    )

    - distinguisherMethod::IoK8sApiFlowcontrolV1alpha1FlowDistinguisherMethod : `distinguisherMethod` defines how to compute the flow distinguisher for requests that match this schema. `nil` specifies that the distinguisher is disabled and thus will always be the empty string.
    - matchingPrecedence::Int32 : `matchingPrecedence` is used to choose among the FlowSchemas that match a given request. The chosen FlowSchema is among those with the numerically lowest (which we take to be logically highest) MatchingPrecedence.  Each MatchingPrecedence value must be non-negative. Note that if the precedence is not specified or zero, it will be set to 1000 as default.
    - priorityLevelConfiguration::IoK8sApiFlowcontrolV1alpha1PriorityLevelConfigurationReference : `priorityLevelConfiguration` should reference a PriorityLevelConfiguration in the cluster. If the reference cannot be resolved, the FlowSchema will be ignored and marked as invalid in its status. Required.
    - rules::Vector{IoK8sApiFlowcontrolV1alpha1PolicyRulesWithSubjects} : `rules` describes which requests will match this flow schema. This FlowSchema matches a request if and only if at least one member of rules matches the request. if it is an empty slice, there will be no requests matching the FlowSchema.
"""
mutable struct IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec <: SwaggerModel
    distinguisherMethod::Any # spec type: Union{ Nothing, IoK8sApiFlowcontrolV1alpha1FlowDistinguisherMethod } # spec name: distinguisherMethod
    matchingPrecedence::Any # spec type: Union{ Nothing, Int32 } # spec name: matchingPrecedence
    priorityLevelConfiguration::Any # spec type: Union{ Nothing, IoK8sApiFlowcontrolV1alpha1PriorityLevelConfigurationReference } # spec name: priorityLevelConfiguration
    rules::Any # spec type: Union{ Nothing, Vector{IoK8sApiFlowcontrolV1alpha1PolicyRulesWithSubjects} } # spec name: rules

    function IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec(;distinguisherMethod=nothing, matchingPrecedence=nothing, priorityLevelConfiguration=nothing, rules=nothing)
        o = new()
        validate_property(IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec, Symbol("distinguisherMethod"), distinguisherMethod)
        setfield!(o, Symbol("distinguisherMethod"), distinguisherMethod)
        validate_property(IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec, Symbol("matchingPrecedence"), matchingPrecedence)
        setfield!(o, Symbol("matchingPrecedence"), matchingPrecedence)
        validate_property(IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec, Symbol("priorityLevelConfiguration"), priorityLevelConfiguration)
        setfield!(o, Symbol("priorityLevelConfiguration"), priorityLevelConfiguration)
        validate_property(IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec, Symbol("rules"), rules)
        setfield!(o, Symbol("rules"), rules)
        o
    end
end # type IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec

const _property_map_IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec = Dict{Symbol,Symbol}(Symbol("distinguisherMethod")=>Symbol("distinguisherMethod"), Symbol("matchingPrecedence")=>Symbol("matchingPrecedence"), Symbol("priorityLevelConfiguration")=>Symbol("priorityLevelConfiguration"), Symbol("rules")=>Symbol("rules"))
const _property_types_IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec = Dict{Symbol,String}(Symbol("distinguisherMethod")=>"IoK8sApiFlowcontrolV1alpha1FlowDistinguisherMethod", Symbol("matchingPrecedence")=>"Int32", Symbol("priorityLevelConfiguration")=>"IoK8sApiFlowcontrolV1alpha1PriorityLevelConfigurationReference", Symbol("rules")=>"Vector{IoK8sApiFlowcontrolV1alpha1PolicyRulesWithSubjects}")
Base.propertynames(::Type{ IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec }) = collect(keys(_property_map_IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec))
Swagger.property_type(::Type{ IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec[name]))}
Swagger.field_name(::Type{ IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec }, property_name::Symbol) =  _property_map_IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec[property_name]

function check_required(o::IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec)
    (getproperty(o, Symbol("priorityLevelConfiguration")) === nothing) && (return false)
    true
end

function validate_property(::Type{ IoK8sApiFlowcontrolV1alpha1FlowSchemaSpec }, name::Symbol, val)
end


text:
struct DiffEqNLSolveTag end

struct DiffCache{T<:AbstractArray, S<:AbstractArray}
    du::T
    dual_du::S
end

Base.@pure function DiffCache(T, size, ::Type{Val{chunk_size}}) where chunk_size
  DiffCache(fill(zero(T), size...), fill(zero(Dual{typeof(ForwardDiff.Tag(DiffEqNLSolveTag(),T)),T,chunk_size}), size...))
end

Base.@pure DiffCache(u::AbstractArray) = DiffCache(eltype(u),size(u),Val{ForwardDiff.pickchunksize(length(u))})
Base.@pure DiffCache(u::AbstractArray,nlsolve) = DiffCache(eltype(u),size(u),Val{get_chunksize(nlsolve)})
Base.@pure DiffCache(u::AbstractArray,T::Type{Val{CS}}) where {CS} = DiffCache(eltype(u),size(u),T)

get_du(dc::DiffCache, ::Type{T}) where {T<:Dual} = dc.dual_du
get_du(dc::DiffCache, T) = dc.du

# Default nlsolve behavior, should move to DiffEqDiffTools.jl

Base.@pure determine_chunksize(u,alg::DiffEqBase.DEAlgorithm) = determine_chunksize(u,get_chunksize(alg))
Base.@pure function determine_chunksize(u,CS)
  if CS != 0
    return CS
  else
    return ForwardDiff.pickchunksize(length(u))
  end
end

struct NLSOLVEJL_SETUP{CS,AD} end
Base.@pure NLSOLVEJL_SETUP(;chunk_size=0,autodiff=true) = NLSOLVEJL_SETUP{chunk_size,autodiff}()
(::NLSOLVEJL_SETUP)(f,u0; kwargs...) = (res=NLsolve.nlsolve(f,u0; kwargs...); res.zero)
function (p::NLSOLVEJL_SETUP{CS,AD})(::Type{Val{:init}},f,u0_prototype) where {CS,AD}
  AD ? autodiff = :forward : autodiff = :central
  OnceDifferentiable(f, u0_prototype, u0_prototype, autodiff,
                     ForwardDiff.Chunk(determine_chunksize(u0_prototype,CS)))
end

get_chunksize(x) = 0
get_chunksize(x::NLSOLVEJL_SETUP{CS,AD}) where {CS,AD} = CS

macro swap!(x,y)
  quote
    local tmp = $(esc(x))
    $(esc(x)) = $(esc(y))
    $(esc(y)) = tmp
  end
end

macro cache(expr)
  name = expr.args[2].args[1].args[1]
  fields = [x for x in expr.args[3].args if typeof(x)!=LineNumberNode]
  cache_vars = Expr[]
  jac_vars = Pair{Symbol,Expr}[]
  for x in fields
    if x.args[2] == :uType || x.args[2] == :rateType ||
       x.args[2] == :kType || x.args[2] == :uNoUnitsType
      push!(cache_vars,:(c.$(x.args[1])))
    elseif x.args[2] == :JCType
      push!(cache_vars,:(c.$(x.args[1]).duals...))
    elseif x.args[2] == :GCType
      push!(cache_vars,:(c.$(x.args[1]).duals))
    elseif x.args[2] == :DiffCacheType
      push!(cache_vars,:(c.$(x.args[1]).du))
      push!(cache_vars,:(c.$(x.args[1]).dual_du))
    elseif x.args[2] == :JType || x.args[2] == :WType
      push!(jac_vars,x.args[1] => :(c.$(x.args[1])))
    end
  end
  quote
    $expr
    $(esc(:full_cache))(c::$name) = tuple($(cache_vars...))
    $(esc(:jac_iter))($(esc(:c))::$name) = tuple($(jac_vars...))
  end
end

# Nest one layer of value in order to get rid of possible Dual{Complex} or Complex{Dual} issues
# value should recurse for anything else.
function constvalue(x)
  _x = DiffEqBase.value(x)
  _x isa Complex ? DiffEqBase.value(real(_x)) : DiffEqBase.value(_x)
end

function diffdir(integrator::DiffEqBase.DEIntegrator)
  difference = maximum(abs, integrator.uprev)*sqrt(eps(typeof(integrator.t)))
  dir = integrator.tdir > zero(integrator.tdir) ?
          integrator.t > integrator.sol.prob.tspan[2] - difference ? -true :  true :
          integrator.t < integrator.sol.prob.tspan[2] + difference ?  true : -true
end


text:
using ModelingToolkit: operation, istree, arguments
# Method of lines discretization scheme
struct MOLFiniteDifference{T,T2} <: DiffEqBase.AbstractDiscretization
    dxs::T
    time::T2
    upwind_order::Int
    centered_order::Int
end

# Constructors. If no order is specified, both upwind and centered differences will be 2nd order
MOLFiniteDifference(dxs, time; upwind_order = 1, centered_order = 2) =
    MOLFiniteDifference(dxs, time, upwind_order, centered_order)

function SciMLBase.symbolic_discretize(pdesys::ModelingToolkit.PDESystem,discretization::DiffEqOperators.MOLFiniteDifference)
    pdeeqs = pdesys.eqs isa Vector ? pdesys.eqs : [pdesys.eqs]
    t = discretization.time
    nottime = filter(x->x.val != t.val,pdesys.indvars)

    # Discretize space

    space = map(nottime) do x
        xdomain = pdesys.domain[findfirst(d->x.val == d.variables,pdesys.domain)]
        @assert xdomain.domain isa IntervalDomain
        dx = discretization.dxs[findfirst(dxs->x.val == dxs[1].val,discretization.dxs)][2]
        dx isa Number ? (xdomain.domain.lower:dx:xdomain.domain.upper) : dx
    end
    tdomain = pdesys.domain[findfirst(d->t.val == d.variables,pdesys.domain)]
    @assert tdomain.domain isa IntervalDomain
    tspan = (tdomain.domain.lower,tdomain.domain.upper)

    # Build symbolic variables
    indices = CartesianIndices(((axes(s)[1] for s in space)...,))
    depvars = map(pdesys.depvars) do u
        [Num(Variable{Symbolics.FnType{Tuple{Any}, Real}}(Base.nameof(ModelingToolkit.operation(u.val)),II.I...))(t) for II in indices]
    end
    spacevals = map(y->[Pair(nottime[i],space[i][y.I[i]]) for i in 1:length(nottime)],indices)

    # Build symbolic maps
    edges = reduce(vcat,[[vcat([Colon() for j in 1:i-1],1,[Colon() for j in i+1:length(nottime)]),
      vcat([Colon() for j in 1:i-1],size(depvars[1],i),[Colon() for j in i+1:length(nottime)])] for i in 1:length(nottime)])

    #edgeindices = [indices[e...] for e in edges]
    edgevals = reduce(vcat,[[nottime[i]=>first(space[i]),nottime[i]=>last(space[i])] for i in 1:length(space)])
    edgevars = [[d[e...] for e in edges] for d in depvars]
    edgemaps = [spacevals[e...] for e in edges]
    initmaps = substitute.(pdesys.depvars,[t=>tspan[1]])

    depvarmaps = reduce(vcat,[substitute.((pdesys.depvars[i],),edgevals) .=> edgevars[i] for i in 1:length(pdesys.depvars)])
    if length(nottime) == 1
        left_weights(j) = DiffEqOperators.calculate_weights(discretization.upwind_order, 0.0, [space[j][1],space[j][2]])
        right_weights(j) = DiffEqOperators.calculate_weights(discretization.upwind_order, 0.0, [space[j][end-1],space[j][end]])
        central_neighbor_idxs(i,j) = [i+CartesianIndex([ifelse(l==j,-1,0) for l in 1:length(nottime)]...),i,i+CartesianIndex([ifelse(l==j,1,0) for l in 1:length(nottime)]...)]
        derivars = [[dot(left_weights(j),[depvars[j][central_neighbor_idxs(CartesianIndex(2),1)[1:2][2]],depvars[j][central_neighbor_idxs(CartesianIndex(2),1)[1:2][1]]]),
                    dot(right_weights(j),[depvars[j][central_neighbor_idxs(CartesianIndex(length(space[1])-1),1)[end-1:end][1]],depvars[j][central_neighbor_idxs(CartesianIndex(length(space[1])-1),1)[end-1:end][2]]])]
                    for j in 1:length(pdesys.depvars)]
        depvarderivmaps = reduce(vcat,[substitute.((Differential(nottime[j])(pdesys.depvars[i]),),edgevals) .=> derivars[i]
                                       for i in 1:length(pdesys.depvars) for j in 1:length(nottime)])
   else
       # TODO: Fix Neumann and Robin on higher dimension
       depvarderivmaps = []
   end

    # Generate initial conditions and bc equations
    u0 = []
    bceqs = []
    for bc in pdesys.bcs
        if ModelingToolkit.operation(bc.lhs) isa Sym && t.val ∉ ModelingToolkit.arguments(bc.lhs)
            # initial condition
            # Assume in the form `u(...) ~ ...` for now
            push!(u0,vec(depvars[findfirst(isequal(bc.lhs),initmaps)] .=> substitute.((bc.rhs,),spacevals)))
        else
            # Algebraic equations for BCs
            i = findfirst(x->occursin(x.val,bc.lhs),first.(depvarmaps))

            # TODO: Fix Neumann and Robin on higher dimension
            lhs = length(nottime) == 1 ? substitute(bc.lhs,depvarderivmaps[i]) : bc.lhs

            lhs = substitute(lhs,depvarmaps[i])
            rhs = substitute.((bc.rhs,),edgemaps[i])
            lhs = lhs isa Vector ? lhs : [lhs] # handle 1D
            push!(bceqs,lhs .~ rhs)
        end
    end
    u0 = reduce(vcat,u0)
    bceqs = reduce(vcat,bceqs)

    # Generate PDE Equations
    interior = indices[[2:length(s)-1 for s in space]...]
    eqs = vec(map(Base.product(interior,pdeeqs)) do p
        i,eq = p

        # TODO: Number of points in the central_neighbor_idxs should be dependent
        # on discretization.centered_order
        # TODO: Generalize central difference handling to allow higher even order derivatives
        central_neighbor_idxs(i,j) = [i+CartesianIndex([ifelse(l==j,-1,0) for l in 1:length(nottime)]...),i,i+CartesianIndex([ifelse(l==j,1,0) for l in 1:length(nottime)]...)]
        central_weights(i,j) = DiffEqOperators.calculate_weights(2, 0.0, [space[j][i[j]-1],space[j][i[j]],space[j][i[j]+1]])
        central_deriv_rules = [(Differential(nottime[j])^2)(pdesys.depvars[k]) => dot(central_weights(i,j),depvars[k][central_neighbor_idxs(i,j)]) for j in 1:length(nottime), k in 1:length(pdesys.depvars)]
        valrules = vcat([pdesys.depvars[k] => depvars[k][i] for k in 1:length(pdesys.depvars)],
                        [nottime[k] => space[k][i[k]] for k in 1:length(nottime)])

        # TODO: Use rule matching for nonlinear Laplacian

        # TODO: upwind rules needs interpolation into `@rule`
        #forward_weights(i,j) = DiffEqOperators.calculate_weights(discretization.upwind_order, 0.0, [space[j][i[j]],space[j][i[j]+1]])
        #reverse_weights(i,j) = DiffEqOperators.calculate_weights(discretization.upwind_order, 0.0, [space[j][i[j]-1],space[j][i[j]]])
        #upwinding_rules = [@rule(*(~~a,(Differential(nottime[j]))(u),~~b) => IfElse.ifelse(*(~~a..., ~~b...,)>0,
        #                        *(~~a..., ~~b..., dot(reverse_weights(i,j),depvars[k][central_neighbor_idxs(i,j)[1:2]])),
        #                        *(~~a..., ~~b..., dot(forward_weights(i,j),depvars[k][central_neighbor_idxs(i,j)[2:3]]))))
        #                        for j in 1:length(nottime), k in 1:length(pdesys.depvars)]

        substitute(eq.lhs,vcat(vec(central_deriv_rules),valrules)) ~ substitute(eq.rhs,vcat(vec(central_deriv_rules),valrules))
    end)

    # Finalize
    defaults = pdesys.ps === nothing || pdesys.ps === SciMLBase.NullParameters() ? u0 : vcat(u0,pdesys.ps)
    ps = pdesys.ps === nothing || pdesys.ps === SciMLBase.NullParameters() ? Num[] : first.(pdesys.ps)
    sys = ODESystem(vcat(eqs,unique(bceqs)),t,vec(reduce(vcat,vec(depvars))),ps,defaults=Dict(defaults))
    sys, tspan
end

function SciMLBase.discretize(pdesys::ModelingToolkit.PDESystem,discretization::DiffEqOperators.MOLFiniteDifference)
    sys, tspan = SciMLBase.symbolic_discretize(pdesys,discretization)
    simpsys = structural_simplify(sys)
    prob = ODEProblem(simpsys,Pair[],tspan)
end

# Piracy, to be deleted when https://github.com/JuliaSymbolics/SymbolicUtils.jl/pull/251
# merges
Base.occursin(needle::ModelingToolkit.SymbolicUtils.Symbolic, haystack::ModelingToolkit.SymbolicUtils.Symbolic) = _occursin(needle, haystack)
Base.occursin(needle, haystack::ModelingToolkit.SymbolicUtils.Symbolic) = _occursin(needle, haystack)
Base.occursin(needle::ModelingToolkit.SymbolicUtils.Symbolic, haystack) = _occursin(needle, haystack)
function _occursin(needle, haystack)
    isequal(needle, haystack) && return true

    if istree(haystack)
        args = arguments(haystack)
        for arg in args
            occursin(needle, arg) && return true
        end
    end
    return false
end


text:
module Agents

using Distributed
using LightGraphs
using DataFrames
using Random
using OpenStreetMapX

import Base.length
import LinearAlgebra

# Core structures of Agents.jl
include("core/agents.jl")
include("core/model.jl")
include("core/schedule.jl")
include("core/space_interaction_API.jl")

include("spaces/nothing.jl")
include("spaces/graph.jl")
include("spaces/grid.jl")
include("spaces/discrete.jl")
include("spaces/continuous.jl")
include("spaces/openstreetmap.jl")
include("spaces/utilities.jl")

# Stepping and data collection functionality
include("simulations/step.jl")
include("simulations/collect.jl")
include("simulations/paramscan.jl")
include("simulations/sample.jl")

# Plot recipes
include("visualization/plot-recipes.jl")

# 4.0 Depreciations
@deprecate space_neighbors nearby_ids
@deprecate node_neighbors nearby_positions
@deprecate get_node_contents ids_in_position
@deprecate get_node_agents agents_in_position
@deprecate pick_empty random_empty
@deprecate find_empty_nodes empty_positions
@deprecate has_empty_nodes has_empty_positions
@deprecate nodes positions

# Predefined models
include("models/Models.jl")
export Models

# Update message:
display_update = true
version_number = "4.0"
update_name = "update_v$(version_number)"

if display_update
if !isfile(joinpath(@__DIR__, update_name))
printstyled(stdout,
"""
\nUpdate message: Agents v$(version_number)

Agents new release v$(version_number) is a massive one!
Notable features:
* Overhauled all spaces for more extendability, better performance, and more features
* New space type based on Open Street Map
* Renaming most of the API towards more intuitive names (deprecations exist!)
and more! See the full changelog online for a list of new features and breaking changes!

https://github.com/JuliaDynamics/Agents.jl/blob/master/CHANGELOG.md

"""; color = :light_magenta)
touch(joinpath(@__DIR__, update_name))
end
end

end # module


text:
# Autorand

"`autorand(x::RandVar)` Single sample from `x`.  Inference `alg` and hyperparams, chosen automatically"
autorand(x::RandVar) = rand(x, 1000; alg = SSMH)[end]
Base.getindex(x::RandVar) = autorand(x)


text:
__precompile__()

module PlotlyBase

using Base.Iterators
using JSON
using DocStringExtensions
using Requires

import Base: ==

# import LaTeXStrings and export the handy macros
using LaTeXStrings
export @L_mstr, @L_str

# export some names from JSON
export json

_symbol_dict(x) = x
_symbol_dict(d::Associative) =
    Dict{Symbol,Any}([(Symbol(k), _symbol_dict(v)) for (k, v) in d])

# include these here because they are used below
include("traces_layouts.jl")
include("styles.jl")

# core plot object
mutable struct Plot{TT<:AbstractTrace}
    data::Vector{TT}
    layout::AbstractLayout
    divid::Base.Random.UUID
    style::Style
end

function Base.show(io::IO, ::MIME"text/plain", p::Plot)
    println(io, """
    data: $(json(map(_describe, p.data), 2))
    layout: "$(_describe(p.layout))"
    """)
end

Base.show(io::IO, p::Plot) = show(io, MIME("text/plain"), p)

function savefig(p::Plot, fn::AbstractString)
    ext = split(fn, ".")[end]
    if ext == "json"
        open(f -> print(f, json(p)), fn, "w")
        return p
    else
        msg = "PlotlyBase can only save figures as JSON. For all other"
        msg *= " file types, please use PlotlyJS.jl"
        throw(ArgumentError(msg))
    end
end

# include the rest of the core parts of the package
include("util.jl")
include("json.jl")
include("subplots.jl")
include("api.jl")
include("convenience_api.jl")
@require DataFrames include("dataframes_api.jl")
include("recession_bands.jl")

# Set some defaults for constructing `Plot`s
function Plot(;style::Style=CURRENT_STYLE[])
    Plot(GenericTrace{Dict{Symbol,Any}}[], Layout(), Base.Random.uuid4(), style)
end

function Plot{T<:AbstractTrace}(data::AbstractVector{T}, layout=Layout();
                                style::Style=CURRENT_STYLE[])
    Plot(data, layout, Base.Random.uuid4(), style)
end

function Plot(data::AbstractTrace, layout=Layout();
              style::Style=CURRENT_STYLE[])
    Plot([data], layout; style=style)
end

# NOTE: we export trace constructing types from inside api.jl
# NOTE: we export names of shapes from traces_layouts.jl
export

    # core types
    Plot, GenericTrace, Layout, Shape, AbstractTrace, AbstractLayout,

    # plotly.js api methods
    restyle!, relayout!, update!, addtraces!, deletetraces!, movetraces!,
    redraw!, extendtraces!, prependtraces!, purge!, to_image, download_image,

    # non-!-versions (forks, then applies, then returns fork)
    restyle, relayout, update, addtraces, deletetraces, movetraces, redraw,
    extendtraces, prependtraces,

    # helper methods
    plot, fork, vline, hline, attr,

    # new trace types
    stem,

    # convenience stuff
    add_recession_bands!,

    # frontend methods
    init_notebook,

    # styles
    use_style!, style, Style, Cycler,

    # other
    savefig

@init begin
    env_style = Symbol(get(ENV, "PLOTLYJS_STYLE", ""))
    if env_style in STYLES
        global DEFAULT_STYLE
        DEFAULT_STYLE[] = Style(env_style)
    end
end

# jupyterlab/nteract integration
Base.istextmime(::MIME"application/vnd.plotly.v1+json") = true
@require IJulia begin
    function IJulia.display_dict(p::Plot)
        Dict(
            "application/vnd.plotly.v1+json" => JSON.lower(p),
            "text/plain" => sprint(show, "text/plain", p)
        )
    end
end

end # module


text:
struct Vis2
    λ::Measurement{Float64}
    data::Vector{Measurement{Float64}}
    u::Vector{Float64}
    v::Vector{Float64}

    function Vis2(λ, data, u, v)
        if length(u) ≠ length(v)
            error("u and v arrays must have the same length")
        end
        if length(data) ≠ length(u)
            error("data array must have the same length as u and v arrays")
        end
        return new(λ, data, u, v)
    end

    function Vis2(
        λ::T,
        λerr::T,
        data::Vector{T},
        err::Vector{T},
        u::Vector{T},
        v::Vector{T},
    ) where T<:Real
        return Vis2(λ .± (0.5 .* λerr), data .± err, u, v)
    end

    function Vis2(λ::Measurement{T}, data::Measurement{T}, u::T, v::T) where T<:Real
        return Vis2(λ, [data], [u], [v])
    end
end

function ==(a::Vis2, b::Vis2)
    return a.λ == b.λ && a.data == b.data && a.u == b.u && a.v == b.v
end

function getindex(a::Vis2, @nospecialize vals)
    return Vis2(a.λ, a.data[vals], a.u[vals], a.v[vals])
end

function length(meas::Vis2)
    return length(meas.data)
end

"""
    purge(meas::Vis2)

Remove NaN values from a Vis2 object
"""
function purge(meas::Vis2)
    nan_val = isnan.(Measurements.value.(meas.data))
    nan_err = isnan.(Measurements.uncertainty.(meas.data))
    mask = .!(nan_val .| nan_err)
    return Vis2(meas.λ, meas.data[mask], meas.u[mask], meas.v[mask])
end

"""
    merge(arr::Vector{Vis2})

This merges Vis2 data with very similar eff_wave values. Currently, the implementation is
idiotic; I will need to think on this more in the future.
"""
function merge(arr::Vector{Vis2})
    λ = map(meas -> meas.λ, arr)
    m2c(x::Measurement{Float64}) = Complex(x.val, x.err)
    c2m(x::Complex{Float64}) = x.re ± x.im
    function bin(x::Vector{Measurement{Float64}})
        lo = minimum(map(y -> y.val - y.err, x))
        hi = maximum(map(y -> y.val + y.err, x))
        er = 0.5*(hi - lo)
        return Complex(mean(x).val, er)
    end
    d = Dict{Complex{Float64}, Vector{Int64}}()
    for i in eachindex(λ)
        test = false
        for k in keys(d)
            if abs(stdscore(c2m(k), λ[i])) < 0.5 * √(2)
                tmparr = vcat(pop!(d, k), i)
                d[bin(λ[tmparr])] = tmparr
                test = true
                break
            end
        end
        if test == false
            d[m2c(λ[i])] = [i]
        end
    end
    kd = sort(collect(keys(d)), by=real, rev=true)
    ret = Vector{Vis2}(undef, length(kd))
    for (i, el) in enumerate(kd)
        data = vcat([arr[j].data for j in d[el]]...)
        u = vcat([arr[j].u for j in d[el]]...)
        v = vcat([arr[j].v for j in d[el]]...)
        ret[i] = Vis2(c2m(el), data, u, v)
    end
    return ret
end

function +(a::Vis2, b::Vis2)
    ret = merge([a,b])
    if length(ret) > 1
        error("Wavelengths are incompatible")
    else
        return ret[1]
    end
end

function load(file::T) where T<:AbstractString
    f = OIFITS.load(file)
    db = OIFITS.select(f, "OI_VIS2")

    if length(db) ≠ 1
        error("Currently, only a single Vis2 table per oifits file is supported")
    end

    λ = db[1].ins[:eff_wave] .± (0.5 .* db[1].ins[:eff_band])
    data = db[1][:vis2data] .± db[1][:vis2err]
    u = db[1][:ucoord]
    v = db[1][:vcoord]

    return [Vis2(λ[i], data[i,:], u, v) |> purge for i in 1:length(λ)]
end

function load(files::Vector{T}) where T<:AbstractString
    return merge(vcat(load.(files)...))
end

function loaddir(dir::T) where T<:AbstractString
    fits = dir .* filter(x -> occursin(".fits", x), readdir(dir))
    oifits = dir .* filter(x -> occursin(".oifits", x), readdir(dir))
    files = vcat(fits, oifits)
    return load(files)
end

function uv(meas::Vis2)
    return (1/meas.λ.val) .* hcat(meas.u, meas.v)'
end

"""
    baseline(uv, inc=0, pa=0)

Converts a 2×n array of (u, v) points, or a Vis2 object, in into a baseline separation. If
inclination and position angle parameters are passed, the function computes the effective
baseline for a source stretched and rotated by that amount on the sky.
"""
function baseline(uv_arr::Array{Float64,2}, inc=0.0, pa=0.0)
    upvp = [
        (cosd(pa)*cosd(inc)) (-sind(pa)*cosd(inc))
        (sind(pa))           (cosd(pa))
    ] * uv_arr
    return hypot.(upvp[1,:], upvp[2,:])
end

baseline(meas::Vis2, inc=0.0, pa=0.0) = baseline(uv(meas), inc, pa)

function setminerror(vis2, percent=5.0)
    for i in eachindex(vis2.data)
        err = vis2.data[i].val * percent / 100.
        if err > vis2.data[i].err
            vis2.data[i] = vis2.data[i].val ± err
        end
    end
end


text:
"""
    calc_padding_regions(dims)

Padding is a jerk.  A HUGE jerk that tries to sneak a bunch of conditionals and edge
cases (quite literally) into our beautiful stencil operations such as convolution,
pooling, etc...  The way we deal with this is to, first, deal with everything in 3d,
and then define a single padding region helper function that returns the seven regions
that all 3d operations must deal with, including the central "unpadded" region where we
can run at full bore, not paying any attention to padding.
"""
function calc_padding_regions(dims)
    width, height, depth = input_size(dims)
    kernel_w, kernel_h, kernel_d = kernel_size(dims)
    C_in = channels_in(dims)
    pad_w_lo, pad_w_hi, pad_h_lo, pad_h_hi, pad_d_lo, pad_d_hi = padding(dims)
    dil_w, dil_h, dil_d = dilation(dims)
    stride_w, stride_h, stride_d = stride(dims)
    out_width, out_height, out_depth = output_size(dims)

    # Let us first calculate the number of rows/cols within which we must zero out some
    # portion of the image patches we're copying over.  The "spillage" here is the number
    # of indices along a particular dimension for which a kernel will have some portion
    # of its input domain overlapping the padding.  If padding is zero, these values are
    # all trivially zero.  The low spillage is trivially the low padding divided by the
    # stride; literally the number of shifts that overlap some padding.  The high
    # spillage is slightly more complicated; we first figure out how many elements of
    # high padding are wasted (e.g. through strides not fitting to the end perfectly)
    # subtract that from the high padding, then do the same:
    calc_lo_spill(O, S, P) = min(ceil(Int, P/S), O)
    @inline function calc_hi_spill(O, S, Pl, Ph, K, D, I)
        wasted_Ph = (I + Pl + Ph - (K - 1)*D - 1)%S
        return min(ceil(Int, (Ph - wasted_Ph)/S), O)
    end

    spill_w_lo = calc_lo_spill(out_width, stride_w, pad_w_lo)
    spill_w_hi = calc_hi_spill(out_width, stride_w, pad_w_lo, pad_w_hi, kernel_w, dil_w, width)
    spill_h_lo = calc_lo_spill(out_height, stride_h, pad_h_lo)
    spill_h_hi = calc_hi_spill(out_height, stride_h, pad_h_lo, pad_h_hi, kernel_h, dil_h, height)
    spill_d_lo = calc_lo_spill(out_depth, stride_d, pad_d_lo)
    spill_d_hi = calc_hi_spill(out_depth, stride_d, pad_d_lo, pad_d_hi, kernel_d, dil_d, depth)

    spill_w_hi_abs = out_width  - spill_w_hi + 1
    spill_h_hi_abs = out_height - spill_h_hi + 1
    spill_d_hi_abs = out_depth  - spill_d_hi + 1

    # These are the regions we're going to have to run with cognizance of padding.
    # There are six of them; one for each face of the cube image.  We explicitly
    # design this so that we run over `width` most tightly, in the expectation that
    # this will generate better code for when `h` and `d` are singleton dimensions.
    # We visualize this as a cube, indexed by dimensions (w, h, d).
    padded_regions = (
        # First region is the lower-d WH face:
        (
            1:out_width,
            1:out_height,
            1:spill_d_lo,
        ),

        # The next largest chunk we choose will be the lower-h WD faces; we always
        # want to maximize going across full `w`, as its contiguous in memory.
        (
            1:out_width,
            1:spill_h_lo,
            (spill_d_lo+1):(spill_d_hi_abs-1),
        ),
        # Then the upper-h WD face
        (
            1:out_width,
            spill_h_hi_abs:out_height,
            (spill_d_lo+1):(spill_d_hi_abs-1),
        ),

        # Next, we fit the HD faces in, but without overlapping the `h` and `d`
        # regions we've done before:
        (
            1:spill_w_lo,
            (spill_h_lo+1):(spill_h_hi_abs-1),
            (spill_d_lo+1):(spill_d_hi_abs-1),
        ),
        (
            spill_w_hi_abs:out_width,
            (spill_h_lo+1):(spill_h_hi_abs-1),
            (spill_d_lo+1):(spill_d_hi_abs-1)
        ),

        # Last region is the higher-d WH face:
        (
            1:out_width,
            1:out_height,
            spill_d_hi_abs:out_depth,
        ),
    )

    # The central region that has no padding.
    central_region = (
        (spill_w_lo+1):(spill_w_hi_abs - 1),
        (spill_h_lo+1):(spill_h_hi_abs - 1),
        (spill_d_lo+1):(spill_d_hi_abs - 1),
    )
    return padded_regions, central_region
end


text:
function update_logweights_cost_to_go(logwms_tilde_kp2, Λ_tilde_prime_kp2, θ_tilde_prime_kp2, ykp1, params::NamedTuple, logμπh::Function)
    return Float64[logwms_tilde_kp2[k]  + logμπh(Λ_tilde_prime_kp2[k], θ_tilde_prime_kp2, ykp1, params) for k in eachindex(Λ_tilde_prime_kp2)]
end

max_stars_repo_name: konkam/DualOptimalFiltering

max_issues_repo_name: konkam/DualOptimalFiltering

max_forks_repo_name: konkam/DualOptimalFiltering


text:
module adapters_sqlite_execute_result_test

using Test # @test
using Octo.Adapters.SQLite # Repo Schema from SELECT FROM WHERE

import SQLite # pathof(SQLite)
dbfile = joinpath(dirname(pathof(SQLite)), "..", "test", "Chinook_Sqlite.sqlite")
dbfile2 = joinpath(@__DIR__, "test.sqlite")
cp(dbfile, dbfile2; force=true)
chmod(dbfile2, 0o666)

Repo.debug_sql()

repo = Repo.connect(
    adapter = Octo.Adapters.SQLite,
    dbfile = dbfile2
)

struct Employee
end
Schema.model(Employee,
    table_name = "Employee",
    primary_key = "EmployeeId"
)

result = Repo.query([CREATE TABLE IF NOT EXISTS :temp AS SELECT * FROM :Album])
@test isempty(result)

struct Temp
end
Schema.model(Temp, table_name="temp", primary_key="AlbumId")

result = Repo.query([DELETE FROM Temp])
@test isempty(result)

result = Repo.query("select * from temp")
@test isempty(result)

result = Repo.execute([DELETE FROM Temp])
@test result.num_affected_rows == 0

changes = (AlbumId=0, Title="Test Album", ArtistId=0)
inserted = Repo.insert!(Temp, changes)
@test inserted.id == 1

result = Repo.query("select * from temp")
@test isone(length(result))

result = Repo.execute("update Temp set Title = 'New Title' where AlbumId > 100")
@test result.num_affected_rows == 0

result = Repo.execute("delete from Temp")
@test result.num_affected_rows == 1

Repo.disconnect()

end # module adapters_sqlite_execute_result_test