text:
using Simpsons, Distributions, DataFrames, CSV, Plots, Test

# see wikipedia entry at http://en.wikipedia.org/wiki/Simpsons_paradox
const data = vcat(
    repeat([["A", "small", 1]], 81), repeat([["A", "small", 0]], 87 - 81),
    repeat([["B", "small", 0]], 270 - 234), repeat([["B", "small", 1]], 234),
    repeat([["B", "large", 1]], 55), repeat([["B", "large", 0]], 80 - 55),
    repeat([["A", "large", 0]], 263 - 192), repeat([["A", "large", 1]], 192)
)
const df = DataFrame(treatment = [d[1] for d in data],
               recovery = [d[3] for d in data],
               kidney_stone_size = [d[2] for d in data])

@test has_simpsons_paradox(df, :treatment, :recovery, :kidney_stone_size) == true

const pathname = "cars.csv"
const dfc = DataFrame(CSV.File(pathname, datarow = 3))
@test has_simpsons_paradox(dfc, :Weight, :MPG, :Cylinders) == false
@test has_simpsons_paradox(dfc, :Weight, :MPG, :Acceleration) == false
@test has_simpsons_paradox(dfc, :Weight, :MPG, :Horsepower) == false

Plots.scalefontsizes(0.6)
simpsons_analysis(dfc, :Horsepower, :Acceleration)
simpsons_analysis(df, :treatment, :recovery)

dfp = make_paradox()
@test has_simpsons_paradox(dfp, :x, :y, :z) == true
plot_kmeans_by_factor(dfp, :x, :y, :z)


text:
import Images, AxisArrays
using AxisArrays: Axis
using Colors

# Create a cone in 3d that changes color over time
sz = [201, 301, 31]
center = [(s+1)>>1 for s in sz]  # ceil(Int, sz/2)
C3 = Bool[(i-center[1])^2+(j-center[2])^2 <= k^2 for i = 1:sz[1], j = 1:sz[2], k = sz[3]:-1:1]
cmap1 = round.(UInt32, range(0, stop=255, length=60))
cmap = Array{UInt32}(undef, length(cmap1))
for i = 1:length(cmap)
    cmap[i] = cmap1[i]<<16 + cmap1[end-i+1]<<8 + cmap1[i]
end
C4 = Array{UInt32}(undef, sz..., length(cmap))
for i = 1:length(cmap)
    C4[:,:,:,i] = C3*cmap[i]
end
img = AxisArray(reinterpret(RGB24, C4), Axis{:x}(1:size(C4,1)), Axis{:y}(1:size(C4,2)), Axis{:z}(range(1,step=3,length=size(C4,3))), Axis{:time}(1:size(C4,4)))

nothing

ext: jl


text:
module ResNet
export ResNetModel, stages_channels

using Pickle
using Downloads: download
using Flux

include("blocks.jl")
include("model.jl")
include("load_utils.jl")

# using Images
# function main()
#     device = cpu
#     model = from_pretrained(18)
#     model = model |> testmode! |> device
#     @info "Model loaded."

#     images = [
#         raw"C:\Users\tonys\Downloads\elephant2-r.jpg",
#         raw"C:\Users\tonys\Downloads\spaceshuttle-r.jpg",
#     ]
#     μ = reshape([0.485, 0.456, 0.406], (3, 1, 1))
#     σ = reshape([0.229, 0.224, 0.225], (3, 1, 1))
#     for image in images
#         x = Images.load(image) |> channelview .|> Float32
#         @. x = (x - μ) / σ
#         x = Flux.unsqueeze(permutedims(x, (3, 2, 1)), 4)

#         @info "Image $image ($(size(x))):"
#         o = x |> device |> model |> softmax |> cpu
#         o = sortperm(o[:, 1])
#         @info "Top 5 classes: $(o[end:-1:end - 5] .- 1)"
#     end
# end
# main()

end


text:
notebooks = ["agentbased.jl",
             "agentgraft.jl",
             "modelmacro.jl",
             "monomial_regression.jl",
             "multivariate_regression.jl",
             "polynomial_regression.jl",
             "workflow.jl",
             "pseudo_polynomial_regression.jl",
             "odegraft.jl",
             ]
for nb in notebooks
    @info "Running example notebook" file=nb
    include(nb)
end


text:
function snp500()

    data = readdlm(joinpath(dirname(@__FILE__),"..","..","examples","data","snp500.txt"))
    g = data[1:300]

    M_bf = 2

    ζ_vec = 0.005:0.005:0.05

    I_sols =
    [[1, 300],
    [1, 128, 300],
    [1, 149, 165, 300],
    [1, 78, 146, 164, 300],
    [1, 145, 191, 244, 251, 300],
    [1, 78, 145, 170, 245, 250, 300],
    [1, 64, 68, 144, 170, 245, 250, 300],
    [1, 64, 68, 145, 163, 203, 241, 252, 300],
    [1, 34, 44, 72, 145, 163, 203, 241, 252, 300],
    [1, 63, 74, 95, 104, 144, 163, 203, 241, 252, 300],
    [1, 34, 44, 78, 94, 105, 144, 163, 203, 241, 252, 300],
    [1, 34, 44, 78, 94, 105, 144, 163, 204, 241, 253, 268, 300],
    [1, 34, 44, 78, 94, 105, 144, 163, 205, 233, 245, 252, 268, 300],
    [1, 34, 44, 78, 94, 105, 144, 163, 203, 241, 252, 266, 268, 270, 300]]

    f_sols =
    [0.303993875391825,
    0.2760951476102491,
    0.2058845486408245,
    0.1791507928410283,
    0.13953735503127973,
    0.11683004720180179,
    0.10346917135575495,
    0.09289707415700832,
    0.08484771880284825,
    0.07610803627903806,
    0.06746465092510334,
    0.06367900239456503,
    0.06051435296103591,
    0.05690190505811188]

    return g, ζ_vec, I_sols, f_sols
end


text:
#
# Autogenerated by Thrift Compiler (0.11.0)
#
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING

struct _enum_TProtocolVersion
  HIVE_CLI_SERVICE_PROTOCOL_V1::Int32
  HIVE_CLI_SERVICE_PROTOCOL_V2::Int32
  HIVE_CLI_SERVICE_PROTOCOL_V3::Int32
  HIVE_CLI_SERVICE_PROTOCOL_V4::Int32
  HIVE_CLI_SERVICE_PROTOCOL_V5::Int32
  HIVE_CLI_SERVICE_PROTOCOL_V6::Int32
  HIVE_CLI_SERVICE_PROTOCOL_V7::Int32
  HIVE_CLI_SERVICE_PROTOCOL_V8::Int32
  HIVE_CLI_SERVICE_PROTOCOL_V9::Int32
  HIVE_CLI_SERVICE_PROTOCOL_V10::Int32
  HIVE_CLI_SERVICE_PROTOCOL_V11::Int32
end
const TProtocolVersion = _enum_TProtocolVersion(Int32(0), Int32(1), Int32(2), Int32(3), Int32(4), Int32(5), Int32(6), Int32(7), Int32(8), Int32(9), Int32(10))

struct _enum_TTypeId
  BOOLEAN_TYPE::Int32
  TINYINT_TYPE::Int32
  SMALLINT_TYPE::Int32
  INT_TYPE::Int32
  BIGINT_TYPE::Int32
  FLOAT_TYPE::Int32
  DOUBLE_TYPE::Int32
  STRING_TYPE::Int32
  TIMESTAMP_TYPE::Int32
  BINARY_TYPE::Int32
  ARRAY_TYPE::Int32
  MAP_TYPE::Int32
  STRUCT_TYPE::Int32
  UNION_TYPE::Int32
  USER_DEFINED_TYPE::Int32
  DECIMAL_TYPE::Int32
  NULL_TYPE::Int32
  DATE_TYPE::Int32
  VARCHAR_TYPE::Int32
  CHAR_TYPE::Int32
  INTERVAL_YEAR_MONTH_TYPE::Int32
  INTERVAL_DAY_TIME_TYPE::Int32
  TIMESTAMPLOCALTZ_TYPE::Int32
end
const TTypeId = _enum_TTypeId(Int32(0), Int32(1), Int32(2), Int32(3), Int32(4), Int32(5), Int32(6), Int32(7), Int32(8), Int32(9), Int32(10), Int32(11), Int32(12), Int32(13), Int32(14), Int32(15), Int32(16), Int32(17), Int32(18), Int32(19), Int32(20), Int32(21), Int32(22))

struct _enum_TStatusCode
  SUCCESS_STATUS::Int32
  SUCCESS_WITH_INFO_STATUS::Int32
  STILL_EXECUTING_STATUS::Int32
  ERROR_STATUS::Int32
  INVALID_HANDLE_STATUS::Int32
end
const TStatusCode = _enum_TStatusCode(Int32(0), Int32(1), Int32(2), Int32(3), Int32(4))

struct _enum_TOperationState
  INITIALIZED_STATE::Int32
  RUNNING_STATE::Int32
  FINISHED_STATE::Int32
  CANCELED_STATE::Int32
  CLOSED_STATE::Int32
  ERROR_STATE::Int32
  UKNOWN_STATE::Int32
  PENDING_STATE::Int32
  TIMEDOUT_STATE::Int32
end
const TOperationState = _enum_TOperationState(Int32(0), Int32(1), Int32(2), Int32(3), Int32(4), Int32(5), Int32(6), Int32(7), Int32(8))

struct _enum_TOperationType
  EXECUTE_STATEMENT::Int32
  GET_TYPE_INFO::Int32
  GET_CATALOGS::Int32
  GET_SCHEMAS::Int32
  GET_TABLES::Int32
  GET_TABLE_TYPES::Int32
  GET_COLUMNS::Int32
  GET_FUNCTIONS::Int32
  UNKNOWN::Int32
end
const TOperationType = _enum_TOperationType(Int32(0), Int32(1), Int32(2), Int32(3), Int32(4), Int32(5), Int32(6), Int32(7), Int32(8))

struct _enum_TGetInfoType
  CLI_MAX_DRIVER_CONNECTIONS::Int32
  CLI_MAX_CONCURRENT_ACTIVITIES::Int32
  CLI_DATA_SOURCE_NAME::Int32
  CLI_FETCH_DIRECTION::Int32
  CLI_SERVER_NAME::Int32
  CLI_SEARCH_PATTERN_ESCAPE::Int32
  CLI_DBMS_NAME::Int32
  CLI_DBMS_VER::Int32
  CLI_ACCESSIBLE_TABLES::Int32
  CLI_ACCESSIBLE_PROCEDURES::Int32
  CLI_CURSOR_COMMIT_BEHAVIOR::Int32
  CLI_DATA_SOURCE_READ_ONLY::Int32
  CLI_DEFAULT_TXN_ISOLATION::Int32
  CLI_IDENTIFIER_CASE::Int32
  CLI_IDENTIFIER_QUOTE_CHAR::Int32
  CLI_MAX_COLUMN_NAME_LEN::Int32
  CLI_MAX_CURSOR_NAME_LEN::Int32
  CLI_MAX_SCHEMA_NAME_LEN::Int32
  CLI_MAX_CATALOG_NAME_LEN::Int32
  CLI_MAX_TABLE_NAME_LEN::Int32
  CLI_SCROLL_CONCURRENCY::Int32
  CLI_TXN_CAPABLE::Int32
  CLI_USER_NAME::Int32
  CLI_TXN_ISOLATION_OPTION::Int32
  CLI_INTEGRITY::Int32
  CLI_GETDATA_EXTENSIONS::Int32
  CLI_NULL_COLLATION::Int32
  CLI_ALTER_TABLE::Int32
  CLI_ORDER_BY_COLUMNS_IN_SELECT::Int32
  CLI_SPECIAL_CHARACTERS::Int32
  CLI_MAX_COLUMNS_IN_GROUP_BY::Int32
  CLI_MAX_COLUMNS_IN_INDEX::Int32
  CLI_MAX_COLUMNS_IN_ORDER_BY::Int32
  CLI_MAX_COLUMNS_IN_SELECT::Int32
  CLI_MAX_COLUMNS_IN_TABLE::Int32
  CLI_MAX_INDEX_SIZE::Int32
  CLI_MAX_ROW_SIZE::Int32
  CLI_MAX_STATEMENT_LEN::Int32
  CLI_MAX_TABLES_IN_SELECT::Int32
  CLI_MAX_USER_NAME_LEN::Int32
  CLI_OJ_CAPABILITIES::Int32
  CLI_XOPEN_CLI_YEAR::Int32
  CLI_CURSOR_SENSITIVITY::Int32
  CLI_DESCRIBE_PARAMETER::Int32
  CLI_CATALOG_NAME::Int32
  CLI_COLLATION_SEQ::Int32
  CLI_MAX_IDENTIFIER_LEN::Int32
  CLI_ODBC_KEYWORDS::Int32
end
const TGetInfoType = _enum_TGetInfoType(Int32(0), Int32(1), Int32(2), Int32(8), Int32(13), Int32(14), Int32(17), Int32(18), Int32(19), Int32(20), Int32(23), Int32(25), Int32(26), Int32(28), Int32(29), Int32(30), Int32(31), Int32(32), Int32(34), Int32(35), Int32(43), Int32(46), Int32(47), Int32(72), Int32(73), Int32(81), Int32(85), Int32(86), Int32(90), Int32(94), Int32(97), Int32(98), Int32(99), Int32(100), Int32(101), Int32(102), Int32(104), Int32(105), Int32(106), Int32(107), Int32(115), Int32(10000), Int32(10001), Int32(10002), Int32(10003), Int32(10004), Int32(10005), Int32(10006))

struct _enum_TFetchOrientation
  FETCH_NEXT::Int32
  FETCH_PRIOR::Int32
  FETCH_RELATIVE::Int32
  FETCH_ABSOLUTE::Int32
  FETCH_FIRST::Int32
  FETCH_LAST::Int32
end
const TFetchOrientation = _enum_TFetchOrientation(Int32(0), Int32(1), Int32(2), Int32(3), Int32(4), Int32(5))

struct _enum_TJobExecutionStatus
  IN_PROGRESS::Int32
  COMPLETE::Int32
  NOT_AVAILABLE::Int32
end
const TJobExecutionStatus = _enum_TJobExecutionStatus(Int32(0), Int32(1), Int32(2))

const TTypeEntryPtr = Int32

const TIdentifier = String

const TPattern = String

const TPatternOrIdentifier = String

mutable struct TTypeQualifierValue <: Thrift.TMsg
  i32Value::Int32
  stringValue::String
  TTypeQualifierValue() = (o=new(); fillunset(o); o)
end # mutable struct TTypeQualifierValue
meta(t::Type{TTypeQualifierValue}) = meta(t, Symbol[:i32Value,:stringValue], Int[], Dict{Symbol,Any}())

mutable struct TTypeQualifiers <: Thrift.TMsg
  qualifiers::Dict{String,TTypeQualifierValue}
  TTypeQualifiers() = (o=new(); fillunset(o); o)
end # mutable struct TTypeQualifiers

mutable struct TPrimitiveTypeEntry <: Thrift.TMsg
  _type::Int32
  typeQualifiers::TTypeQualifiers
  TPrimitiveTypeEntry() = (o=new(); fillunset(o); o)
end # mutable struct TPrimitiveTypeEntry
meta(t::Type{TPrimitiveTypeEntry}) = meta(t, Symbol[:typeQualifiers], Int[], Dict{Symbol,Any}())

mutable struct TArrayTypeEntry <: Thrift.TMsg
  objectTypePtr::TTypeEntryPtr
  TArrayTypeEntry() = (o=new(); fillunset(o); o)
end # mutable struct TArrayTypeEntry

mutable struct TMapTypeEntry <: Thrift.TMsg
  keyTypePtr::TTypeEntryPtr
  valueTypePtr::TTypeEntryPtr
  TMapTypeEntry() = (o=new(); fillunset(o); o)
end # mutable struct TMapTypeEntry

mutable struct TStructTypeEntry <: Thrift.TMsg
  nameToTypePtr::Dict{String,TTypeEntryPtr}
  TStructTypeEntry() = (o=new(); fillunset(o); o)
end # mutable struct TStructTypeEntry

mutable struct TUnionTypeEntry <: Thrift.TMsg
  nameToTypePtr::Dict{String,TTypeEntryPtr}
  TUnionTypeEntry() = (o=new(); fillunset(o); o)
end # mutable struct TUnionTypeEntry

mutable struct TUserDefinedTypeEntry <: Thrift.TMsg
  typeClassName::String
  TUserDefinedTypeEntry() = (o=new(); fillunset(o); o)
end # mutable struct TUserDefinedTypeEntry

mutable struct TTypeEntry <: Thrift.TMsg
  primitiveEntry::TPrimitiveTypeEntry
  arrayEntry::TArrayTypeEntry
  mapEntry::TMapTypeEntry
  structEntry::TStructTypeEntry
  unionEntry::TUnionTypeEntry
  userDefinedTypeEntry::TUserDefinedTypeEntry
  TTypeEntry() = (o=new(); fillunset(o); o)
end # mutable struct TTypeEntry
meta(t::Type{TTypeEntry}) = meta(t, Symbol[:primitiveEntry,:arrayEntry,:mapEntry,:structEntry,:unionEntry,:userDefinedTypeEntry], Int[], Dict{Symbol,Any}())

mutable struct TTypeDesc <: Thrift.TMsg
  types::Vector{TTypeEntry}
  TTypeDesc() = (o=new(); fillunset(o); o)
end # mutable struct TTypeDesc

mutable struct TColumnDesc <: Thrift.TMsg
  columnName::String
  typeDesc::TTypeDesc
  position::Int32
  comment::String
  TColumnDesc() = (o=new(); fillunset(o); o)
end # mutable struct TColumnDesc
meta(t::Type{TColumnDesc}) = meta(t, Symbol[:comment], Int[], Dict{Symbol,Any}())

mutable struct TTableSchema <: Thrift.TMsg
  columns::Vector{TColumnDesc}
  TTableSchema() = (o=new(); fillunset(o); o)
end # mutable struct TTableSchema

mutable struct TBoolValue <: Thrift.TMsg
  value::Bool
  TBoolValue() = (o=new(); fillunset(o); o)
end # mutable struct TBoolValue
meta(t::Type{TBoolValue}) = meta(t, Symbol[:value], Int[], Dict{Symbol,Any}())

mutable struct TByteValue <: Thrift.TMsg
  value::UInt8
  TByteValue() = (o=new(); fillunset(o); o)
end # mutable struct TByteValue
meta(t::Type{TByteValue}) = meta(t, Symbol[:value], Int[], Dict{Symbol,Any}())

mutable struct TI16Value <: Thrift.TMsg
  value::Int16
  TI16Value() = (o=new(); fillunset(o); o)
end # mutable struct TI16Value
meta(t::Type{TI16Value}) = meta(t, Symbol[:value], Int[], Dict{Symbol,Any}())

mutable struct TI32Value <: Thrift.TMsg
  value::Int32
  TI32Value() = (o=new(); fillunset(o); o)
end # mutable struct TI32Value
meta(t::Type{TI32Value}) = meta(t, Symbol[:value], Int[], Dict{Symbol,Any}())

mutable struct TI64Value <: Thrift.TMsg
  value::Int64
  TI64Value() = (o=new(); fillunset(o); o)
end # mutable struct TI64Value
meta(t::Type{TI64Value}) = meta(t, Symbol[:value], Int[], Dict{Symbol,Any}())

mutable struct TDoubleValue <: Thrift.TMsg
  value::Float64
  TDoubleValue() = (o=new(); fillunset(o); o)
end # mutable struct TDoubleValue
meta(t::Type{TDoubleValue}) = meta(t, Symbol[:value], Int[], Dict{Symbol,Any}())

mutable struct TStringValue <: Thrift.TMsg
  value::String
  TStringValue() = (o=new(); fillunset(o); o)
end # mutable struct TStringValue
meta(t::Type{TStringValue}) = meta(t, Symbol[:value], Int[], Dict{Symbol,Any}())

mutable struct TColumnValue <: Thrift.TMsg
  boolVal::TBoolValue
  byteVal::TByteValue
  i16Val::TI16Value
  i32Val::TI32Value
  i64Val::TI64Value
  doubleVal::TDoubleValue
  stringVal::TStringValue
  TColumnValue() = (o=new(); fillunset(o); o)
end # mutable struct TColumnValue
meta(t::Type{TColumnValue}) = meta(t, Symbol[:boolVal,:byteVal,:i16Val,:i32Val,:i64Val,:doubleVal,:stringVal], Int[], Dict{Symbol,Any}())

mutable struct TRow <: Thrift.TMsg
  colVals::Vector{TColumnValue}
  TRow() = (o=new(); fillunset(o); o)
end # mutable struct TRow

mutable struct TBoolColumn <: Thrift.TMsg
  values::Vector{Bool}
  nulls::Vector{UInt8}
  TBoolColumn() = (o=new(); fillunset(o); o)
end # mutable struct TBoolColumn

mutable struct TByteColumn <: Thrift.TMsg
  values::Vector{UInt8}
  nulls::Vector{UInt8}
  TByteColumn() = (o=new(); fillunset(o); o)
end # mutable struct TByteColumn

mutable struct TI16Column <: Thrift.TMsg
  values::Vector{Int16}
  nulls::Vector{UInt8}
  TI16Column() = (o=new(); fillunset(o); o)
end # mutable struct TI16Column

mutable struct TI32Column <: Thrift.TMsg
  values::Vector{Int32}
  nulls::Vector{UInt8}
  TI32Column() = (o=new(); fillunset(o); o)
end # mutable struct TI32Column

mutable struct TI64Column <: Thrift.TMsg
  values::Vector{Int64}
  nulls::Vector{UInt8}
  TI64Column() = (o=new(); fillunset(o); o)
end # mutable struct TI64Column

mutable struct TDoubleColumn <: Thrift.TMsg
  values::Vector{Float64}
  nulls::Vector{UInt8}
  TDoubleColumn() = (o=new(); fillunset(o); o)
end # mutable struct TDoubleColumn

mutable struct TStringColumn <: Thrift.TMsg
  values::Vector{String}
  nulls::Vector{UInt8}
  TStringColumn() = (o=new(); fillunset(o); o)
end # mutable struct TStringColumn

mutable struct TBinaryColumn <: Thrift.TMsg
  values::Vector{Vector{UInt8}}
  nulls::Vector{UInt8}
  TBinaryColumn() = (o=new(); fillunset(o); o)
end # mutable struct TBinaryColumn

mutable struct TColumn <: Thrift.TMsg
  boolVal::TBoolColumn
  byteVal::TByteColumn
  i16Val::TI16Column
  i32Val::TI32Column
  i64Val::TI64Column
  doubleVal::TDoubleColumn
  stringVal::TStringColumn
  binaryVal::TBinaryColumn
  TColumn() = (o=new(); fillunset(o); o)
end # mutable struct TColumn
meta(t::Type{TColumn}) = meta(t, Symbol[:boolVal,:byteVal,:i16Val,:i32Val,:i64Val,:doubleVal,:stringVal,:binaryVal], Int[], Dict{Symbol,Any}())

mutable struct TRowSet <: Thrift.TMsg
  startRowOffset::Int64
  rows::Vector{TRow}
  columns::Vector{TColumn}
  binaryColumns::Vector{UInt8}
  columnCount::Int32
  TRowSet() = (o=new(); fillunset(o); o)
end # mutable struct TRowSet
meta(t::Type{TRowSet}) = meta(t, Symbol[:columns,:binaryColumns,:columnCount], Int[], Dict{Symbol,Any}())

mutable struct TStatus <: Thrift.TMsg
  statusCode::Int32
  infoMessages::Vector{String}
  sqlState::String
  errorCode::Int32
  errorMessage::String
  TStatus() = (o=new(); fillunset(o); o)
end # mutable struct TStatus
meta(t::Type{TStatus}) = meta(t, Symbol[:infoMessages,:sqlState,:errorCode,:errorMessage], Int[], Dict{Symbol,Any}())

mutable struct THandleIdentifier <: Thrift.TMsg
  guid::Vector{UInt8}
  secret::Vector{UInt8}
  THandleIdentifier() = (o=new(); fillunset(o); o)
end # mutable struct THandleIdentifier

mutable struct TSessionHandle <: Thrift.TMsg
  sessionId::THandleIdentifier
  TSessionHandle() = (o=new(); fillunset(o); o)
end # mutable struct TSessionHandle

mutable struct TOperationHandle <: Thrift.TMsg
  operationId::THandleIdentifier
  operationType::Int32
  hasResultSet::Bool
  modifiedRowCount::Float64
  TOperationHandle() = (o=new(); fillunset(o); o)
end # mutable struct TOperationHandle
meta(t::Type{TOperationHandle}) = meta(t, Symbol[:modifiedRowCount], Int[], Dict{Symbol,Any}())

mutable struct TOpenSessionReq <: Thrift.TMsg
  client_protocol::Int32
  username::String
  password::String
  configuration::Dict{String,String}
  TOpenSessionReq() = (o=new(); fillunset(o); o)
end # mutable struct TOpenSessionReq
meta(t::Type{TOpenSessionReq}) = meta(t, Symbol[:username,:password,:configuration], Int[], Dict{Symbol,Any}(:client_protocol => Int32(9)))

mutable struct TOpenSessionResp <: Thrift.TMsg
  status::TStatus
  serverProtocolVersion::Int32
  sessionHandle::TSessionHandle
  configuration::Dict{String,String}
  TOpenSessionResp() = (o=new(); fillunset(o); o)
end # mutable struct TOpenSessionResp
meta(t::Type{TOpenSessionResp}) = meta(t, Symbol[:sessionHandle,:configuration], Int[], Dict{Symbol,Any}(:serverProtocolVersion => Int32(9)))

mutable struct TSetClientInfoReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  configuration::Dict{String,String}
  TSetClientInfoReq() = (o=new(); fillunset(o); o)
end # mutable struct TSetClientInfoReq
meta(t::Type{TSetClientInfoReq}) = meta(t, Symbol[:configuration], Int[], Dict{Symbol,Any}())

mutable struct TSetClientInfoResp <: Thrift.TMsg
  status::TStatus
  TSetClientInfoResp() = (o=new(); fillunset(o); o)
end # mutable struct TSetClientInfoResp

mutable struct TCloseSessionReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  TCloseSessionReq() = (o=new(); fillunset(o); o)
end # mutable struct TCloseSessionReq

mutable struct TCloseSessionResp <: Thrift.TMsg
  status::TStatus
  TCloseSessionResp() = (o=new(); fillunset(o); o)
end # mutable struct TCloseSessionResp

mutable struct TGetInfoValue <: Thrift.TMsg
  stringValue::String
  smallIntValue::Int16
  integerBitmask::Int32
  integerFlag::Int32
  binaryValue::Int32
  lenValue::Int64
  TGetInfoValue() = (o=new(); fillunset(o); o)
end # mutable struct TGetInfoValue
meta(t::Type{TGetInfoValue}) = meta(t, Symbol[:stringValue,:smallIntValue,:integerBitmask,:integerFlag,:binaryValue,:lenValue], Int[], Dict{Symbol,Any}())

mutable struct TGetInfoReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  infoType::Int32
  TGetInfoReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetInfoReq

mutable struct TGetInfoResp <: Thrift.TMsg
  status::TStatus
  infoValue::TGetInfoValue
  TGetInfoResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetInfoResp

mutable struct TExecuteStatementReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  statement::String
  confOverlay::Dict{String,String}
  runAsync::Bool
  queryTimeout::Int64
  TExecuteStatementReq() = (o=new(); fillunset(o); o)
end # mutable struct TExecuteStatementReq
meta(t::Type{TExecuteStatementReq}) = meta(t, Symbol[:confOverlay,:runAsync,:queryTimeout], Int[], Dict{Symbol,Any}(:runAsync => false, :queryTimeout => Int64(0)))

mutable struct TExecuteStatementResp <: Thrift.TMsg
  status::TStatus
  operationHandle::TOperationHandle
  TExecuteStatementResp() = (o=new(); fillunset(o); o)
end # mutable struct TExecuteStatementResp
meta(t::Type{TExecuteStatementResp}) = meta(t, Symbol[:operationHandle], Int[], Dict{Symbol,Any}())

mutable struct TGetTypeInfoReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  TGetTypeInfoReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetTypeInfoReq

mutable struct TGetTypeInfoResp <: Thrift.TMsg
  status::TStatus
  operationHandle::TOperationHandle
  TGetTypeInfoResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetTypeInfoResp
meta(t::Type{TGetTypeInfoResp}) = meta(t, Symbol[:operationHandle], Int[], Dict{Symbol,Any}())

mutable struct TGetCatalogsReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  TGetCatalogsReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetCatalogsReq

mutable struct TGetCatalogsResp <: Thrift.TMsg
  status::TStatus
  operationHandle::TOperationHandle
  TGetCatalogsResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetCatalogsResp
meta(t::Type{TGetCatalogsResp}) = meta(t, Symbol[:operationHandle], Int[], Dict{Symbol,Any}())

mutable struct TGetSchemasReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  catalogName::TIdentifier
  schemaName::TPatternOrIdentifier
  TGetSchemasReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetSchemasReq
meta(t::Type{TGetSchemasReq}) = meta(t, Symbol[:catalogName,:schemaName], Int[], Dict{Symbol,Any}())

mutable struct TGetSchemasResp <: Thrift.TMsg
  status::TStatus
  operationHandle::TOperationHandle
  TGetSchemasResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetSchemasResp
meta(t::Type{TGetSchemasResp}) = meta(t, Symbol[:operationHandle], Int[], Dict{Symbol,Any}())

mutable struct TGetTablesReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  catalogName::TPatternOrIdentifier
  schemaName::TPatternOrIdentifier
  tableName::TPatternOrIdentifier
  tableTypes::Vector{String}
  TGetTablesReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetTablesReq
meta(t::Type{TGetTablesReq}) = meta(t, Symbol[:catalogName,:schemaName,:tableName,:tableTypes], Int[], Dict{Symbol,Any}())

mutable struct TGetTablesResp <: Thrift.TMsg
  status::TStatus
  operationHandle::TOperationHandle
  TGetTablesResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetTablesResp
meta(t::Type{TGetTablesResp}) = meta(t, Symbol[:operationHandle], Int[], Dict{Symbol,Any}())

mutable struct TGetTableTypesReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  TGetTableTypesReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetTableTypesReq

mutable struct TGetTableTypesResp <: Thrift.TMsg
  status::TStatus
  operationHandle::TOperationHandle
  TGetTableTypesResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetTableTypesResp
meta(t::Type{TGetTableTypesResp}) = meta(t, Symbol[:operationHandle], Int[], Dict{Symbol,Any}())

mutable struct TGetColumnsReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  catalogName::TIdentifier
  schemaName::TPatternOrIdentifier
  tableName::TPatternOrIdentifier
  columnName::TPatternOrIdentifier
  TGetColumnsReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetColumnsReq
meta(t::Type{TGetColumnsReq}) = meta(t, Symbol[:catalogName,:schemaName,:tableName,:columnName], Int[], Dict{Symbol,Any}())

mutable struct TGetColumnsResp <: Thrift.TMsg
  status::TStatus
  operationHandle::TOperationHandle
  TGetColumnsResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetColumnsResp
meta(t::Type{TGetColumnsResp}) = meta(t, Symbol[:operationHandle], Int[], Dict{Symbol,Any}())

mutable struct TGetFunctionsReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  catalogName::TIdentifier
  schemaName::TPatternOrIdentifier
  functionName::TPatternOrIdentifier
  TGetFunctionsReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetFunctionsReq
meta(t::Type{TGetFunctionsReq}) = meta(t, Symbol[:catalogName,:schemaName], Int[], Dict{Symbol,Any}())

mutable struct TGetFunctionsResp <: Thrift.TMsg
  status::TStatus
  operationHandle::TOperationHandle
  TGetFunctionsResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetFunctionsResp
meta(t::Type{TGetFunctionsResp}) = meta(t, Symbol[:operationHandle], Int[], Dict{Symbol,Any}())

mutable struct TGetPrimaryKeysReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  catalogName::TIdentifier
  schemaName::TIdentifier
  tableName::TIdentifier
  TGetPrimaryKeysReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetPrimaryKeysReq
meta(t::Type{TGetPrimaryKeysReq}) = meta(t, Symbol[:catalogName,:schemaName,:tableName], Int[], Dict{Symbol,Any}())

mutable struct TGetPrimaryKeysResp <: Thrift.TMsg
  status::TStatus
  operationHandle::TOperationHandle
  TGetPrimaryKeysResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetPrimaryKeysResp
meta(t::Type{TGetPrimaryKeysResp}) = meta(t, Symbol[:operationHandle], Int[], Dict{Symbol,Any}())

mutable struct TGetCrossReferenceReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  parentCatalogName::TIdentifier
  parentSchemaName::TIdentifier
  parentTableName::TIdentifier
  foreignCatalogName::TIdentifier
  foreignSchemaName::TIdentifier
  foreignTableName::TIdentifier
  TGetCrossReferenceReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetCrossReferenceReq
meta(t::Type{TGetCrossReferenceReq}) = meta(t, Symbol[:parentCatalogName,:parentSchemaName,:parentTableName,:foreignCatalogName,:foreignSchemaName,:foreignTableName], Int[], Dict{Symbol,Any}())

mutable struct TGetCrossReferenceResp <: Thrift.TMsg
  status::TStatus
  operationHandle::TOperationHandle
  TGetCrossReferenceResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetCrossReferenceResp
meta(t::Type{TGetCrossReferenceResp}) = meta(t, Symbol[:operationHandle], Int[], Dict{Symbol,Any}())

mutable struct TGetOperationStatusReq <: Thrift.TMsg
  operationHandle::TOperationHandle
  getProgressUpdate::Bool
  TGetOperationStatusReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetOperationStatusReq
meta(t::Type{TGetOperationStatusReq}) = meta(t, Symbol[:getProgressUpdate], Int[], Dict{Symbol,Any}())

mutable struct TProgressUpdateResp <: Thrift.TMsg
  headerNames::Vector{String}
  rows::Vector{Vector{String}}
  progressedPercentage::Float64
  status::Int32
  footerSummary::String
  startTime::Int64
  TProgressUpdateResp() = (o=new(); fillunset(o); o)
end # mutable struct TProgressUpdateResp

mutable struct TGetOperationStatusResp <: Thrift.TMsg
  status::TStatus
  operationState::Int32
  sqlState::String
  errorCode::Int32
  errorMessage::String
  taskStatus::String
  operationStarted::Int64
  operationCompleted::Int64
  hasResultSet::Bool
  progressUpdateResponse::TProgressUpdateResp
  numModifiedRows::Int64
  TGetOperationStatusResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetOperationStatusResp
meta(t::Type{TGetOperationStatusResp}) = meta(t, Symbol[:operationState,:sqlState,:errorCode,:errorMessage,:taskStatus,:operationStarted,:operationCompleted,:hasResultSet,:progressUpdateResponse,:numModifiedRows], Int[], Dict{Symbol,Any}())

mutable struct TCancelOperationReq <: Thrift.TMsg
  operationHandle::TOperationHandle
  TCancelOperationReq() = (o=new(); fillunset(o); o)
end # mutable struct TCancelOperationReq

mutable struct TCancelOperationResp <: Thrift.TMsg
  status::TStatus
  TCancelOperationResp() = (o=new(); fillunset(o); o)
end # mutable struct TCancelOperationResp

mutable struct TCloseOperationReq <: Thrift.TMsg
  operationHandle::TOperationHandle
  TCloseOperationReq() = (o=new(); fillunset(o); o)
end # mutable struct TCloseOperationReq

mutable struct TCloseOperationResp <: Thrift.TMsg
  status::TStatus
  TCloseOperationResp() = (o=new(); fillunset(o); o)
end # mutable struct TCloseOperationResp

mutable struct TGetResultSetMetadataReq <: Thrift.TMsg
  operationHandle::TOperationHandle
  TGetResultSetMetadataReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetResultSetMetadataReq

mutable struct TGetResultSetMetadataResp <: Thrift.TMsg
  status::TStatus
  schema::TTableSchema
  TGetResultSetMetadataResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetResultSetMetadataResp
meta(t::Type{TGetResultSetMetadataResp}) = meta(t, Symbol[:schema], Int[], Dict{Symbol,Any}())

mutable struct TFetchResultsReq <: Thrift.TMsg
  operationHandle::TOperationHandle
  orientation::Int32
  maxRows::Int64
  fetchType::Int16
  TFetchResultsReq() = (o=new(); fillunset(o); o)
end # mutable struct TFetchResultsReq
meta(t::Type{TFetchResultsReq}) = meta(t, Symbol[:fetchType], Int[], Dict{Symbol,Any}(:orientation => Int32(0), :fetchType => Int16(0)))

mutable struct TFetchResultsResp <: Thrift.TMsg
  status::TStatus
  hasMoreRows::Bool
  results::TRowSet
  TFetchResultsResp() = (o=new(); fillunset(o); o)
end # mutable struct TFetchResultsResp
meta(t::Type{TFetchResultsResp}) = meta(t, Symbol[:hasMoreRows,:results], Int[], Dict{Symbol,Any}())

mutable struct TGetDelegationTokenReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  owner::String
  renewer::String
  TGetDelegationTokenReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetDelegationTokenReq

mutable struct TGetDelegationTokenResp <: Thrift.TMsg
  status::TStatus
  delegationToken::String
  TGetDelegationTokenResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetDelegationTokenResp
meta(t::Type{TGetDelegationTokenResp}) = meta(t, Symbol[:delegationToken], Int[], Dict{Symbol,Any}())

mutable struct TCancelDelegationTokenReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  delegationToken::String
  TCancelDelegationTokenReq() = (o=new(); fillunset(o); o)
end # mutable struct TCancelDelegationTokenReq

mutable struct TCancelDelegationTokenResp <: Thrift.TMsg
  status::TStatus
  TCancelDelegationTokenResp() = (o=new(); fillunset(o); o)
end # mutable struct TCancelDelegationTokenResp

mutable struct TRenewDelegationTokenReq <: Thrift.TMsg
  sessionHandle::TSessionHandle
  delegationToken::String
  TRenewDelegationTokenReq() = (o=new(); fillunset(o); o)
end # mutable struct TRenewDelegationTokenReq

mutable struct TRenewDelegationTokenResp <: Thrift.TMsg
  status::TStatus
  TRenewDelegationTokenResp() = (o=new(); fillunset(o); o)
end # mutable struct TRenewDelegationTokenResp

mutable struct TGetQueryIdReq <: Thrift.TMsg
  operationHandle::TOperationHandle
  TGetQueryIdReq() = (o=new(); fillunset(o); o)
end # mutable struct TGetQueryIdReq

mutable struct TGetQueryIdResp <: Thrift.TMsg
  queryId::String
  TGetQueryIdResp() = (o=new(); fillunset(o); o)
end # mutable struct TGetQueryIdResp

abstract type TCLIServiceClientBase end


text:
# black box, uses score function estimator
function single_sample_gradient_estimate!(
        var_model::GenerativeFunction, var_model_args::Tuple,
        model::GenerativeFunction, model_args::Tuple, observations::ChoiceMap,
        scale_factor=1.)

    # sample from variational approximation
    trace = simulate(var_model, var_model_args)

    # compute learning signal
    constraints = merge(observations, get_choices(trace)) # TODO characterize what it means when not all var_model choices are in the model..
    (model_log_weight, _) = assess(model, model_args, constraints)
    log_weight = model_log_weight - get_score(trace)

    # accumulate the weighted gradient
    accumulate_param_gradients!(trace, nothing, log_weight * scale_factor)

    # unbiased estimate of objective function, and trace
    (log_weight, trace)
end

function vimco_geometric_baselines(log_weights)
    num_samples = length(log_weights)
    s = sum(log_weights)
    baselines = Vector{Float64}(undef, num_samples)
    for i=1:num_samples
        temp = log_weights[i]
        log_weights[i] = (s - log_weights[i]) / (num_samples - 1)
        baselines[i] = logsumexp(log_weights) - log(num_samples)
        log_weights[i] = temp
    end
    baselines
end

function logdiffexp(x, y)
    m = max(x, y)
    m + log(exp(x - m) - exp(y - m))
end

function vimco_arithmetic_baselines(log_weights)
    num_samples = length(log_weights)
    log_total_weight = logsumexp(log_weights)
    baselines = Vector{Float64}(undef, num_samples)
    for i=1:num_samples
        log_sum_f_without_i = logdiffexp(log_total_weight, log_weights[i])
        log_f_hat = log_sum_f_without_i - log(num_samples - 1)
        baselines[i] = logsumexp(log_sum_f_without_i, log_f_hat) - log(num_samples)
    end
    baselines
end

# black box, VIMCO gradient estimator
# for use in training models
function multi_sample_gradient_estimate!(
        var_model::GenerativeFunction, var_model_args::Tuple,
        model::GenerativeFunction, model_args::Tuple, observations::ChoiceMap,
        num_samples::Int, scale_factor=1., geometric=true)

    # sample from variational approximation multiple times
    traces = Vector{Any}(undef, num_samples)
    log_weights = Vector{Float64}(undef, num_samples)
    for i=1:num_samples
        traces[i] = simulate(var_model, var_model_args)
        constraints = merge(observations, get_choices(traces[i])) # TODO characterize as above
        model_weight, = assess(model, model_args, constraints)
        log_weights[i] = model_weight - get_score(traces[i])
    end

    # multi-sample log marginal likelihood estimate
    log_total_weight = logsumexp(log_weights)
    L = log_total_weight - log(num_samples)

    # baselines
    if geometric
        baselines = vimco_geometric_baselines(log_weights)
    else
        baselines = vimco_arithmetic_baselines(log_weights)
    end

    weights_normalized = exp.(log_weights .- log_total_weight)
    for i=1:num_samples
        learning_signal = (L - baselines[i]) - weights_normalized[i]
        accumulate_param_gradients!(traces[i], nothing, learning_signal * scale_factor)
    end

    # collection of traces and normalized importance weights, and estimate of
    # objective function
    (L, traces, weights_normalized)
end

"""
    (elbo_estimate, traces, elbo_history) = black_box_vi!(
        model::GenerativeFunction, args::Tuple,
        observations::ChoiceMap,
        var_model::GenerativeFunction, var_model_args::Tuple,
        update::ParamUpdate;
        iters=1000, samples_per_iter=100, verbose=false,
        callback=(iter, traces, elbo_estimate) -> nothing)

Fit the parameters of a generative function (`var_model`) to the posterior
distribution implied by the given model and observations using stochastic
gradient methods.
"""
function black_box_vi!(
        model::GenerativeFunction, model_args::Tuple,
        observations::ChoiceMap,
        var_model::GenerativeFunction, var_model_args::Tuple,
        update::ParamUpdate;
        iters=1000, samples_per_iter=100, verbose=false,
        callback=(iter, traces, elbo_estimate) -> nothing)

    traces = Vector{Any}(undef, samples_per_iter)
    elbo_history = Vector{Float64}(undef, iters)
    for iter=1:iters

        # compute gradient estimate and objective function estimate
        elbo_estimate = 0.
        # TODO multithread
        for sample=1:samples_per_iter
            (log_weight, trace) = single_sample_gradient_estimate!(
                var_model, var_model_args,
                model, model_args, observations, 1/samples_per_iter)
            elbo_estimate += (log_weight / samples_per_iter)

            # record the model trace
            traces[sample] = trace
        end
        elbo_history[iter] = elbo_estimate

        # print it
        verbose && println("iter $iter; est objective: $elbo_estimate")

        # callback
        callback(iter, traces, elbo_estimate)

        # do an update
        apply!(update)
    end

    (elbo_history[end], traces, elbo_history)
end

"""
    (iwelbo_estimate, traces, iwelbo_history) = black_box_vimco!(
        model::GenerativeFunction, args::Tuple,
        observations::ChoiceMap,
        var_model::GenerativeFunction, var_model_args::Tuple,
        update::ParamUpdate, num_samples::Int;
        iters=1000, samples_per_iter=100, verbose=false,
        callback=(iter, traces, elbo_estimate) -> nothing)

Fit the parameters of a generative function (`var_model`) to the posterior
distribution implied by the given model and observations using stochastic
gradient methods applied to the [Variational Inference with Monte Carlo
Objectives](https://arxiv.org/abs/1602.06725) lower bound on the marginal
likelihood.
"""
function black_box_vimco!(
        model::GenerativeFunction, model_args::Tuple,
        observations::ChoiceMap,
        var_model::GenerativeFunction, var_model_args::Tuple,
        update::ParamUpdate, num_samples::Int;
        iters=1000, samples_per_iter=100, verbose=false,
        geometric=true,
        callback=(iter, traces, elbo_estimate) -> nothing)

    traces = Vector{Any}(undef, samples_per_iter)
    iwelbo_history = Vector{Float64}(undef, iters)
    for iter=1:iters

        # compute gradient estimate and objective function estimate
        iwelbo_estimate = 0.
        for sample=1:samples_per_iter
            (est, original_traces, weights) = multi_sample_gradient_estimate!(
                var_model, var_model_args,
                model, model_args, observations, num_samples,
                1/samples_per_iter, geometric)
            iwelbo_estimate += (est / samples_per_iter)

            # record a model trace obtained by resampling from the weighted collection
            traces[sample] = original_traces[categorical(weights)]
        end
        iwelbo_history[iter] = iwelbo_estimate

        # print it
        verbose && println("iter $iter; est objective: $iwelbo_estimate")

        # callback
        callback(iter, traces, iwelbo_estimate)

        # do an update
        apply!(update)
    end

    (iwelbo_history[end], traces, iwelbo_history)
end

export black_box_vi!, black_box_vimco!

max_stars_repo_name: georgematheos/Gen

max_issues_repo_name: georgematheos/Gen

max_forks_repo_name: georgematheos/Gen


text:
# Set the variables
means = [620; 388; 583; 313]
@randomvariable(m, T[i = 1:4], mean = means[i])
@recoursevariable(m, Qc)
@variable(m, x)

# Define the constraints
@constraint(m, 0.67Qc - 2T[2] - x >= -100)
@constraint(m, -250 - T[2] == x)
@constraint(m, 1388.5 + 0.5Qc - 0.75T[1] - T[2] - T[3] <= 0.0)
@constraint(m, 2044 + Qc - 1.5T[1] - 2T[2] - T[3] <= 0.0)
@constraint(m, 2830 + Qc - 1.5T[1] - 2T[2] - T[3] - 2T[4] <= 0.0)
@constraint(m, -Qc + 1.5T[1] + 2T[2] + T[3] + 3T[4] <= 3153)
true


text:
"""
    Config(p"~/.playground/config.yml", root=p"~/.playground")

Stores various default playground environment settings including paths for
storing shared binaries and environments.
"""
type Config
    root::AbstractPath
    tmp::AbstractPath
    src::AbstractPath
    bin::AbstractPath
    share::AbstractPath
    default_playground_path::AbstractPath
    default_shell::AbstractString
    default_registry::AbstractString
    default_branch::AbstractString
    default_git_address::AbstractString
    default_git_revision::AbstractString
    isolated_shell_history::Bool
    isolated_julia_history::Bool

    function Config(kwargs::Dict)
        root = kwargs["root"]
        default_pg_path = abs(Path(kwargs["default_playground_path"]))

        new(
            root,
            join(root, p"tmp"),
            join(root, p"src"),
            join(root, p"bin"),
            join(root, p"share"),
            default_pg_path,
            get(kwargs, "default_shell", "/bin/bash"),
            get(kwargs, "default_registry", ""),
            get(kwargs, "default_branch", ""),
            kwargs["default_git_address"],
            kwargs["default_git_revision"],
            kwargs["isolated_shell_history"],
            kwargs["isolated_julia_history"],
        )
    end
end

function Config(config::AbstractString, root::AbstractPath)
    config_dict = configload(config)
    config_dict["root"] = root
    return Config(config_dict)
end

function Config{P<:AbstractPath}(file::P, root::P=configpath())
    Config(read(file), root)
end

function Config()
    config_file = join(configpath(), "config.yml")
    if exists(config_file)
        return Config(config_file)
    else
        return Config(Playground.DEFAULT_CONFIG, configpath())
    end
end

function init(config::Config)
    for p in (config.root, config.tmp, config.src, config.bin, config.share)
        mkdir(p; recursive=true, exist_ok=true)
    end
end

function configload(content)
    content_hash = hash(content)
    config_path = configpath()

    mkdir(config_path; recursive=true, exist_ok=true)
    config_cache_file = join(config_path, ".config-$(Base.VERSION_STRING).cache")

    if exists(config_cache_file)
        try
            cache = open(config_cache_file, "r") do f
                deserialize(f)
            end

            saved_hash = cache["hash"]
            debug(logger, "Checking hash: $content_hash == $saved_hash")
            if content_hash == saved_hash
                return cache
            end
        catch ex
            warn(logger, ex)
        end
    end

    new_cache = load(content)
    new_cache["hash"] = content_hash

    open(config_cache_file, "w") do f
        serialize(f, new_cache)
    end

    return new_cache
end

function configpath()
    default_path = join(home(), ".playground")
    alt_path = join(parent(parent(Path(@__FILE__))), p"deps", p"usr", p".playground")
    exists(default_path) ? default_path : alt_path
end

function envpath(config::Config)
    p = abs(join(cwd(), config.default_playground_path))
    debug(logger, "Using `default_playground_path`: $p")
    return p
end

envpath(config::Config, name::AbstractString) = abs(join(config.share, name))
envpath(config::Config, path::AbstractPath) = abs(path)

function envname(config::Config, path::AbstractPath)
    root_path = abs(path)
    name = ""

    for p in readdir(config.share)
        file_path = join(config.share, p)
        if islink(file_path)
            if abs(readlink(file_path)) == root_path
                name = basename(p)
                break
            end
        end
    end

    return name
end


text:
@testset "IO" begin
    @testset "FileExist" begin
        @test isfile("data/in.cfl")
        @test isfile("data/in.hdr")
    end

    @testset "ReadWrite" begin
        ## Read bart files
        println(pwd())
        filenameIn = "data/in"
        im = BartIO.readcfl(filenameIn)

        ## test writing to file
        filenameOut="data/out"
        BartIO.writecfl(filenameOut,im)
        ## Read back that files
        im2 = BartIO.readcfl(filenameOut)
        rm(filenameOut*".hdr")
        rm(filenameOut*".cfl")

        ## test
        @test im == im2

    end
end


text:
abstract type EventLikelihood{T<:Real} <: Likelihood{T} end

include("poisson.jl")
include("negativebinomial.jl")

""" Return the labels in a vector of vectors for multiple outputs"""
function treat_labels!(y::AbstractVector{T},likelihood::L) where {T,N,L<:EventLikelihood}
    @assert T<:Integer "For event count target(s) should be integers"
    return y,1,likelihood
end


text:
module JustJoshing

using Requires

include("p1_black_scholes_vanilla/black_scholes_vanilla.jl")

function __init__()
    @require CuArrays="3a865a2d-5b23-5a0f-bc46-62713ec82fae" include("cuda/mc_pricers.jl")
end

end


text:
export Experiment

using Dates
using ReinforcementLearningBase
using ReinforcementLearningCore
using .ReinforcementLearningEnvironments
using Flux
using BSON
using TensorBoardLogger
using Logging

function RLCore.Experiment(
    ::Val{:JuliaRL},
    ::Val{:BasicDQN},
    ::Val{:CartPole},
    ::Nothing;
    save_dir = nothing,
)
    if isnothing(save_dir)
        t = Dates.format(now(), "yyyymmddHHMMSS")
        save_dir = joinpath(pwd(), "checkpoints", "JuliaRL_BasicDQN_CartPole_$(t)")
    end

    lg = TBLogger(joinpath(save_dir, "tb_log"), min_level = Logging.Info)

    env = CartPoleEnv(; T = Float32, seed = 11)
    ns, na = length(rand(get_observation_space(env))), length(get_action_space(env))
    agent = Agent(
        policy = QBasedPolicy(
            learner = BasicDQNLearner(
                approximator = NeuralNetworkApproximator(
                    model = Chain(
                        Dense(ns, 128, relu; initW = seed_glorot_uniform(seed = 17)),
                        Dense(128, 128, relu; initW = seed_glorot_uniform(seed = 23)),
                        Dense(128, na; initW = seed_glorot_uniform(seed = 39)),
                    ) |> cpu,
                    optimizer = ADAM(),
                ),
                batch_size = 32,
                min_replay_history = 100,
                loss_func = huber_loss,
                seed = 22,
            ),
            explorer = EpsilonGreedyExplorer(
                kind = :exp,
                ϵ_stable = 0.01,
                decay_steps = 500,
                seed = 33,
            ),
        ),
        trajectory = CircularCompactSARTSATrajectory(
            capacity = 1000,
            state_type = Float32,
            state_size = (ns,),
        ),
    )

    stop_condition = StopAfterStep(10000)

    total_reward_per_episode = TotalRewardPerEpisode()
    time_per_step = TimePerStep()
    hook = ComposedHook(
        total_reward_per_episode,
        time_per_step,
        DoEveryNStep() do t, agent, env, obs
            with_logger(lg) do
                @info "training" loss = agent.policy.learner.loss
            end
        end,
        DoEveryNEpisode() do t, agent, env, obs
            with_logger(lg) do
                @info "training" reward = total_reward_per_episode.rewards[end]
            end
        end,
        DoEveryNStep(10000) do t, agent, env, obs
            RLCore.save(save_dir, agent)
            BSON.@save joinpath(save_dir, "stats.bson") total_reward_per_episode time_per_step
        end,
    )

    description = """
    This experiment uses three dense layers to approximate the Q value.
    The testing environment is CartPoleEnv.

    Agent and statistic info will be saved to: `$save_dir`
    You can also view the tensorboard logs with `tensorboard --logdir $(joinpath(save_dir, "tb_log"))`
    To load the agent and statistic info:
    ```
    agent = RLCore.load("$save_dir", Agent)
    BSON.@load joinpath("$save_dir", "stats.bson") total_reward_per_episode time_per_step
    ```
    """

    Experiment(agent, env, stop_condition, hook, description)
end

function RLCore.Experiment(
    ::Val{:JuliaRL},
    ::Val{:DQN},
    ::Val{:CartPole},
    ::Nothing;
    save_dir = nothing,
)
    if isnothing(save_dir)
        t = Dates.format(now(), "yyyymmddHHMMSS")
        save_dir = joinpath(pwd(), "checkpoints", "JuliaRL_DQN_CartPole_$(t)")
    end

    lg = TBLogger(joinpath(save_dir, "tb_log"), min_level = Logging.Info)

    env = CartPoleEnv(; T = Float32, seed = 11)
    ns, na = length(rand(get_observation_space(env))), length(get_action_space(env))

    agent = Agent(
        policy = QBasedPolicy(
            learner = DQNLearner(
                approximator = NeuralNetworkApproximator(
                    model = Chain(
                        Dense(ns, 128, relu; initW = seed_glorot_uniform(seed = 17)),
                        Dense(128, 128, relu; initW = seed_glorot_uniform(seed = 23)),
                        Dense(128, na; initW = seed_glorot_uniform(seed = 39)),
                    ) |> cpu,
                    optimizer = ADAM(),
                ),
                target_approximator = NeuralNetworkApproximator(
                    model = Chain(
                        Dense(ns, 128, relu; initW = seed_glorot_uniform(seed = 17)),
                        Dense(128, 128, relu; initW = seed_glorot_uniform(seed = 23)),
                        Dense(128, na; initW = seed_glorot_uniform(seed = 39)),
                    ) |> cpu,
                    optimizer = ADAM(),
                ),
                loss_func = huber_loss,
                stack_size = nothing,
                batch_size = 32,
                update_horizon = 1,
                min_replay_history = 100,
                update_freq = 1,
                target_update_freq = 100,
                seed = 22,
            ),
            explorer = EpsilonGreedyExplorer(
                kind = :exp,
                ϵ_stable = 0.01,
                decay_steps = 500,
                seed = 33,
            ),
        ),
        trajectory = CircularCompactSARTSATrajectory(
            capacity = 1000,
            state_type = Float32,
            state_size = (ns,),
        ),
    )

    stop_condition = StopAfterStep(10_000)

    total_reward_per_episode = TotalRewardPerEpisode()
    time_per_step = TimePerStep()
    hook = ComposedHook(
        total_reward_per_episode,
        time_per_step,
        DoEveryNStep() do t, agent, env, obs
            if agent.policy.learner.update_step % agent.policy.learner.update_freq == 0
                with_logger(lg) do
                    @info "training" loss = agent.policy.learner.loss
                end
            end
        end,
        DoEveryNStep(10000) do t, agent, env, obs
            RLCore.save(save_dir, agent)
            BSON.@save joinpath(save_dir, "stats.bson") total_reward_per_episode time_per_step
        end,
    )

    description = """
    This experiment uses the `DQNLearner` method with three dense layers to approximate the Q value.
    The testing environment is CartPoleEnv.

    Agent and statistic info will be saved to: `$save_dir`
    You can also view the tensorboard logs with `tensorboard --logdir $(joinpath(save_dir, "tb_log"))`
    To load the agent and statistic info:

    ```
    agent = RLCore.load("$save_dir", Agent)
    BSON.@load joinpath("$save_dir", "stats.bson") total_reward_per_episode time_per_step
    ```
    """

    Experiment(agent, env, stop_condition, hook, description)
end

function RLCore.Experiment(
    ::Val{:JuliaRL},
    ::Val{:PrioritizedDQN},
    ::Val{:CartPole},
    ::Nothing;
    save_dir = nothing,
)
    if isnothing(save_dir)
        t = Dates.format(now(), "yyyymmddHHMMSS")
        save_dir = joinpath(pwd(), "checkpoints", "JuliaRL_PrioritizedDQN_CartPole_$(t)")
    end

    lg = TBLogger(joinpath(save_dir, "tb_log"), min_level = Logging.Info)

    env = CartPoleEnv(; T = Float32, seed = 11)
    ns, na = length(rand(get_observation_space(env))), length(get_action_space(env))

    agent = Agent(
        policy = QBasedPolicy(
            learner = PrioritizedDQNLearner(
                approximator = NeuralNetworkApproximator(
                    model = Chain(
                        Dense(ns, 128, relu; initW = seed_glorot_uniform(seed = 17)),
                        Dense(128, 128, relu; initW = seed_glorot_uniform(seed = 23)),
                        Dense(128, na; initW = seed_glorot_uniform(seed = 39)),
                    ) |> cpu,
                    optimizer = ADAM(),
                ),
                target_approximator = NeuralNetworkApproximator(
                    model = Chain(
                        Dense(ns, 128, relu; initW = seed_glorot_uniform(seed = 17)),
                        Dense(128, 128, relu; initW = seed_glorot_uniform(seed = 23)),
                        Dense(128, na; initW = seed_glorot_uniform(seed = 39)),
                    ) |> cpu,
                    optimizer = ADAM(),
                ),
                loss_func = huber_loss_unreduced,
                stack_size = nothing,
                batch_size = 32,
                update_horizon = 1,
                min_replay_history = 100,
                update_freq = 1,
                target_update_freq = 100,
                seed = 22,
            ),
            explorer = EpsilonGreedyExplorer(
                kind = :exp,
                ϵ_stable = 0.01,
                decay_steps = 500,
                seed = 33,
            ),
        ),
        trajectory = CircularCompactPSARTSATrajectory(
            capacity = 1000,
            state_type = Float32,
            state_size = (ns,),
        ),
    )

    stop_condition = StopAfterStep(10_000)

    total_reward_per_episode = TotalRewardPerEpisode()
    time_per_step = TimePerStep()
    hook = ComposedHook(
        total_reward_per_episode,
        time_per_step,
        DoEveryNStep() do t, agent, env, obs
            if agent.policy.learner.update_step % agent.policy.learner.update_freq == 0
                with_logger(lg) do
                    @info "training" loss = agent.policy.learner.loss
                end
            end
        end,
        DoEveryNStep(10000) do t, agent, env, obs
            RLCore.save(save_dir, agent)
            BSON.@save joinpath(save_dir, "stats.bson") total_reward_per_episode time_per_step
        end,
    )

    description = """
    This experiment uses the `PrioritizedDQNLearner` method with three dense layers to approximate the Q value.
    The testing environment is CartPoleEnv.

    Agent and statistic info will be saved to: `$save_dir`
    You can also view the tensorboard logs with `tensorboard --logdir $(joinpath(save_dir, "tb_log"))`
    To load the agent and statistic info:

    ```
    agent = RLCore.load("$save_dir", Agent)
    BSON.@load joinpath("$save_dir", "stats.bson") total_reward_per_episode time_per_step
    ```
    """

    Experiment(agent, env, stop_condition, hook, description)
end

function RLCore.Experiment(
    ::Val{:JuliaRL},
    ::Val{:Rainbow},
    ::Val{:CartPole},
    ::Nothing;
    save_dir = nothing,
)
    if isnothing(save_dir)
        t = Dates.format(now(), "yyyymmddHHMMSS")
        save_dir = joinpath(pwd(), "checkpoints", "JuliaRL_Rainbow_CartPole_$(t)")
    end

    lg = TBLogger(joinpath(save_dir, "tb_log"), min_level = Logging.Info)

    env = CartPoleEnv(; T = Float32, seed = 11)
    ns, na = length(rand(get_observation_space(env))), length(get_action_space(env))

    n_atoms = 51
    agent = Agent(
        policy = QBasedPolicy(
            learner = RainbowLearner(
                approximator = NeuralNetworkApproximator(
                    model = Chain(
                        Dense(ns, 128, relu; initW = seed_glorot_uniform(seed = 17)),
                        Dense(128, 128, relu; initW = seed_glorot_uniform(seed = 23)),
                        Dense(128, na * n_atoms; initW = seed_glorot_uniform(seed = 39)),
                    ) |> cpu,
                    optimizer = ADAM(0.0005),
                ),
                target_approximator = NeuralNetworkApproximator(
                    model = Chain(
                        Dense(ns, 128, relu; initW = seed_glorot_uniform(seed = 17)),
                        Dense(128, 128, relu; initW = seed_glorot_uniform(seed = 23)),
                        Dense(128, na * n_atoms; initW = seed_glorot_uniform(seed = 39)),
                    ) |> cpu,
                    optimizer = ADAM(0.0005),
                ),
                n_actions = na,
                n_atoms = n_atoms,
                Vₘₐₓ = 200.0f0,
                Vₘᵢₙ = 0.0f0,
                update_freq = 1,
                γ = 0.99f0,
                update_horizon = 1,
                batch_size = 32,
                stack_size = nothing,
                min_replay_history = 100,
                loss_func = logitcrossentropy_unreduced,
                target_update_freq = 100,
                seed = 22,
            ),
            explorer = EpsilonGreedyExplorer(
                kind = :exp,
                ϵ_stable = 0.01,
                decay_steps = 500,
                seed = 33,
            ),
        ),
        trajectory = CircularCompactPSARTSATrajectory(
            capacity = 1000,
            state_type = Float32,
            state_size = (ns,),
        ),
    )

    stop_condition = StopAfterStep(10_000)

    total_reward_per_episode = TotalRewardPerEpisode()
    time_per_step = TimePerStep()
    hook = ComposedHook(
        total_reward_per_episode,
        time_per_step,
        DoEveryNStep() do t, agent, env, obs
            if agent.policy.learner.update_step % agent.policy.learner.update_freq == 0
                with_logger(lg) do
                    @info "training" loss = agent.policy.learner.loss
                end
            end
        end,
        DoEveryNStep(10000) do t, agent, env, obs
            RLCore.save(save_dir, agent)
            BSON.@save joinpath(save_dir, "stats.bson") total_reward_per_episode time_per_step
        end,
    )

    description = """
    This experiment uses the `RainbowLearner` method with three dense layers to approximate the distributed Q value.
    The testing environment is CartPoleEnv.

    Agent and statistic info will be saved to: `$save_dir`
    You can also view the tensorboard logs with `tensorboard --logdir $(joinpath(save_dir, "tb_log"))`
    To load the agent and statistic info:

    ```
    agent = RLCore.load("$save_dir", Agent)
    BSON.@load joinpath("$save_dir", "stats.bson") total_reward_per_episode time_per_step
    ```
    """

    Experiment(agent, env, stop_condition, hook, description)
end

function RLCore.Experiment(
    ::Val{:JuliaRL},
    ::Val{:IQN},
    ::Val{:CartPole},
    ::Nothing;
    save_dir = nothing,
)
    if isnothing(save_dir)
        t = Dates.format(now(), "yyyymmddHHMMSS")
        save_dir = joinpath(pwd(), "checkpoints", "JuliaRL_IQN_CartPole_$(t)")
    end

    lg = TBLogger(joinpath(save_dir, "tb_log"), min_level = Logging.Info)

    env = CartPoleEnv(; T = Float32, seed = 111)
    ns, na = length(rand(get_observation_space(env))), length(get_action_space(env))

    init = seed_glorot_uniform(seed = 17)
    Nₑₘ = 16
    n_hidden = 64
    κ = 1.0f0

    nn_creator() =
        ImplicitQuantileNet(
            ψ = Dense(ns, n_hidden, relu; initW = init),
            ϕ = Dense(Nₑₘ, n_hidden, relu; initW = init),
            header = Dense(n_hidden, na; initW = init),
        ) |> cpu

    agent = Agent(
        policy = QBasedPolicy(
            learner = IQNLearner(
                approximator = NeuralNetworkApproximator(
                    model = nn_creator(),
                    optimizer = ADAM(0.001),
                ),
                target_approximator = NeuralNetworkApproximator(model = nn_creator()),
                κ = κ,
                N = 8,
                N′ = 8,
                Nₑₘ = Nₑₘ,
                K = 32,
                γ = 0.99f0,
                stack_size = nothing,
                batch_size = 32,
                update_horizon = 1,
                min_replay_history = 100,
                update_freq = 1,
                target_update_freq = 100,
                default_priority = 1.0f2,
                seed = 123,
                device_seed = 321,
            ),
            explorer = EpsilonGreedyExplorer(
                kind = :exp,
                ϵ_stable = 0.01,
                decay_steps = 500,
                seed = 33,
            ),
        ),
        trajectory = CircularCompactPSARTSATrajectory(
            capacity = 1000,
            state_type = Float32,
            state_size = (ns,),
        ),
    )

    stop_condition = StopAfterStep(10_000)

    total_reward_per_episode = TotalRewardPerEpisode()
    time_per_step = TimePerStep()
    hook = ComposedHook(
        total_reward_per_episode,
        time_per_step,
        DoEveryNStep() do t, agent, env, obs
            if agent.policy.learner.update_step % agent.policy.learner.update_freq == 0
                with_logger(lg) do
                    @info "training" loss = agent.policy.learner.loss
                end
            end
        end,
        DoEveryNStep(10000) do t, agent, env, obs
            RLCore.save(save_dir, agent)
            BSON.@save joinpath(save_dir, "stats.bson") total_reward_per_episode time_per_step
        end,
    )

    description = """
    This experiment uses the `IQNLearner` method with a `ImplicitQuantileNet`.
    The testing environment is CartPoleEnv.

    Agent and statistic info will be saved to: `$save_dir`
    You can also view the tensorboard logs with `tensorboard --logdir $(joinpath(save_dir, "tb_log"))`
    To load the agent and statistic info:

    ```
    agent = RLCore.load("$save_dir", Agent)
    BSON.@load joinpath("$save_dir", "stats.bson") total_reward_per_episode time_per_step
    ```
    """

    Experiment(agent, env, stop_condition, hook, description)
end

function RLCore.Experiment(
    ::Val{:JuliaRL},
    ::Val{:A2C},
    ::Val{:CartPole},
    ::Nothing;
    save_dir = nothing,
)
    N_ENV = 16
    UPDATE_FREQ = 10
    env = MultiThreadEnv([CartPoleEnv(; T = Float32, seed = i) for i in 1:N_ENV])
    ns, na = length(rand(get_observation_space(env[1]))), length(get_action_space(env[1]))
    RLBase.reset!(env, is_force = true)
    agent = Agent(
        policy = QBasedPolicy(
            learner = A2CLearner(
                approximator = ActorCritic(
                    actor = Chain(
                        Dense(ns, 256, relu; initW = seed_glorot_uniform(seed = 17)),
                        Dense(256, na; initW = seed_glorot_uniform(seed = 23)),
                    ),
                    critic = Chain(
                        Dense(ns, 256, relu; initW = seed_glorot_uniform(seed = 29)),
                        Dense(256, 1; initW = seed_glorot_uniform(seed = 29)),
                    ),
                    optimizer = ADAM(1e-3),
                ) |> cpu,
                γ = 0.99f0,
                actor_loss_weight = 1.0f0,
                critic_loss_weight = 0.5f0,
                entropy_loss_weight = 0.001f0,
            ),
            explorer = BatchExplorer(GumbelSoftmaxExplorer()),#= seed = nothing =#
        ),
        trajectory = CircularCompactSARTSATrajectory(;
            capacity = UPDATE_FREQ,
            state_type = Float32,
            state_size = (ns, N_ENV),
            action_type = Int,
            action_size = (N_ENV,),
            reward_type = Float32,
            reward_size = (N_ENV,),
            terminal_type = Bool,
            terminal_size = (N_ENV,),
        ),
    )

    hook = TotalBatchRewardPerEpisode(N_ENV)
    stop_condition = StopAfterStep(100000)
    Experiment(agent, env, stop_condition, hook, "# A2C with CartPole")
end

function RLCore.Experiment(
    ::Val{:JuliaRL},
    ::Val{:A2CGAE},
    ::Val{:CartPole},
    ::Nothing;
    save_dir = nothing,
)
    N_ENV = 16
    UPDATE_FREQ = 10
    env = MultiThreadEnv([CartPoleEnv(; T = Float32, seed = i) for i in 1:N_ENV])
    ns, na = length(rand(get_observation_space(env[1]))), length(get_action_space(env[1]))
    RLBase.reset!(env, is_force = true)
    agent = Agent(
        policy = QBasedPolicy(
            learner = A2CGAELearner(
                approximator = ActorCritic(
                    actor = NeuralNetworkApproximator(
                        model = Chain(
                            Dense(ns, 256, relu; initW = seed_glorot_uniform(seed = 17)),
                            Dense(256, na; initW = seed_glorot_uniform(seed = 23)),
                        ),
                        optimizer = ADAM(1e-3),
                    ),
                    critic = NeuralNetworkApproximator(
                        model = Chain(
                            Dense(ns, 256, relu; initW = seed_glorot_uniform(seed = 29)),
                            Dense(256, 1; initW = seed_glorot_uniform(seed = 29)),
                        ),
                        optimizer = ADAM(1e-3),
                    ),
                ) |> cpu,
                γ = 0.99f0,
                λ = 0.97f0,
                actor_loss_weight = 1.0f0,
                critic_loss_weight = 0.5f0,
                entropy_loss_weight = 0.001f0,
            ),
            explorer = BatchExplorer(GumbelSoftmaxExplorer(;)), #= seed = nothing =#
        ),
        trajectory = CircularCompactSARTSATrajectory(;
            capacity = UPDATE_FREQ,
            state_type = Float32,
            state_size = (ns, N_ENV),
            action_type = Int,
            action_size = (N_ENV,),
            reward_type = Float32,
            reward_size = (N_ENV,),
            terminal_type = Bool,
            terminal_size = (N_ENV,),
        ),
    )
    Experiment(
        agent,
        env,
        StopAfterStep(100000),
        TotalBatchRewardPerEpisode(N_ENV),
        "# A2CGAE with CartPole",
    )
end

function RLCore.Experiment(::Val{:JuliaRL}, ::Val{:DDPG}, ::Val{:Pendulum}, ::Nothing;)
    inner_env = PendulumEnv(T = Float32, seed = 9231)
    action_space = get_action_space(inner_env)
    low = action_space.low
    high = action_space.high
    ns = length(rand(get_observation_space(inner_env)))

    env = WrappedEnv(;
        env = inner_env,
        postprocessor = ((x,),) -> (low + (x + 1) * 0.5 * (high - low),), # rescale [-1, 1] -> (low, high)
    )

    init = seed_glorot_uniform(seed = 17)

    create_actor() = Chain(
        Dense(ns, 256, relu; initW = init),
        Dense(256, 256, relu; initW = init),
        Dense(256, 1, tanh; initW = init),
    )

    create_critic() = Chain(
        Dense(ns + 1, 256, relu; initW = init),
        Dense(256, 256, relu; initW = init),
        Dense(256, 1; initW = init),
    )

    agent = Agent(
        policy = DDPGPolicy(
            behavior_actor = NeuralNetworkApproximator(
                model = create_actor(),
                optimizer = ADAM(),
            ),
            behavior_critic = NeuralNetworkApproximator(
                model = create_critic(),
                optimizer = ADAM(),
            ),
            target_actor = NeuralNetworkApproximator(
                model = create_actor(),
                optimizer = ADAM(),
            ),
            target_critic = NeuralNetworkApproximator(
                model = create_critic(),
                optimizer = ADAM(),
            ),
            γ = 0.99f0,
            ρ = 0.995f0,
            batch_size = 64,
            start_steps = 1000,
            start_policy = RandomPolicy(ContinuousSpace(-1.0, 1.0); seed = 923),
            update_after = 1000,
            update_every = 1,
            act_limit = 1.0,
            act_noise = 0.1,
            seed = 131,
        ),
        trajectory = CircularCompactSARTSATrajectory(
            capacity = 10000,
            state_type = Float32,
            state_size = (ns,),
            action_type = Float32,
        ),
    )

    description = """
    # Play Pendulum with DDPG
    """

    Experiment(agent, env, StopAfterStep(10000), TotalRewardPerEpisode(), description)
end

function RLCore.Experiment(::Val{:JuliaRL}, ::Val{:PPO}, ::Val{:CartPole}, ::Nothing;)
    N_ENV = 8
    UPDATE_FREQ = 16
    env = MultiThreadEnv([CartPoleEnv(; T = Float32, seed = i) for i in 1:N_ENV])
    ns, na = length(rand(get_observation_space(env[1]))), length(get_action_space(env[1]))
    RLBase.reset!(env, is_force = true)
    agent = Agent(
        policy = QBasedPolicy(
            learner = PPOLearner(
                approximator = ActorCritic(
                    actor = NeuralNetworkApproximator(
                        model = Chain(
                            Dense(ns, 256, relu; initW = seed_glorot_uniform(seed = 17)),
                            Dense(256, na; initW = seed_glorot_uniform(seed = 23)),
                        ),
                        optimizer = ADAM(1e-3),
                    ),
                    critic = NeuralNetworkApproximator(
                        model = Chain(
                            Dense(ns, 256, relu; initW = seed_glorot_uniform(seed = 29)),
                            Dense(256, 1; initW = seed_glorot_uniform(seed = 29)),
                        ),
                        optimizer = ADAM(1e-3),
                    ),
                ) |> cpu,
                γ = 0.99f0,
                λ = 0.95f0,
                clip_range = 0.1f0,
                max_grad_norm = 0.5f0,
                n_epochs = 4,
                n_microbatches = 4,
                actor_loss_weight = 1.0f0,
                critic_loss_weight = 0.5f0,
                entropy_loss_weight = 0.001f0,
            ),
            explorer = BatchExplorer(GumbelSoftmaxExplorer(; seed = 1)),
        ),
        trajectory = PPOTrajectory(;
            capacity = 32,
            state_type = Float32,
            state_size = (ns, N_ENV),
            action_type = Int,
            action_size = (N_ENV,),
            action_log_prob_type = Float32,
            action_log_prob_size = (N_ENV,),
            reward_type = Float32,
            reward_size = (N_ENV,),
            terminal_type = Bool,
            terminal_size = (N_ENV,),
        ),
    )
    Experiment(
        agent,
        env,
        StopAfterStep(100000),
        TotalBatchRewardPerEpisode(N_ENV),
        "# PPO with CartPole",
    )
end

function RLCore.Experiment(
    ::Val{:JuliaRL},
    ::Val{:BasicDQN},
    ::Val{:MountainCar},
    ::Nothing;
    save_dir = nothing,
)
    if isnothing(save_dir)
        t = Dates.format(now(), "yyyymmddHHMMSS")
        save_dir = joinpath(pwd(), "checkpoints", "JuliaRL_BasicDQN_MountainCar_$(t)")
    end

    lg = TBLogger(joinpath(save_dir, "tb_log"), min_level = Logging.Info)

    env = MountainCarEnv(; T = Float32, max_steps = 5000, seed = 11)
    ns, na = length(rand(get_observation_space(env))), length(get_action_space(env))
    agent = Agent(
        policy = QBasedPolicy(
            learner = BasicDQNLearner(
                approximator = NeuralNetworkApproximator(
                    model = Chain(
                        Dense(ns, 64, relu; initW = seed_glorot_uniform(seed = 17)),
                        Dense(64, 64, relu; initW = seed_glorot_uniform(seed = 23)),
                        Dense(64, na; initW = seed_glorot_uniform(seed = 39)),
                    ) |> cpu,
                    optimizer = ADAM(),
                ),
                batch_size = 32,
                min_replay_history = 100,
                loss_func = huber_loss,
                seed = 22,
            ),
            explorer = EpsilonGreedyExplorer(
                kind = :exp,
                ϵ_stable = 0.01,
                decay_steps = 500,
                seed = 33,
            ),
        ),
        trajectory = CircularCompactSARTSATrajectory(
            capacity = 50000,
            state_type = Float32,
            state_size = (ns,),
        ),
    )

    stop_condition = StopAfterStep(40000)

    total_reward_per_episode = TotalRewardPerEpisode()
    time_per_step = TimePerStep()
    hook = ComposedHook(
        total_reward_per_episode,
        time_per_step,
        DoEveryNStep() do t, agent, env, obs
            with_logger(lg) do
                @info "training" loss = agent.policy.learner.loss
            end
        end,
        DoEveryNEpisode() do t, agent, env, obs
            with_logger(lg) do
                @info "training" reward = total_reward_per_episode.rewards[end]
            end
        end,
        DoEveryNStep(10000) do t, agent, env, obs
            RLCore.save(save_dir, agent)
            BSON.@save joinpath(save_dir, "stats.bson") total_reward_per_episode time_per_step
        end,
    )

    description = """
    This experiment uses three dense layers to approximate the Q value.
    The testing environment is MountainCarEnv.

    Agent and statistic info will be saved to: `$save_dir`
    You can also view the tensorboard logs with `tensorboard --logdir $(joinpath(save_dir, "tb_log"))`
    To load the agent and statistic info:
    ```
    agent = RLCore.load("$save_dir", Agent)
    BSON.@load joinpath("$save_dir", "stats.bson") total_reward_per_episode time_per_step
    ```
    """

    Experiment(agent, env, stop_condition, hook, description)
end

function RLCore.Experiment(
    ::Val{:JuliaRL},
    ::Val{:DQN},
    ::Val{:MountainCar},
    ::Nothing;
    save_dir = nothing,
)
    if isnothing(save_dir)
        t = Dates.format(now(), "yyyymmddHHMMSS")
        save_dir = joinpath(pwd(), "checkpoints", "JuliaRL_DQN_MountainCar_$(t)")
    end

    lg = TBLogger(joinpath(save_dir, "tb_log"), min_level = Logging.Info)

    env = MountainCarEnv(; T = Float32, max_steps = 5000, seed = 11)
    ns, na = length(rand(get_observation_space(env))), length(get_action_space(env))

    agent = Agent(
        policy = QBasedPolicy(
            learner = DQNLearner(
                approximator = NeuralNetworkApproximator(
                    model = Chain(
                        Dense(ns, 64, relu; initW = seed_glorot_uniform(seed = 17)),
                        Dense(64, 64, relu; initW = seed_glorot_uniform(seed = 23)),
                        Dense(64, na; initW = seed_glorot_uniform(seed = 39)),
                    ) |> cpu,
                    optimizer = ADAM(),
                ),
                target_approximator = NeuralNetworkApproximator(
                    model = Chain(
                        Dense(ns, 64, relu; initW = seed_glorot_uniform(seed = 17)),
                        Dense(64, 64, relu; initW = seed_glorot_uniform(seed = 23)),
                        Dense(64, na; initW = seed_glorot_uniform(seed = 39)),
                    ) |> cpu,
                    optimizer = ADAM(),
                ),
                loss_func = huber_loss,
                stack_size = nothing,
                batch_size = 32,
                update_horizon = 1,
                min_replay_history = 100,
                update_freq = 1,
                target_update_freq = 100,
                seed = 22,
            ),
            explorer = EpsilonGreedyExplorer(
                kind = :exp,
                ϵ_stable = 0.01,
                decay_steps = 500,
                seed = 33,
            ),
        ),
        trajectory = CircularCompactSARTSATrajectory(
            capacity = 50000,
            state_type = Float32,
            state_size = (ns,),
        ),
    )

    stop_condition = StopAfterStep(40_000)

    total_reward_per_episode = TotalRewardPerEpisode()
    time_per_step = TimePerStep()
    hook = ComposedHook(
        total_reward_per_episode,
        time_per_step,
        DoEveryNStep() do t, agent, env, obs
            if agent.policy.learner.update_step % agent.policy.learner.update_freq == 0
                with_logger(lg) do
                    @info "training" loss = agent.policy.learner.loss
                end
            end
        end,
        DoEveryNStep(10000) do t, agent, env, obs
            RLCore.save(save_dir, agent)
            BSON.@save joinpath(save_dir, "stats.bson") total_reward_per_episode time_per_step
        end,
    )

    description = """
    This experiment uses the `DQNLearner` method with three dense layers to approximate the Q value.
    The testing environment is MountainCarEnv.

    Agent and statistic info will be saved to: `$save_dir`
    You can also view the tensorboard logs with `tensorboard --logdir $(joinpath(save_dir, "tb_log"))`
    To load the agent and statistic info:

    ```
    agent = RLCore.load("$save_dir", Agent)
    BSON.@load joinpath("$save_dir", "stats.bson") total_reward_per_episode time_per_step
    ```
    """

    Experiment(agent, env, stop_condition, hook, description)
end


text:
module Ramnit
mutable struct RANDINT
    seed
end

function rand_int_modulus!(r, modulus)
    ix = r.seed
    ix = 16807*(ix % 127773) - 2836*trunc(Int64, ix/127773) & 0xFFFFFFFF
    r.seed = ix
    return ix % modulus
end

function gen_one(seed=0x123abc12, tld="")
    domain = ""
    r = RANDINT(seed)
    seed_a = r.seed
    domain_len = rand_int_modulus!(r,12) + 8
    seed_b = r.seed
    for i in 1:domain_len
        domain *= 'a' + rand_int_modulus!(r,25)
    end
    domain *= tld
    return domain
end

function gen_many(cnt=100)
    res = []
    r = RANDINT(0x123abc12)
    for _ in 1:cnt
        seed_a = r.seed
        domain_len = rand_int_modulus!(r,12) + 8
        seed_b = r.seed
        domain = ""
        for i in 1:domain_len
            domain *= 'a' + rand_int_modulus!(r,25)
        end
        m = seed_a*seed_b
        r.seed = (m + trunc(Int64, m/(2^32))) % 2^32
        res =[res..., domain]
    end
    return res
end

end  # module Ramnit


text:
using ITensors,
      Test

@testset "SiteSet" begin

  N = 10

  @testset "Star in operator strings" begin
    sites = spinHalfSites(N)
    @test_throws ArgumentError op(sites, "Sp", 1)
    @test sites[1] isa Index
    Sz = op(sites,"Sz",2)
    SzSz = op(sites,"Sz * Sz",2)
    @test SzSz ≈ multSiteOps(Sz,Sz)
    Sy = op(sites,"Sy",2)
    SySy = op(sites,"Sy * Sy",2)
    @test SySy ≈ multSiteOps(Sy,Sy)
    str = split(sprint(show, sites), '\n')
    @test str[1] == "SiteSet"
    @test length(str) == N + 2

    sites = spinOneSites(N)
    @test_throws ArgumentError op(sites, "Sp", 1)
    Sz = op(sites,"Sz",2)
    SzSz = op(sites,"Sz * Sz",2)
    @test SzSz ≈ multSiteOps(Sz,Sz)
    Sy = op(sites,"Sy",2)
    SySy = op(sites,"Sy * Sy",2)
    @test SySy ≈ multSiteOps(Sy,Sy)
  end
  @test_throws ArgumentError ITensors.operator(ITensors.BasicSite(2), "aiodhfaiohf")
  @test length(SiteSet()) == 0
end


text:
function builddispatchmodel(capacity, transmissioncapacity; optionlist...)
    options, hourinfo, sets, params = buildsetsparams(; optionlist...)
    return builddispatchvarsmodel(capacity, transmissioncapacity, options, hourinfo, sets, params)
end

function builddispatchvarsmodel(capacity, transmissioncapacity, options, hourinfo, sets, params)
    println("\nBuilding model...")
    modelname = initjumpmodel(options)
    print("  - variables:   ")
    @time vars = makedispatchvariables(modelname, sets)
    print("  - extra bounds:")
    @time setdispatchbounds(capacity, transmissioncapacity, sets, params, vars, hourinfo, options)
    print("  - constraints: ")
    @time constraints = makedispatchconstraints(capacity, transmissioncapacity, modelname, sets, params, vars, hourinfo, options)
    print("  - objective:   ")
    @time makeobjective(modelname, sets, vars)

    return ModelInfo(modelname, sets, params, vars, constraints, hourinfo, options)
end

# BASIC USAGE: (carbon tax 50 €/ton CO2, 3-hour time periods)
# m, annualelec, capac, tcapac, chart = runmodel(carboncap=50, hours=3, [more options]...);
function rundispatchmodel(capacity, transmissioncapacity; name="", group="", optionlist...)       # carbon tax in €/ton CO2
    model = builddispatchmodel(capacity, transmissioncapacity; optionlist...)

    #writeMPS(model, "model3.mps")
    if model.options[:solver] == :cplex
        println("\nSolving model using CPLEX version $(CPLEX.version())...")
    else
        println("\nSolving model...")
    end

    status = @time solve(model.modelname)
    println("\nSolve status: $status")

    println("\nReading results...")
    results = readresults(model, status)

    filename = model.options[:resultsfile]

    if !isempty(filename)
        if isempty(name)
            name = autorunname(model.options)
        end
        println("\nSaving results to disk...")
        saveresults(results, name, resultsfile=filename, group=group)
    end

    annualelec, capac, tcapac, chart = analyzeresults(results)

    if status != :Optimal
        @warn "The solver did not report an optimal solution. It could still be fine, but examine the log."
    end

    return results, annualelec, capac, tcapac, chart
end

max_stars_repo_name: niclasmattsson/Supergrid

max_issues_repo_name: niclasmattsson/Supergrid

max_forks_repo_name: niclasmattsson/Supergrid


text:
"""
`vortices = remove_edgevortices(vortices,x,y,edge=1)`

Strips edgevortices due to periodic phase differencing."""
function remove_vortices_edge(vortices,x,y,edge=1)
    dx=x[2]-x[1];dy=y[2]-y[1];
    Nfound,_ = size(vortices)
    keep = []
    for j = 1:Nfound
        xi = vortices[j,1]; yi = vortices[j,2];
        xedge = isapprox(xi,x[1],atol=edge*dx) || isapprox(xi,x[end],atol=edge*dx)
        yedge = isapprox(yi,y[1],atol=edge*dy) || isapprox(yi,y[end],atol=edge*dy)
        not_edge = !(xedge || yedge)
        not_edge && push!(keep,j)
    end
    vortices = vortices[keep,:]
    nt = size(vortices)[1]
    np = sum(vortices[:,3].>0)
    nn = nt - np
    return nt,np,nn,vortices
end


text:
function check_height{K,V}(node::TreeNode{K,V}, prevheight::Int=0, height::Int=0, first::Bool=true)
    if( !node.isRed ) height += 1 end
    isbalanced=true
    if(!isleftleaf(node))
        isbalanced, prevheight = check_height(node.left, prevheight, height, first)
    end

    if(!isbalanced)
        return false, prevheight
    end

    if( isleftleaf(node) && isrightleaf(node))
        if (height != prevheight && !first)
            return false, prevheight
        end
        first=false
        prevheight = height
    end

    if(!isrightleaf(node))
        isbalanced, prevheight = check_height(node.right, prevheight, height, first)
    end

    return isbalanced, prevheight

end
check_height{K,V}(tree::LLRBTree{K,V}) = check_height(tree.root)[1]


text:
module ComputedGeodesicEquations

using Parameters
using Tullio
import StaticArrays: @SMatrix, SMatrix, MArray
import GeodesicBase:
    AbstractMetricParams, geodesic_eq, constrain, on_chart, inner_radius, metric

"""
    let_unpack(u, v, expr)

Helper utility which unpacks a position four-vector `u` and a velocity four-vector `v` into
predefined symbols, via

```julia
t, r, θ, ϕ = u[1:4]
v_t, v_r, v_theta, v_phi = v[1:4]
```

Wraps `expr` in a `let` block, with these symbols defined locally.
"""
macro let_unpack(u, v, expr)
    quote
        @inbounds let t = $u[1],
            r = $u[2],
            theta = $u[3],
            phi = $u[4],
            v_t = $v[1],
            v_r = $v[2],
            v_theta = $v[3],
            v_phi = $v[4]

            $expr
        end
    end |> esc
end

@inline function christoffel_symbols(ginv, jac)
    # TODO: using heap allocations by default
    # can we somehow make this method stack allocated for 64 floats?
    Γ = zeros(MArray{Tuple{4,4,4},Float64})
    @tullio Γ[i, k, l] = 1 / 2 * ginv[i, m] * (jac[l][m, k] + jac[k][m, l] - jac[m][k, l])
    Γ
end

@inline function geodesic_eq_from_christoffel(Γ, v)
    # TODO: using heap allocations by default
    # can we somehow make this method stack allocated for 4 floats?
    δxδλ = zeros(MArray{Tuple{4},Float64})
    @tullio δxδλ[i] = -Γ[i, j, k] * v[j] * v[k]
    δxδλ
end

@inline function jac_geodesic_eq(m::AbstractMetricParams{T}, u, v) where {T}
    ginv = inverse_metric(m, u)
    jac = jacobian(m, u)
    Γ = christoffel_symbols(ginv, jac)
    geodesic_eq_from_christoffel(Γ, v)
end

include("boyer-lindquist.jl")
include("eddington-finkelstein.jl")
include("morris-thorne.jl")
include("johannsen-psaltis.jl")

export geodesic_eq, constrain, on_chart, inner_radius

end # module


text:
"""
Compute partition numbers https://en.wikipedia.org/wiki/Partition_(number_theory)
This example is not performant because for initial value `N` every step invokes
recursion on `N` subproblems but for most steps this creates many subproblems
with negative values, which are simply discarded.
"""

include("../ragamuffin.jl")

function partition(N, floor=1)
    if N == 0
        return 1
    end
    out = 0
    for i in floor:N
        out += partition(N - i, i)
    end
    return out
end

function expand_helper(x :: Cell{T}, n) :: Cell{T} where T
    if n >= x.value[2]
        return Cell{T}((x.value[1] - n, n), x.depth, x.output_index)
    else
        return Cell{T}((-1, -1) , -1, -1)
    end
end

function ragamuffin_partition(min_N, max_N)

    T = Tuple{Int32, Int32}
    program = initialize(collect((Int32(i), Int32(1)) for i in min_N:max_N), (-Int32(1), -Int32(1)), CuFrame, 1024, Int)
    add!(program, :root, (:test_base_case, :end), value_function = x -> x.value[1] >= 0 )
    add!(program, :test_base_case, (:increment, :expand), value_function = x -> x.value[1] == 0)
    add!(program, :increment, :end, dest_function = x -> 1)
    add!(program, :expand, :root, value_function = (expand_helper, collect(1:max_N)))

    @time run(program)
    return program.dest
end
max_N = 10
@time partition(max_N)
expected = collect(partition(i) for i in 1:max_N)
batched = ragamuffin_partition(1, max_N)
@info batched
@assert expected == batched