text:
struct Wrapper
  tickPrice::Function
  tickSize::Function
  tickOptionComputation::Function
  tickGeneric::Function
  tickString::Function
  tickEFP::Function
  orderStatus::Function
  openOrder::Function
  openOrderEnd::Function
#  winError::Function
#  connectionClosed::Function
  updateAccountValue::Function
  updatePortfolio::Function
  updateAccountTime::Function
  accountDownloadEnd::Function
  nextValidId::Function
  contractDetails::Function
  bondContractDetails::Function
  contractDetailsEnd::Function
  execDetails::Function
  execDetailsEnd::Function
  error::Function
  updateMktDepth::Function
  updateMktDepthL2::Function
  updateNewsBulletin::Function
  managedAccounts::Function
  receiveFA::Function
  historicalData::Function
  scannerParameters::Function
  scannerData::Function
  realtimeBar::Function
  currentTime::Function
  fundamentalData::Function
  deltaNeutralValidation::Function
  tickSnapshotEnd::Function
  marketDataType::Function
  commissionReport::Function
  position::Function
  positionEnd::Function
  accountSummary::Function
  accountSummaryEnd::Function
  verifyMessageAPI::Function
  verifyCompleted::Function
  displayGroupList::Function
  displayGroupUpdated::Function
  verifyAndAuthMessageAPI::Function
  verifyAndAuthCompleted::Function
#  connectAck::Function
  positionMulti::Function
  positionMultiEnd::Function
  accountUpdateMulti::Function
  accountUpdateMultiEnd::Function
  securityDefinitionOptionalParameter::Function
  securityDefinitionOptionalParameterEnd::Function
  softDollarTiers::Function
  familyCodes::Function
  symbolSamples::Function
  mktDepthExchanges::Function
  tickNews::Function
  smartComponents::Function
  tickReqParams::Function
  newsProviders::Function
  newsArticle::Function
  historicalNews::Function
  historicalNewsEnd::Function
  headTimestamp::Function
  histogramData::Function
  historicalDataUpdate::Function
  rerouteMktDataReq::Function
  rerouteMktDepthReq::Function
  marketRule::Function
  pnl::Function
  pnlSingle::Function
  historicalTicks::Function
  historicalTicksBidAsk::Function
  historicalTicksLast::Function
  tickByTickAllLast::Function
  tickByTickBidAsk::Function
  tickByTickMidPoint::Function
  orderBound::Function
  completedOrder::Function
  completedOrdersEnd::Function
  replaceFAEnd::Function
  wshMetaData::Function
  wshEventData::Function
end
function Wrapper(; kw...)

  default = (_...) -> println("default implementation")

  args = (get(kw, a, default) for a ∈ fieldnames(Wrapper))

  Wrapper(args...)
end

function simple_wrap()

  d = Dict{Symbol,Any}()

  w = Wrapper(

    tickPrice= (tickerId::Int, field::String, price::Float64, size::Float64, attrib::TickAttrib) ->
                 println("tickPrice: $tickerId $field $price $size $attrib"),

    tickSize= (tickerId::Int, field::String, size::Float64) -> println("tickSize: $tickerId $field $size"),

    tickOptionComputation= function(tickerId::Int, tickType::String, tickAttrib::Union{Int,Nothing}, impliedVol::Union{Float64,Nothing}, delta::Union{Float64,Nothing}, optPrice::Union{Float64,Nothing}, pvDividend::Union{Float64,Nothing}, gamma::Union{Float64,Nothing}, vega::Union{Float64,Nothing}, theta::Union{Float64,Nothing}, undPrice::Union{Float64,Nothing})
                             d[:option] = (tickType, tickAttrib, impliedVol, delta, optPrice, pvDividend, gamma, vega, theta, undPrice)
                             println("tickOption: $tickerId $tickType")
                           end,

    tickGeneric= (tickerId::Int, tickType::String, value::Float64) ->
                   println("tickGeneric: $tickerId $tickType $value"),

    tickString= (tickerId::Int, tickType::String, value::String) ->
                  println("tickString: $tickerId $tickType $value"),

    orderStatus= function(orderId::Int, status::String, filled::Float64, remaining::Float64, avgFillPrice::Float64, permId::Int, parentId::Int, lastFillPrice::Float64, clientId::Int, whyHeld::String, mktCapPrice::Float64)
                   d[:orderstatus] = (orderId=       orderId,
                                      status=        status,
                                      filled=        filled,
                                      remaining=     remaining,
                                      avgFillPrice=  avgFillPrice,
                                      permId=        permId,
                                      lastFillPrice= lastFillPrice,
                                      clientId=      clientId,
                                      whyHeld=       whyHeld,
                                      mktCapPrice=   mktCapPrice)
                   println("orderStatus: $orderId $status")
                 end,

    openOrder= function(orderId::Int, contract::Contract, order::Order, orderstate::OrderState)
                 d[:order_contract] = contract
                 d[:order] = order
                 d[:orderstate] = orderstate
                 println("openOrder: $orderId $(orderstate.status)")
              end,

    openOrderEnd= () -> println("openOrderEnd"),

    updateAccountValue= (key::String, val::String, currency::String, accountName::String) ->
                          println("accountValue: $key $val $currency $accountName"),

    updatePortfolio= (contract::Contract, position::Float64, marketPrice::Float64, marketValue::Float64, averageCost::Float64, unrealizedPNL::Float64, realizedPNL::Float64, accountName::String) ->
                       println("portfolio:  $(contract.symbol) $position $marketPrice $marketValue $averageCost $unrealizedPNL $realizedPNL $accountName"),

    updateAccountTime= (timeStamp::String) -> println("accountTime: $timeStamp"),

    accountDownloadEnd= (accountName::String) -> println("accountDownloadEnd: $accountName"),

    nextValidId= (orderId::Int) -> d[:nextId] = orderId,

    contractDetails = function(reqId::Int, contractDetails::ContractDetails)
                        d[:cd] = contractDetails
                        println("contractDetails: $reqId ", contractDetails.contract.conId)
                      end,

    bondContractDetails = function(reqId::Int, contractDetails::ContractDetails)
                        d[:cdbond] = contractDetails
                        println("bondContractDetails: $reqId ", contractDetails.contract.conId)
                      end,

    contractDetailsEnd= (reqId::Int) -> println("contractDetailsEnd: $reqId"),

    execDetails= function(reqId::Int, contract::Contract, execution::Execution)
                    d[:ex_con] = contract
                    d[:execution] = execution
                    println("execDetails: $reqId")
                 end,

    execDetailsEnd= (reqId::Int) -> println("execDetailsEnd: $reqId"),

    error= (id::Union{Int,Nothing}, errorCode::Union{Int,Nothing}, errorString::String) ->
                     println("error: ",
                             something(id, "NA"), " ",
                             something(errorCode, "NA"), " ",
                             errorString),

    updateMktDepth= (id::Int, position::Int, operation::Int, side::Int, price::Float64, size::Float64) ->
                      println("mktDepth: $id $position $operation $side $price $size"),

    updateMktDepthL2= (id::Int, position::Int, marketMaker::String, operation::Int, side::Int, price::Float64, size::Float64, isSmartDepth::Bool) ->
                        println("mktDepthL2: $id $position $marketMaker $operation $side $price $size $isSmartDepth"),

    updateNewsBulletin= function(msgId::Int, msgType::Int, newsMessage::String, originExch::String)
                          d[:newsbulletin] = newsMessage
                          println("newsBulletin: $msgId $msgType $originExch")
                          println(newsMessage)
                        end,

    managedAccounts= (accountsList::String) -> d[:accounts] = accountsList,

    receiveFA= function(faDataType::FaDataType, xml::String)
                 d[:fa] = xml
                 println("receiveFA: $faDataType")
               end,

    historicalData= function(reqId::Int, bar::DataFrame)
                      d[:history] = bar
                      println("historicalData: $reqId $(size(bar))")
                    end,

    scannerParameters= function(xml::String)
                        d[:scannerparam] = xml
                        println("scannerParameters")
                       end,

    scannerData= function(reqId::Int, rank::Vector{Int}, contractDetails::Vector{ContractDetails}, distance::Vector{String}, benchmark::Vector{String}, projection::Vector{String}, legsStr::Vector{String})
                   d[:scannerdata] = (rank=       rank,
                                      cd=         contractDetails,
                                      distance=   distance,
                                      benchmark=  benchmark,
                                      projection= projection,
                                      legsStr=    legsStr)
                   println("scannerData: $reqId")
                 end,

    realtimeBar= (reqId::Int, time::Int, open::Float64, high::Float64, low::Float64, close::Float64, volume::Float64, wap::Float64, count::Int) ->
                   println("realtimeBar: $reqId $time $open $high, $low $close $volume $wap $count"),

    currentTime= (time::Int) -> println("currentTime: $time"),

    fundamentalData= function(reqId::Int, data::String)
                       d[:fundamental] = data
                       println("fundamentalData: $reqId")
                     end,

    tickSnapshotEnd= (reqId::Int) -> println("tickSnapshotEnd: $reqId"),

    marketDataType= (reqId::Int, marketDataType::MarketDataType) -> println("marketDataType: $reqId $marketDataType"),

    commissionReport= function(commissionReport::CommissionReport)
                        d[:commission] = commissionReport
                        println("commissionReport")
                      end,

    position= (account::String, contract::Contract, position::Float64, avgCost::Float64) ->
                println("position: $account $(contract.symbol) $position $avgCost"),

    positionEnd= () -> println("positionEnd"),

    accountSummary= (reqId::Int, account::String, tag::String, value::String, currency::String) -> println("accountSummary: $reqId $account $tag $value $currency"),

    accountSummaryEnd= (reqId::Int) -> println("accountSummaryEnd: $reqId"),

    displayGroupList= (reqId::Int, groups::String) -> println("displayGroupList: $reqId $groups"),

    displayGroupUpdated= (reqId::Int, contractInfo::String) -> println("displayGroupUpdated: $reqId $contractInfo"),

    positionMulti= (reqId::Int, account::String, modelCode::String, contract::Contract, position::Float64, avgCost::Float64) ->
                     println("positionMulti: $reqId $account $modelCode $(contract.symbol) $position $avgCost"),

    positionMultiEnd= (reqId::Int) -> println("positionMultiEnd $reqId"),

    accountUpdateMulti= (reqId::Int, account::String, modelCode::String, key::String, value::String, currency::String) -> println("accountUpdateMulti: $reqId $account, $modelCode $key=$value $currency"),

    accountUpdateMultiEnd= (reqId::Int) -> println("accountUpdateMultiEnd: $reqId"),

    securityDefinitionOptionalParameter= function(reqId::Int, exchange::String, underlyingConId::Int, tradingClass::String, multiplier::String, expirations::Vector{String}, strikes::Vector{Float64})
                                           d[:sdop] = (e= expirations,
                                                       s= strikes)
                                           println("sdop: $reqId $exchange $underlyingConId $tradingClass $multiplier $(length(expirations)) $(length(strikes))")
                                         end,

    securityDefinitionOptionalParameterEnd= (reqId::Int) -> println("sdopEnd: $reqId"),

    softDollarTiers= function(reqId::Int, tiers::Vector{SoftDollarTier})
                       d[:softdollar] = tiers
                       println("softDollarTiers: $reqId $(length(tiers))")
                     end,

    familyCodes= function(familyCodes::Vector{FamilyCode})
                   d[:familycodes] = familyCodes
                   println("familyCodes: $(length(familyCodes))")
                 end,

    symbolSamples= function(reqId::Int, contractDescriptions::Vector{ContractDescription})
                     d[:symbolsamples] = contractDescriptions
                     println("symbolSamples: $reqId")
                   end,

    mktDepthExchanges= function(depthMktDataDescriptions::DataFrame)
                        d[:mktdepthexchanges] = depthMktDataDescriptions
                        println("mktDepthExchanges")
                      end,

    tickNews= (tickerId::Int, timeStamp::Int, providerCode::String, articleId::String, headline::String, extraData::String) ->
                println("tickNews: $tickerId $timeStamp $providerCode $articleId $headline $extraData"),

    smartComponents= function(reqId::Int, theMap::DataFrame)
                       d[:smartcomponents] = theMap
                       println("smartComponents: $reqId $(size(theMap))")
                     end,

    tickReqParams= (tickerId::Int, minTick::Union{Float64,Nothing}, bboExchange::String, snapshotPermissions::Int) ->
                     println("tickReqParams: $tickerId ",
                             something(minTick, "NA"),
                             " $bboExchange $snapshotPermissions"),

    newsProviders= function(newsProviders::DataFrame)
                     d[:newsproviders] = newsProviders
                     println("newsProviders")
                   end,

    newsArticle= function(requestId::Int, articleType::Int, articleText::String)
                   d[:newsarticle] = articleText
                   println("newsArticle: $requestId $articleType")
                 end,

    historicalNews= function(requestId::Int, time::String, providerCode::String, articleId::String, headline::String)
                      println("historicalNews: $requestId $time $providerCode $articleId $headline")
                    end,

    historicalNewsEnd= (requestId::Int, hasMore::Bool) -> println("historicalNewsEnd: $requestId $hasMore"),

    headTimestamp= (reqId::Int, headTimestamp::String) -> println("headTimestamp: $reqId $headTimestamp"),

    histogramData= function(reqId::Int, data::DataFrame)
                    d[:histogram] = data
                    println("histogramData: $reqId")
                  end,

    historicalDataUpdate= (reqId::Int, bar::NamedTuple) ->
                            println("historicalDataUpdate: $reqId $bar"),

    rerouteMktDataReq= (reqId::Int, conid::Int, exchange::String) ->
                         println("rerouteMktDataReq: $reqId $conid $exchange"),

    rerouteMktDepthReq= (reqId::Int, conid::Int, exchange::String) ->
                          println("rerouteMktDepthReq: $reqId $conid $exchange"),

    marketRule= function(marketRuleId::Int, priceIncrements::DataFrame)
                  d[:marketrule] = priceIncrements
                  println("marketRule: $marketRuleId")
                end,

    pnl= (reqId::Int, dailyPnL::Float64, unrealizedPnL::Float64, realizedPnL::Float64) ->
           println("pnl: $reqId $dailyPnL $unrealizedPnL $realizedPnL"),

    pnlSingle= (reqId::Int, pos::Int, dailyPnL::Float64, unrealizedPnL::Union{Float64,Nothing}, realizedPnL::Union{Float64,Nothing}, value::Float64) ->
                 println("pnlSingle: $reqId $pos $dailyPnL ",
                         something(unrealizedPnL, "NA"), " ",
                         something(realizedPnL, "NA"),   " ",
                         value),

    historicalTicks= function(reqId::Int, ticks::DataFrame, done::Bool)
                       d[:historyticks] = ticks
                       println("historicalTicks: $reqId $done")
                     end,

    historicalTicksBidAsk= function(reqId::Int, ticks::DataFrame, done::Bool)
                             d[:historyticksbidask] = ticks
                             println("historicalTicksBidAsk: $reqId $done")
                           end,

    historicalTicksLast= function(reqId::Int, ticks::DataFrame, done::Bool)
                           d[:historytickslast] = ticks
                           println("historicalTicksLast: $reqId $done")
                         end,

    tickByTickAllLast= (reqId::Int, tickType::Int, time::Int, price::Float64, size::Float64, attribs::TickAttribLast, exchange::String, specialConditions::String) ->
                         println("tickByTickAllLast: $reqId $tickType $time $price $size $attribs $exchange $specialConditions"),

    tickByTickBidAsk= (reqId::Int, time::Int, bidPrice::Float64, askPrice::Float64, bidSize::Float64, askSize::Float64, attribs::TickAttribBidAsk) ->
                        println("tickByTickBidAsk: $reqId $time $bidPrice $askPrice $bidSize $askSize $attribs"),

    tickByTickMidPoint= (reqId::Int, time::Int, midPoint::Float64) ->
                          println("tickByTickMidPoint: $reqId $time $midPoint"),

    orderBound= (orderId::Int, apiClientId::Int, apiOrderId::Int) ->
                  println("orderBound: $orderId $apiClientId $apiOrderId"),

    completedOrder= function(contract::Contract, order::Order, orderState::OrderState)
                      d[:completed_contract] = contract
                      d[:completed] = order
                      d[:completed_state] = orderState
                 println("completedOrder: $(contract.symbol) $(orderState.status)")
              end,

    completedOrdersEnd= () -> println("completedOrdersEnd"),

    replaceFAEnd= (reqId::Int, text::String) -> println("replaceFAEnd: $reqId $text"),

    wshMetaData= (reqId::Int, dataJson::String) -> println("wshMetaData: $reqId $dataJson"),

    wshEventData= (reqId::Int, dataJson::String) -> println("wshEventData: $reqId $dataJson"),
  )

  d, w
end


text:
struct TestComponent <: InfrastructureSystemsType
    name::AbstractString
    val::Int
    forecasts::Forecasts
    internal::InfrastructureSystemsInternal
end

struct AdditionalTestComponent <: InfrastructureSystemsType
    name::AbstractString
    val::Int
    forecasts::Forecasts
    internal::InfrastructureSystemsInternal
end

function TestComponent(name, val)
    return TestComponent(name, val, Forecasts(), InfrastructureSystemsInternal())
end

function AdditionalTestComponent(name, val)
    return AdditionalTestComponent(name, val, Forecasts(), InfrastructureSystemsInternal())
end

get_internal(component::TestComponent) = component.internal
get_internal(component::AdditionalTestComponent) = component.internal
get_val(component::TestComponent) = component.val

function get_forecasts(component::TestComponent)
    return component.forecasts
end

function JSON2.read(io::IO, ::Type{TestComponent})
    data = JSON2.read(io)
    return TestComponent(
        data.name,
        data.val,
        convert_type(Forecasts, data.forecasts),
        JSON2.read(JSON2.write(data.internal), InfrastructureSystemsInternal),
    )
end

struct TestEvent <: AbstractRecorderEvent
    common::RecorderEventCommon
    val1::String
    val2::Int
    val3::Float64
end

function TestEvent(val1::String, val2::Int, val3::Float64)
    return TestEvent(RecorderEventCommon("TestEvent"), val1, val2, val3)
end

struct TestEvent2 <: AbstractRecorderEvent
    common::RecorderEventCommon
    val::Int
end

function TestEvent2(val::Int)
    return TestEvent2(RecorderEventCommon("TestEvent2"), val)
end

function runtests(args...)
    test_prefix = "test_"
    for arg in args
        if !startswith(arg, test_prefix)
            arg = test_prefix * arg
        end
        push!(ARGS, arg)
    end

    try
        include("test/runtests.jl")
    finally
        empty!(ARGS)
    end
end

ext: jl


text:
mutable struct Variable
    id
    t
    val
end
mutable struct EXPR{T}
    args::Vector
    span::Int
    defs::Vector{Variable}
    val::String
end

abstract type IDENTIFIER end
abstract type LITERAL{K} end
abstract type KEYWORD{K} end
abstract type OPERATOR{P,K,dot} end
abstract type PUNCTUATION{K} end
abstract type HEAD{K} end
abstract type ERROR end

function LITERAL(ps::ParseState)
    span = ps.nt.startbyte - ps.t.startbyte
    if ps.t.kind == Tokens.STRING || ps.t.kind == Tokens.TRIPLE_STRING
        return parse_string(ps)
    else
        EXPR{LITERAL{ps.t.kind}}(EXPR[], span, Variable[], ps.t.val)
    end
end

IDENTIFIER(ps::ParseState) = EXPR{IDENTIFIER}(EXPR[], ps.nt.startbyte - ps.t.startbyte, Variable[], ps.t.val)

OPERATOR(ps::ParseState) = EXPR{OPERATOR{precedence(ps.t),ps.t.kind,ps.dot}}(EXPR[], ps.nt.startbyte - ps.t.startbyte, Variable[], "")

KEYWORD(ps::ParseState) = EXPR{KEYWORD{ps.t.kind}}(EXPR[], ps.nt.startbyte - ps.t.startbyte, Variable[], "")

PUNCTUATION(ps::ParseState) = EXPR{PUNCTUATION{ps.t.kind}}(EXPR[], ps.nt.startbyte - ps.t.startbyte, Variable[], "")

function INSTANCE(ps::ParseState)
    span = ps.nt.startbyte - ps.t.startbyte
    return isidentifier(ps.t) ? IDENTIFIER(ps) :
        isliteral(ps.t) ? LITERAL(ps) :
        iskw(ps.t) ? KEYWORD(ps) :
        isoperator(ps.t) ? OPERATOR(ps) :
        ispunctuation(ps.t) ? PUNCTUATION(ps) :
        ps.t.kind == Tokens.SEMICOLON ? PUNCTUATION(ps) :
        EXPR{ERROR}(EXPR[], span, Variable[], "")
end

# heads

const TRUE = EXPR{LITERAL{Tokens.TRUE}}(EXPR[], 0, Variable[], "")
const FALSE = EXPR{LITERAL{Tokens.FALSE}}(EXPR[], 0, Variable[], "")
const NOTHING = EXPR{HEAD{:nothing}}(EXPR[], 0, Variable[], "nothing")
const GlobalRefDOC = EXPR{HEAD{:globalrefdoc}}(EXPR[], 0, Variable[], "globalrefdoc")

abstract type Scope{t} end

mutable struct File
    imports
    includes::Vector{Tuple{String,Any}}
    path::String
    ast::EXPR
    errors
end
File(path::String) = File([], [], path, EXPR{FileH}(EXPR[], 0, Variable[], ""), [])

mutable struct Project
    path::String
    files::Vector{File}
end

const NoVariable = Variable(NOTHING, NOTHING, NOTHING)

abstract type Head end

abstract type Call <: Head end
abstract type UnaryOpCall <: Head end
abstract type UnarySyntaxOpCall <: Head end
abstract type BinaryOpCall <: Head end
abstract type BinarySyntaxOpCall <: Head end
abstract type ConditionalOpCall <: Head end
abstract type ComparisonOpCall <: Head end
abstract type ChainOpCall <: Head end
abstract type ColonOpCall <: Head end

abstract type Abstract <: Head end
abstract type Begin <: Head end
abstract type Bitstype <: Head end
abstract type Block <: Head end
abstract type Break <: Head end
abstract type Cell1d <: Head end
abstract type Const <: Head end
abstract type Continue <: Head end
abstract type Comparison <: Head end
abstract type Curly <: Head end
abstract type Do <: Head end
abstract type Filter <: Head end
abstract type Flatten <: Head end
abstract type For <: Head end
abstract type FunctionDef <: Head end
abstract type Generator <: Head end
abstract type Global <: Head end
abstract type If <: Head end
abstract type Kw <: Head end
abstract type Let <: Head end
abstract type Local <: Head end
abstract type Macro <: Head end
abstract type MacroCall <: Head end
abstract type Mutable <: Head end
abstract type Parameters <: Head end
abstract type Primitive <: Head end
abstract type Quote <: Head end
abstract type Quotenode <: Head end
abstract type InvisBrackets <: Head end
abstract type StringH <: Head end
abstract type Struct <: Head end
abstract type Try <: Head end
abstract type TupleH <: Head end
abstract type TypeAlias <: Head end
abstract type FileH <: Head end
abstract type Return <: Head end
abstract type Vect <: Head end
abstract type While <: Head end
abstract type x_Cmd <: Head end
abstract type x_Str <: Head end

abstract type ModuleH <: Head end
abstract type BareModule <: Head end
abstract type TopLevel <: Head end
abstract type Export <: Head end
abstract type Import <: Head end
abstract type ImportAll <: Head end
abstract type Using <: Head end

abstract type Comprehension <: Head end
abstract type DictComprehension <: Head end
abstract type TypedComprehension <: Head end
abstract type Hcat <: Head end
abstract type TypedHcat <: Head end
abstract type Ref <: Head end
abstract type Row <: Head end
abstract type Vcat <: Head end
abstract type TypedVcat <: Head end
abstract type Vect <: Head end

Quotenode(x::EXPR) = EXPR{Quotenode}(EXPR[x], x.span, Variable[], "")


text:
module SparseSampling

using Random
using POMDPs
using Parameters
using StaticArrays
using POMDPModelTools

export
    SSOptions,
    SparseSamplingSolver,
    POWSSOptions,
    SSPlanner,
    valuepairs

abstract type AbstractSSOptions end

# accessors
maxdepth(opt::AbstractSSOptions) = opt.maxdepth
width(opt::AbstractSSOptions) = opt.width

@with_kw struct SSOptions <: AbstractSSOptions
    maxdepth::Int
    width::Int
end

@with_kw struct POWSSOptions <: AbstractSSOptions
    maxdepth::Int
    width::Int
end

struct SparseSamplingSolver
    opt::AbstractSSOptions
    rng::AbstractRNG
end

SparseSamplingSolver(opt::AbstractSSOptions; rng=Random.GLOBAL_RNG) = SparseSamplingSolver(opt, rng)
SparseSamplingSolver(;rng=Random.GLOBAL_RNG, kwargs...) = SparseSamplingSolver(SSOptions(kwargs...), rng)

function POMDPs.solve(s::SparseSamplingSolver, m::Union{MDP,POMDP})
    if s.opt isa POWSSOptions
        @assert !(Nothing <: statetype(m)) "POWSS does not support problems where the state can be nothing (this can be fixed by adding Some in appropriate places)."
        # @assert !(Nothing <: obstype(m)) "POWSS does not support problems where the observation can be nothing (this can be fixed by adding Some in appropriate places)."
    end
    SSPlanner(m, s.opt, s.rng)
end
struct SSPlanner{M<:Union{MDP,POMDP},O<:AbstractSSOptions,R<:AbstractRNG}
    m::M
    opt::O
    rng::R
end

include("pomdp_sparse_sampling.jl")

end # module


text:
using Turing
using Test
using Random

Random.seed!(125)

alg = SGHMC(10000, 0.02, 0.5)

@model gdemo(x) = begin
  s ~ InverseGamma(2,3)
  m ~ Normal(0,sqrt.(s))
  x[1] ~ Normal(m, sqrt.(s))
  x[2] ~ Normal(m, sqrt.(s))
  return s, m
end

chain = sample(gdemo([1.5, 2.0]), alg)
@test mean(chain[:s]) ≈ 49/24 atol=0.1
@test mean(chain[:m]) ≈ 7/6 atol=0.1


text:
abstract type AbstractDataset <: AbstractDataContainer end

function Base.show(io::IO, d::D) where D <: AbstractDataset
    print(io, "$(D.name.name)()")
end

function Base.show(io::IO, ::MIME"text/plain", d::D) where D <: AbstractDataset
    recur_io = IOContext(io, :compact => false)

    print(io, "dataset $(D.name.name):")  # if the type is parameterized don't print the parameters

    for f in fieldnames(D)
        if !startswith(string(f), "_")
            fstring = leftalign(string(f), 10)
            print(recur_io, "\n  $fstring  =>    ")
            # show(recur_io, MIME"text/plain"(), getfield(d, f))
            # println(recur_io)
            print(recur_io, "$(_summary(getfield(d, f)))")
        end
    end
end

function leftalign(s::AbstractString, n::Int)
    m = length(s)
    if m > n
        return s[1:n]
    else
        return s * repeat(" ", n-m)
    end
end

_summary(x) = x
_summary(x::Symbol) = ":$x"
_summary(x::Union{Dict, AbstractArray, DataFrame}) = summary(x)
_summary(x::Union{Tuple, NamedTuple}) = map(summary, x)

"""
    abstract type SupervisedDataset <: AbstractDataset end

An abstract dataset type for supervised learning tasks.
Concrete dataset types inheriting from it must provide
a `features` and a `targets` fields.
"""
abstract type SupervisedDataset <: AbstractDataset end

Base.length(d::SupervisedDataset) = numobs((d.features, d.targets))

# We return named tuples
Base.getindex(d::SupervisedDataset) = getobs((; d.features, d.targets))
Base.getindex(d::SupervisedDataset, i) = getobs((; d.features, d.targets), i)

"""
    abstract type UnsupervisedDataset <: AbstractDataset end

An abstract dataset type for unsupervised or self-supervised learning tasks.
Concrete dataset types inheriting from it must provide
a `features` field.
"""
abstract type UnsupervisedDataset <: AbstractDataset end

Base.length(d::UnsupervisedDataset) = numobs(d.features)

Base.getindex(d::UnsupervisedDataset) = getobs(d.features)
Base.getindex(d::UnsupervisedDataset, i) = getobs(d.features, i)

### DOCSTRING TEMPLATES ######################

# SUPERVISED TABLE
const ARGUMENTS_SUPERVISED_TABLE = """
- If `as_df = true`, load the data as dataframes instead of plain arrays.

- You can pass a specific `dir` where to load or download the dataset, otherwise uses
the default one.
"""

const FIELDS_SUPERVISED_TABLE = """
- `metadata`: A dictionary containing additional information on the dataset.
- `features`: The data features. An array if `as_df=true`, otherwise a dataframe.
- `targets`: The targets for supervised learning. An array if `as_df=true`, otherwise a dataframe.
- `dataframe`: A dataframe containing both `features` and `targets`. It is `nothing` if `as_df=false`.
"""

const METHODS_SUPERVISED_TABLE = """
- `dataset[i]`: Return observation(s) `i` as a named tuple of features and targets .
- `dataset[]`: Return all observations as a named tuple of features and targets.
- `length(dataset)`: Number of observations.
"""

# SUPERVISED ARRAY DATASET

const ARGUMENTS_SUPERVISED_ARRAY = """
- You can pass a specific `dir` where to load or download the dataset, otherwise uses
the default one.
"""

const FIELDS_SUPERVISED_ARRAY = """
- `metadata`: A dictionary containing additional information on the dataset.
- `features`: An array storing the data features.
- `targets`: An array storing the targets for supervised learning.
"""

const METHODS_SUPERVISED_ARRAY = """
- `dataset[i]`: Return observation(s) `i` as a named tuple of features and targets .
- `dataset[]`: Return all observations as a named tuple of features and targets.
- `length(dataset)`: Number of observations.
"""


text:
FT = Float64
# Conductivity polynomials (can be defined outside):
const TempPoly   = Polynomial(FT.([2.903602, 8.607e-2, 4.738817e-4, -2.991e-6, 4.3041e-9]),:T)
const SalPoly1   = Polynomial(FT.([37.5109, 5.45216, 0.014409]),:S);
const SalPoly2   = Polynomial(FT.([1004.75, 182.283, 1.0]),:S);
const α₀PolNom   = Polynomial(FT.([6.9431, 3.2841, -0.099486]),:S);
const α₀PolDenom = Polynomial(FT.([84.85, 69.024, 1.0]),:S);
const α₁         = Polynomial(FT.([49.843, -0.2276, 0.00198]),:S);
const aU = FT.([0.46606917e-2, -0.26087876e-4, -0.63926782e-5,
                       0.63000075e1,   0.26242021e-2, -0.42984155e-2,
                       0.34414691e-4,  0.17667420e-3, -0.20491560e-6,
                       0.58366888e3,   0.12634992e3,   0.69227972e-4,
                       0.38957681e-6,  0.30742330e3,   0.12634992e3,
                       0.37245044e1,   0.92609781e-2, -0.26093754e-1]
                       );


text:
using BrainFlow

# enable logs
BrainFlow.enable_dev_logger(BrainFlow.BOARD_CONTROLLER)
BrainFlow.enable_dev_logger(BrainFlow.DATA_HANDLER)

params = BrainFlowInputParams()
board_shim = BrainFlow.BoardShim(BrainFlow.SYNTHETIC_BOARD, params)
sampling_rate = BrainFlow.get_sampling_rate(BrainFlow.SYNTHETIC_BOARD)

BrainFlow.prepare_session(board_shim)
BrainFlow.start_stream(board_shim)
sleep(10)
BrainFlow.stop_stream(board_shim)
data = BrainFlow.get_current_board_data(BrainFlow.get_nearest_power_of_two(sampling_rate), board_shim)
BrainFlow.release_session(board_shim)

eeg_channels = BrainFlow.get_eeg_channels(BrainFlow.SYNTHETIC_BOARD)
data_first_channel = data[eeg_channels[1], :]

# returns tuple of wavelet coeffs and lengths
wavelet_data = BrainFlow.perform_wavelet_transform(data_first_channel, BrainFlow.DB3, 2, BrainFlow.SYMMETRIC)
restored_wavelet_data = BrainFlow.perform_inverse_wavelet_transform(wavelet_data, length(data_first_channel),
																	BrainFlow.DB3, 2, BrainFlow.SYMMETRIC)

fft_data = BrainFlow.perform_fft(data_first_channel, BrainFlow.NO_WINDOW)
restored_fft_data = BrainFlow.perform_ifft(fft_data)

println("Original Data")
println(data_first_channel)
println("Restored from Wavelet Data")
println(restored_wavelet_data)
println("Restored from FFT Data")
println(restored_fft_data)


text:
# --------------------------------------------------------------------
# prevalence is a bit of an outlier

@reduce_fraction """
Return the fraction of positive observations in `targets`.
Which value denotes "positive" depends on the given (or inferred)
`encoding`.

$FRAC_ENCODING_DESCR

$AVGMODE_DESCR

# Arguments

$FRAC_ARGS

# See also

[`condition_positive`](@ref)

# Examples

```jldoctest
julia> prevalence([0,1,1,0,1], [1,1,1,0,1])
0.6

julia> prevalence([-1,1,1,-1,1], [1,1,1,-1,1])
0.6

julia> prevalence([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], LabelEnc.OneVsRest(:c))
0.4

julia> prevalence([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c]) # avgmode=:none
Dict{Symbol,Float64} with 3 entries:
  :a => 0.4
  :b => 0.2
  :c => 0.4

julia> prevalence([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:micro)
0.3333333333333333
```
""" ->
prevalence := condition_positive / _length_targets

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

@reduce_fraction """
Return the fraction of positive predicted outcomes in `outputs`
that are true positives according to the correspondig `targets`.
This is also known as "precision" (alias `precision_score`).
Which value(s) denote "positive" or "negative" depends on the
given (or inferred) `encoding`.

$FRAC_ENCODING_DESCR

$AVGMODE_DESCR

# Arguments

$FRAC_ARGS

# See also

[`true_positives`](@ref),
[`predicted_positive`](@ref),
[`true_positive_rate`](@ref) (aka "recall" or "sensitivity"),
[`f_score`](@ref)

# Examples

```jldoctest
julia> precision_score([0,1,1,0,1], [1,1,1,0,1])
0.75

julia> precision_score([-1,1,1,-1,1], [1,1,1,-1,1])
0.75

julia> precision_score([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], LabelEnc.OneVsRest(:c))
0.6666666666666666

julia> precision_score([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c]) # avgmode=:none
Dict{Symbol,Float64} with 3 entries:
  :a => 1.0
  :b => 0.0
  :c => 0.666667

julia> precision_score([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:micro)
0.6

julia> precision_score([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:macro)
0.5555555555555555
```
""" ->
positive_predictive_value := true_positives / predicted_positive

const precision_score = positive_predictive_value

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

@reduce_fraction """
Return the fraction of negative predicted outcomes in `outputs`
that are true negatives according to the corresponding `targets`.
Which value(s) denote "positive" or "negative" depends on the
given (or inferred) `encoding`.

$FRAC_ENCODING_DESCR

$AVGMODE_DESCR

# Arguments

$FRAC_ARGS

# See also

[`true_negatives`](@ref),
[`predicted_negative`](@ref)

# Examples

```jldoctest
julia> negative_predictive_value([0,1,1,0,1], [1,1,1,0,1])
1.0

julia> negative_predictive_value([-1,1,1,-1,1], [1,1,1,-1,1])
1.0

julia> negative_predictive_value([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], LabelEnc.OneVsRest(:b))
0.75

julia> negative_predictive_value([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c]) # avgmode=:none
Dict{Symbol,Float64} with 3 entries:
  :a => 0.75
  :b => 0.75
  :c => 1.0

julia> negative_predictive_value([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:micro)
0.8

julia> negative_predictive_value([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:macro)
0.8333333333333334
```
""" ->
negative_predictive_value := true_negatives / predicted_negative

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

@reduce_fraction """
Return the fraction of truly positive observations in `outputs`
that were predicted as positives. This is also known as `recall`
or `sensitivity`. What constitutes "truly positive" depends on to
the corresponding `targets` and the given (or inferred) `encoding`.

$FRAC_ENCODING_DESCR

$AVGMODE_DESCR

# Arguments

$FRAC_ARGS

# See also

[`true_positives`](@ref),
[`positive_predictive_value`](@ref) (aka "precision"),
[`true_negative_rate`](@ref) (aka "specificity"),
[`f_score`](@ref)

# Examples

```jldoctest
julia> recall([0,1,1,0,1,1], [1,0,1,0,1,1])
0.75

julia> recall([-1,1,1,-1,1], [1,-1,1,-1,1])
0.6666666666666666

julia> recall([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], LabelEnc.OneVsRest(:a))
0.5

julia> recall([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c]) # avgmode=:none
Dict{Symbol,Float64} with 3 entries:
  :a => 0.5
  :b => 0.0
  :c => 1.0

julia> recall([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:micro)
0.6

julia> recall([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:macro)
0.5
```
""" ->
true_positive_rate := true_positives / condition_positive

const sensitivity = true_positive_rate
const recall = true_positive_rate

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

@reduce_fraction """
Return the fraction of truly negative observations in `outputs`
that were (wrongly) predicted as positives. What constitutes
"truly negative" depends on to the corresponding `targets` and
the given (or inferred) `encoding`.

$FRAC_ENCODING_DESCR

$AVGMODE_DESCR

# Arguments

$FRAC_ARGS

# See also

[`true_positives`](@ref),
[`positive_predictive_value`](@ref) (aka "precision"),
[`true_negative_rate`](@ref) (aka "specificity"),
[`f_score`](@ref)

# Examples

```jldoctest
julia> false_positive_rate([0,1,1,0,1], [1,1,1,0,1])
0.5

julia> false_positive_rate([-1,1,1,-1,1], [1,1,1,-1,1])
0.5

julia> false_positive_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], LabelEnc.OneVsRest(:b))
0.25

julia> false_positive_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c]) # avgmode=:none
Dict{Symbol,Float64} with 3 entries:
  :a => 0.0
  :b => 0.25
  :c => 0.333333

julia> false_positive_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:micro)
0.2

julia> false_positive_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:macro)
0.19444444444444442
```
""" ->
false_positive_rate := false_positives / condition_negative

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

@reduce_fraction """
Return the fraction of negative predicted outcomes that are true
negatives according to the corresponding `targets`. This is also
known as `specificity`.
Which value(s) denote "positive" or "negative" depends on the
given (or inferred) `encoding`.

$FRAC_ENCODING_DESCR

$AVGMODE_DESCR

# Arguments

$FRAC_ARGS

# See also

[`true_negatives`](@ref),
[`condition_negative`](@ref),
[`true_positive_rate`](@ref) (aka "recall" or "sensitivity")

# Examples

```jldoctest
julia> true_negative_rate([0,1,1,0,1], [1,1,1,0,1])
0.5

julia> true_negative_rate([-1,1,1,-1,1], [1,1,1,-1,1])
0.5

julia> true_negative_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], LabelEnc.OneVsRest(:b))
0.75

julia> true_negative_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c]) # avgmode=:none
Dict{Symbol,Float64} with 3 entries:
  :a => 1.0
  :b => 0.75
  :c => 0.666667

julia> true_negative_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:micro)
0.8

julia> true_negative_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:macro)
0.8055555555555555
```
""" ->
true_negative_rate := true_negatives / condition_negative

const specificity = true_negative_rate

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

@reduce_fraction """
Return the fraction of truely positive observations that were
(wrongly) predicted as negative. What constitutes "truly
positive" depends on to the corresponding `targets` and the given
(or inferred) `encoding`.

$FRAC_ENCODING_DESCR

$AVGMODE_DESCR

# Arguments

$FRAC_ARGS

# See also

[`false_negatives`](@ref),
[`condition_positive`](@ref)

# Examples

```jldoctest
julia> false_negative_rate([0,1,1,0,1], [1,0,1,0,1])
0.3333333333333333

julia> false_negative_rate([-1,1,1,-1,1], [1,1,1,-1,1])
0.0

julia> false_negative_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], LabelEnc.OneVsRest(:a))
0.5

julia> false_negative_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c]) # avgmode=:none
Dict{Symbol,Float64} with 3 entries:
  :a => 0.5
  :b => 1.0
  :c => 0.0

julia> false_negative_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:micro)
0.4

julia> false_negative_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:macro)
0.5
```
""" ->
false_negative_rate := false_negatives / condition_positive

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

@reduce_fraction """
Return the fraction of positive predicted outcomes in `outputs`
that are false positives according to the corresponding `targets`.
Which value(s) denote "positive" or "negative" depends on the
given (or inferred) `encoding`.

$FRAC_ENCODING_DESCR

$AVGMODE_DESCR

# Arguments

$FRAC_ARGS

# See also

[`false_positives`](@ref),
[`predicted_positive`](@ref),
[`false_omission_rate`](@ref)

# Examples

```jldoctest
julia> false_discovery_rate([0,1,1,0,1], [1,1,1,0,1])
0.25

julia> false_discovery_rate([-1,1,1,-1,1], [1,1,1,-1,1])
0.25

julia> false_discovery_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], LabelEnc.OneVsRest(:b))
1.0

julia> false_discovery_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c]) # avgmode=:none
Dict{Symbol,Float64} with 3 entries:
  :a => 0.0
  :b => 1.0
  :c => 0.333333

julia> false_discovery_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:micro)
0.4

julia> false_discovery_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:macro)
0.4444444444444444
```
""" ->
false_discovery_rate := false_positives / predicted_positive

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

@reduce_fraction """
Return the fraction of negative predicted outcomes in `outputs`
that are false negatives according to the corresponding `targets`.
Which value(s) denote "positive" or "negative" depends on the
given (or inferred) `encoding`.

$FRAC_ENCODING_DESCR

$AVGMODE_DESCR

# Arguments

$FRAC_ARGS

# See also

[`false_negatives`](@ref),
[`predicted_negative`](@ref),
[`false_discovery_rate`](@ref)

# Examples

```jldoctest
julia> false_omission_rate([0,1,1,0,1], [1,1,1,0,1])
0.0

julia> false_omission_rate([-1,1,1,-1,1], [1,1,1,-1,1])
0.0

julia> false_omission_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], LabelEnc.OneVsRest(:b))
0.25

julia> false_omission_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c]) # avgmode=:none
Dict{Symbol,Float64} with 3 entries:
  :a => 0.25
  :b => 0.25
  :c => 0.0

julia> false_omission_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:micro)
0.2

julia> false_omission_rate([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:macro)
0.16666666666666666
```
""" ->
false_omission_rate := false_negatives / predicted_negative

# --------------------------------------------------------------------
# MAP FRACTION

@map_fraction """
Compute the positive likelihood ratio for the given `outputs` and
`targets`. It is a useful meassure for assessing the quality of a
diagnostic test and is defined as `sensitivity / (1 -
specificity)`. This can also be written as `true_positive_rate /
false_positive_rate`.
Which value(s) denote "positive" or "negative" depends on the
given (or inferred) `encoding`.

$FRAC_ENCODING_DESCR

$AVGMODE_DESCR

# Arguments

$FRAC_ARGS

# See also

[`true_positive_rate`](@ref) (aka "recall" or "sensitivity"),
[`false_positive_rate`](@ref),
[`negative_likelihood_ratio`](@ref),
[`diagnostic_odds_ratio`](@ref)

# Examples

```jldoctest
julia> positive_likelihood_ratio([0,1,1,0,1], [1,1,1,0,1])
2.0

julia> positive_likelihood_ratio([-1,1,1,-1,1], [1,1,1,-1,1])
2.0

julia> positive_likelihood_ratio([:b,:b,:a,:c,:c], [:a,:c,:b,:c,:c], LabelEnc.OneVsRest(:c))
3.0

julia> positive_likelihood_ratio([:b,:b,:a,:c,:c], [:a,:c,:b,:c,:c]) # avgmode=:none
Dict{Symbol,Float64} with 3 entries:
  :a => 0.0
  :b => 0.0
  :c => 3.0

julia> positive_likelihood_ratio([:b,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:micro)
1.3333333333333335

julia> positive_likelihood_ratio([:b,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:macro)
1.090909090909091
```
""" ->
positive_likelihood_ratio := true_positive_rate / false_positive_rate

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

@map_fraction """
Compute the negative likelihood ratio for the given `outputs` and
`targets`. It is a useful meassure for assessing the quality of a
diagnostic test and is defined as `(1 - sensitivity) /
specificity`. This can also be written as `false_negative_rate /
true_negative_rate`.
Which value(s) denote "positive" or "negative" depends on the
given (or inferred) `encoding`.

$FRAC_ENCODING_DESCR

$AVGMODE_DESCR

# Arguments

$FRAC_ARGS

# See also

[`false_negative_rate`](@ref),
[`true_negative_rate`](@ref) (aka "specificity"),
[`positive_likelihood_ratio`](@ref),
[`diagnostic_odds_ratio`](@ref)

# Examples

```jldoctest
julia> negative_likelihood_ratio([0,1,1,0,1], [1,0,1,0,1])
0.6666666666666666

julia> negative_likelihood_ratio([-1,1,1,-1,1], [1,-1,1,-1,1])
0.6666666666666666

julia> negative_likelihood_ratio([:b,:b,:a,:c,:c], [:a,:c,:b,:c,:c], LabelEnc.OneVsRest(:a))
1.3333333333333333

julia> negative_likelihood_ratio([:b,:b,:a,:c,:c], [:a,:c,:b,:c,:c]) # avgmode=:none
Dict{Symbol,Float64} with 3 entries:
  :a => 1.33333
  :b => 1.5
  :c => 0.0

julia> negative_likelihood_ratio([:b,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:micro)
0.8571428571428572

julia> negative_likelihood_ratio([:b,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:macro)
0.9600000000000002
```
""" ->
negative_likelihood_ratio := false_negative_rate / true_negative_rate

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

@map_fraction """
Compute the diagnostic odds ratio (DOR) for the given `outputs`
and `targets`. It is a useful meassure of the effectiveness of a
diagnostic test and is defined as `positive_likelihood_ratio /
negative_likelihood_ratio`.
Which value(s) denote "positive" or "negative" depends on the
given (or inferred) `encoding`.

$FRAC_ENCODING_DESCR

$AVGMODE_DESCR

# Arguments

$FRAC_ARGS

# See also

[`positive_likelihood_ratio`](@ref),
[`negative_likelihood_ratio`](@ref)

# Examples

```jldoctest
julia> diagnostic_odds_ratio([0,1,1,0,1], [1,0,1,0,1])
2.0

julia> diagnostic_odds_ratio([-1,1,1,-1,1], [1,-1,1,-1,1])
2.0

julia> diagnostic_odds_ratio([:b,:b,:a,:c,:c], [:a,:b,:b,:c,:c], LabelEnc.OneVsRest(:b))
2.0

julia> diagnostic_odds_ratio([:b,:b,:a,:c,:c], [:a,:b,:b,:c,:c]) # avgmode=:none
Dict{Symbol,Float64} with 3 entries:
  :a => 0.0
  :b => 2.0
  :c => Inf

julia> diagnostic_odds_ratio([:b,:b,:a,:c,:c], [:a,:b,:b,:c,:c], avgmode=:micro)
5.999999999999999

julia> diagnostic_odds_ratio([:b,:b,:a,:c,:c], [:a,:b,:b,:c,:c], avgmode=:macro)
4.142857142857143
```
""" ->
diagnostic_odds_ratio := positive_likelihood_ratio / negative_likelihood_ratio
# FIXME: maybe check if both false negatives and false positives are zero

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

"""
    accuracy(targets, outputs, [encoding]; [normalize = true]) -> Float64

Compute the fraction of correctly predicted outcomes in `outputs`
according to the given true `targets`. This is known as the
classification accuracy.

$FRAC_ENCODING_DESCR

# Arguments

- `targets::AbstractArray`: The array of ground truths
  ``\\mathbf{y}``.

- `outputs::AbstractArray`: The array of predicted outputs
  ``\\mathbf{\\hat{y}}``.

- `encoding`: Optional. Specifies the possible values in
  `targets` and `outputs` and their interpretation (e.g. what
  constitutes as a positive or negative label, how many labels
  exist, etc). It can either be an object from the namespace
  `LabelEnc`, or a vector of labels.

- `normalize::Bool`: Optional keyword argument. If `true`, the
  function will return the fraction of correctly classified
  observations in `outputs`. Otherwise it returns the total
  number. Defaults to `true`.

# See also

[`correctly_classified`](@ref), [`f_score`](@ref)

# Examples

```jldoctest
julia> accuracy([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c])
0.6

julia> accuracy([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], normalize=false)
3.0

julia> accuracy([1,0,0,1,1], [1,-1,-1,-1,1], LabelEnc.FuzzyBinary())
0.8
```
"""
function accuracy(targets::AbstractArray,
                  outputs::AbstractArray,
                  encoding::BinaryLabelEncoding;
                  normalize = true)
    @_dimcheck length(targets) == length(outputs)
    tp::Int = 0; tn::Int = 0
    @inbounds for i = 1:length(targets)
        target = targets[i]
        output = outputs[i]
        tp += true_positives(target, output, encoding)
        tn += true_negatives(target, output, encoding)
    end
    correct = tp + tn
    normalize ? Float64(correct/length(targets)) : Float64(correct)
end

function accuracy(object; normalize = true)
    correct = true_positives(object) + true_negatives(object)
    normalize ? Float64(correct/nobs(object)) : Float64(correct)
end

function accuracy(targets::AbstractArray,
                  outputs::AbstractArray,
                  encoding::LabelEncoding;
                  normalize = true)
    @_dimcheck length(targets) == length(outputs)
    correct::Int = 0
    @inbounds for i = 1:length(targets)
        correct += targets[i] == outputs[i]
    end
    normalize ? Float64(correct/length(targets)) : Float64(correct)
end

function accuracy(targets::AbstractArray,
                  outputs::AbstractArray,
                  labels::AbstractVector;
                  normalize = true)
    accuracy(targets, outputs, LabelEnc.NativeLabels(labels), normalize = normalize)::Float64
end

function accuracy(targets::AbstractArray,
                  outputs::AbstractArray;
                  normalize = true)
    accuracy(targets, outputs, _labelenc(targets, outputs), normalize = normalize)::Float64
end

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

"""
    f_score(targets, outputs, [encoding], [avgmode], [beta = 1]) -> Float64

Compute the F-score for the `outputs` given the `targets`.
The F-score is a measure for accessing the quality of binary
predictor by considering both *recall* and the *precision*.
Which value(s) denote "positive" or "negative" depends on the
given (or inferred) `encoding`.

$FRAC_ENCODING_DESCR

$AVGMODE_DESCR

# Arguments

$FRAC_ARGS
- `beta::Number`: Optional keyword argument. Used to balance the
  importance of recall vs precision. The default `beta = 1`
  corresponds to the harmonic mean. A value of `beta > 1` weighs
  recall higher than precision, while a value of `beta < 1`
  weighs recall lower than precision.

# See also

[`accuracy`](@ref),
[`positive_predictive_value`](@ref) (aka "precision"),
[`true_positive_rate`](@ref) (aka "recall" or "sensitivity")

# Examples

```jldoctest
julia> recall([1,0,0,1,1], [1,0,0,0,1])
0.6666666666666666

julia> precision_score([1,0,0,1,1], [1,0,0,0,1])
1.0

julia> f_score([1,0,0,1,1], [1,0,0,0,1])
0.8

julia> f_score([1,0,0,1,1], [1,0,0,0,1], beta = 2)
0.7142857142857143

julia> f_score([1,0,0,1,1], [1,0,0,0,1], beta = 0.5)
0.9090909090909091

julia> f_score([1,0,0,1,1], [1,-1,-1,-1,1], LabelEnc.FuzzyBinary())
0.8

julia> f_score([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c]) # avgmode=:none
Dict{Symbol,Float64} with 3 entries:
  :a => 0.666667
  :b => 0.0
  :c => 0.8

julia> f_score([:a,:b,:a,:c,:c], [:a,:c,:b,:c,:c], avgmode=:micro)
0.6
```
"""
function f_score(targets::AbstractArray,
                 outputs::AbstractArray,
                 encoding::BinaryLabelEncoding,
                 avgmode::AvgMode.None,
                 β::Number = 1.0)
    @_dimcheck length(targets) == length(outputs)
    β² = abs2(β)
    tp::Int = 0; fp::Int = 0; fn::Int = 0
    @inbounds for I in eachindex(targets, outputs)
        target = targets[I]
        output = outputs[I]
        tp += true_positives(target,  output, encoding)
        fp += false_positives(target, output, encoding)
        fn += false_negatives(target, output, encoding)
    end
    (1+β²)*tp / ((1+β²)*tp + β²*fn + fp)
end

f_score(object; beta = 1.0) = f_score(object, beta)
function f_score(object, β::Number)
    β² = abs2(β)
    tp = true_positives(object)
    fp = false_positives(object)
    fn = false_negatives(object)
    (1+β²)*tp / ((1+β²)*tp + β²*fn + fp)
end

# Micro averaging multiclass f-score
function f_score(targets::AbstractArray,
                 outputs::AbstractArray,
                 encoding::LabelEncoding,
                 avgmode::AvgMode.Micro,
                 β::Number = 1.0)
    r = true_positive_rate(targets, outputs, encoding, avgmode)
    p = positive_predictive_value(targets, outputs, encoding, avgmode)
    β² = abs2(β)
    ((1+β²)*(p*r)) / (β²*(p+r))
end

# Macro averaging multiclass f-score
function f_score(targets::AbstractArray,
                 outputs::AbstractArray,
                 encoding::LabelEncoding,
                 avgmode::AverageMode,
                 β::Number = 1.0)
    @_dimcheck length(targets) == length(outputs)
    labels = label(encoding)
    n = length(labels)
    ovr = [LabelEnc.OneVsRest(l) for l in labels]
    precision_ = zeros(n); recall_ = zeros(n)
    @inbounds for j = 1:n
        recall_[j] = true_positive_rate(targets, outputs, ovr[j])
        precision_[j] = positive_predictive_value(targets, outputs, ovr[j])
    end
    β² = abs2(β)
    scores = ((1.0 .+ β²) .* (precision_ .* recall_)) ./ (β² .* (precision_ .+ recall_))
    scores .= ifelse.(isequal.(scores, NaN), zero(eltype(scores)), scores)
    aggregate_score(scores, labels, avgmode)
end

aggregate_score(score, labels, ::AvgMode.None) = Dict(Pair.(labels, score))
aggregate_score(score, labels, ::AvgMode.Macro) = mean(score)
aggregate_score(score, labels, ::AvgMode.Micro) = error("unreachable")

f_score(targets, outputs, encoding::LabelEncoding, β::Number) =
    f_score(targets, outputs, encoding, AvgMode.None(), β)

f_score(targets, outputs, labels::AbstractVector, args...) =
    f_score(targets, outputs, LabelEnc.NativeLabels(labels), args...)

f_score(targets, outputs, β::Number) =
    f_score(targets, outputs, _labelenc(targets, outputs), AvgMode.None(), β)

f_score(targets, outputs, avgmode::AverageMode, β::Number = 1.0) =
    f_score(targets, outputs, _labelenc(targets, outputs), avgmode, β)

f_score(targets, outputs; avgmode=AvgMode.None(), beta::Number = 1.0) =
    f_score(targets, outputs, convert(AverageMode, avgmode), beta)

f_score(targets, outputs, encoding; avgmode=AvgMode.None(), beta::Number = 1.0) =
    f_score(targets, outputs, encoding, convert(AverageMode, avgmode), beta)

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

"""
    f1_score(targets, outputs, [encoding], [avgmode])

Same as [`f_score`](@ref), but with `beta` fixed to 1.
"""
f1_score(object) = f_score(object, 1.0)

f1_score(targets, outputs, enc::LabelEncoding) =
    f_score(targets, outputs, enc, 1.0)

f1_score(targets, outputs, labels::AbstractVector, args...) =
    f_score(targets, outputs, labels, args..., 1.0)

f1_score(targets, outputs, avgmode::AverageMode) =
    f_score(targets, outputs, avgmode, 1.0)

f1_score(targets, outputs, enc::LabelEncoding, avgmode::AverageMode) =
    f_score(targets, outputs, enc, avgmode, 1.0)

f1_score(targets, outputs, enc; avgmode=AvgMode.None()) =
    f_score(targets, outputs, enc, convert(AverageMode, avgmode), 1.0)

f1_score(targets, outputs; avgmode=AvgMode.None()) =
    f_score(targets, outputs, convert(AverageMode, avgmode), 1.0)

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

# TODO: make this work for AvgMode and LabelEncoding
function matthews_corrcoef(target, output)
    @_dimcheck length(target) == length(output)
    tp = true_positives(target, output)
    tn = true_negatives(target, output)
    fp = false_positives(target, output)
    fn = false_negatives(target, output)
    numerator = (tp * tn) - (fp * fn)
    denominator = (tp + fp) * (tp + fn) * (tn + fp) * (tn + fn)
    return(numerator / (denominator ^ 0.5))
end


text:
create(c::Client, ::Type{Role}, g::AbstractGuild; kwargs...) = create_guild_role(c, g.id; kwargs...)

retrieve(c::Client, ::Type{Role}, g::AbstractGuild) = get_guild_roles(c, g.id)

update(c::Client, r::Role, g::AbstractGuild; kwargs...) = modify_guild_role(c, g.id, r.id; kwargs...)

delete(c::Client, r::Role, g::AbstractGuild) = delete_guild_role(c, g.id, r.id)


text:
# Note that this script can accept some limited command-line arguments, run
# `julia build_tarballs.jl --help` to see a usage message.
using BinaryBuilder, Pkg

name = "rocm_smi_lib"
version = v"4.2.0"

# Collection of sources required to complete build
sources = [
    ArchiveSource("https://github.com/RadeonOpenCompute/rocm_smi_lib/archive/refs/tags/rocm-$(version).tar.gz", "c31bf91c492f00d0c5ab21e45afbd7baa990e4a8d7ce9b01e3b988e5fdd53f50")
]

# Bash recipe for building across all platforms
script = raw"""
cd ${WORKSPACE}/srcdir/rocm_smi_lib-rocm-*/
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=${prefix} -DCMAKE_PREFIX_PATH=${prefix} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TARGET_TOOLCHAIN} ..
make -j${nproc}
make install
"""

# These are the platforms we will build for by default, unless further
# platforms are passed in on the command line
platforms = [
    Platform("x86_64", "linux"; libc="glibc"),
    Platform("x86_64", "linux"; libc="musl"),
]
platforms = expand_cxxstring_abis(platforms)

# The products that we will ensure are always built
products = [
    LibraryProduct("liboam", :liboam, "oam/lib"),
    LibraryProduct("librocm_smi64", :librocm_smi, "rocm_smi/lib"),
    FileProduct("rocm_smi/bindings/rsmiBindings.py", :rsmiBindingspy),
    FileProduct("bin/rsmiBindings.py", :rsmiBindingspylink),
    FileProduct("bin/rocm_smi.py", :rocm_smipy)
]

# Dependencies that must be installed before this package can be built
dependencies = [
]

# Build the tarballs, and possibly a `build.jl` as well.
build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies; julia_compat="1.6", preferred_gcc_version = v"8.1.0")

max_stars_repo_name: jakebolewski/Yggdrasil

max_issues_repo_name: jakebolewski/Yggdrasil

max_forks_repo_name: jakebolewski/Yggdrasil


text:
"""
    Params

Stores model struct without parametric types.
"""
module Params end

"""
    Model

module for model.
"""
module Model
struct FooBar{FT,I}
  x::FT
  i::I
end
struct Bar{FT,I,FB}
  x::FT
  i::I
  fb::FB
end
struct Foo{FT,I}
  x::FT
  a::Bar{FT,I}
end
m = Foo(3.0, Bar(1.0, 2, FooBar(4.0, 5)))
end