text:
module DegreesOfFreedom

using Printf: @printf, @sprintf
using StaticArrays: SVector
using LaTeXStrings: latexstring
using ..Spatials: PID, AbstractBond
using ...Interfaces: rank, dimension
using ...Prerequisites: Float, decimaltostr, rawtype
using ...Prerequisites.TypeTraits: efficientoperations
using ...Prerequisites.CompositeStructures: CompositeDict
using ...Mathematics.VectorSpaces: VectorSpace
using ...Mathematics.AlgebraOverFields: SimpleID, ID, Element, Elements

import ..Spatials: pidtype, rcoord, icoord
import ...Interfaces: reset!, update!, sequence
import ...Mathematics.AlgebraOverFields: idpropertynames

export IID, Index, pid, iidtype, iid
export IndexToTuple, DirectIndexToTuple, directindextotuple, FilteredAttributes
export Internal, IDFConfig, Table
export LaTeX, OID, Operator, Operators, isHermitian, twist
export coordpresent, coordabsent
export latexformat, script, oidtype, otype
export Boundary

"""
    IID

The id of an internal degree of freedom.
"""
abstract type IID <: SimpleID end

"""
    Internal

The whole internal degrees of freedom at a single point.
"""
abstract type Internal{I<:IID} <: VectorSpace{I} end

"""
    show(io::IO, i::Internal)

Show an internal.
"""
Base.show(io::IO, i::Internal) = @printf io "%s(%s)" i|>typeof|>nameof join(("$name=$(getfield(i, name))" for name in i|>typeof|>fieldnames), ", ")

"""
    Index{P, I}

The complete index of a degree of freedom, which consist of the spatial part and the internal part.
"""
abstract type Index{P<:PID, I<:IID} <: SimpleID end

"""
    (INDEX::Type{<:Index})(pid::PID, iid::IID) -> INDEX

Get the corresponding index from a pid and an iid.
"""
@generated function (INDEX::Type{<:Index})(pid::PID, iid::IID)
    (INDEX <: UnionAll) ? :(INDEX(convert(Tuple, pid)..., convert(Tuple, iid)...)) : :(rawtype(INDEX)(convert(Tuple, pid)..., convert(Tuple, iid)...))
end

"""
    pidtype(index::Index)
    pidtype(::Type{<:Index{P}}) where {P<:PID}

Get the type of the spatial part of an index.
"""
pidtype(index::Index) = index |> typeof |> pidtype
pidtype(::Type{<:Index{P}}) where {P<:PID} = P

"""
    pid(index::Index) -> PID

Get the spatial part of an index.
"""
@generated function pid(index::Index)
    exprs = [:(getfield(index, $i)) for i = 1:fieldcount(index|>pidtype)]
    return :(rawtype(pidtype(index))($(exprs...)))
end

"""
    iidtype(index::Index)
    iidtype(::Type{<:Index{<:PID, I}}) where {I<:IID}

Get the type of the internal part of an index.
"""
iidtype(index::Index) = index |> typeof |> iidtype
iidtype(::Type{<:Index{<:PID, I}}) where {I<:IID} = I

"""
    iid(index::Index) -> IID

Get the internal part of an index.
"""
@generated function iid(index::Index)
    exprs = [:(getfield(index, $i)) for i = fieldcount(index|>pidtype)+1:fieldcount(index)]
    return :(rawtype(iidtype(index))($(exprs...)))
end

"""
    adjoint(index::Index) -> typeof(index)

Get the adjoint of an index.
"""
Base.adjoint(index::Index) = typeof(index)(index|>pid, index|>iid|>adjoint)

"""
    union(::Type{P}, ::Type{I}) where {P<:PID, I<:IID}

Combine a concrete `PID` type and a concrete `IID` type to a concrete `Index` type.
"""
Base.union(::Type{P}, ::Type{I}) where {P<:PID, I<:IID} = Index{P, I}

"""
    IndexToTuple

The rules for converting an index to a tuple.

As a function, every instance should accept only one positional argument, i.e. the index to be converted to a tuple.
"""
abstract type IndexToTuple <: Function end
Base.:(==)(itt1::T, itt2::T) where {T<:IndexToTuple} = ==(efficientoperations, itt1, itt2)
Base.isequal(itt1::T, itt2::T) where {T<:IndexToTuple} = isequal(efficientoperations, itt1, itt2)

"""
    DirectIndexToTuple

Direct index to tuple.
"""
struct DirectIndexToTuple <: IndexToTuple end

"""
    (indextotuple::DirectIndexToTuple)(index::Index) -> Tuple

Convert an index to tuple directly.
"""
(indextotuple::DirectIndexToTuple)(index::Index) = convert(Tuple, index)

"""
    directindextotuple

Indicate that the conversion from an index to a tuple is direct.
"""
const directindextotuple = DirectIndexToTuple()

"""
    FilteredAttributes(::Type{I}) where {I<:Index}

A method that converts an arbitary index to a tuple, by iterating over the selected attributes in a specific order.
"""
struct FilteredAttributes{N} <: IndexToTuple
    attributes::NTuple{N, Symbol}
end
FilteredAttributes(attrs::Symbol...) = FilteredAttributes(attrs)
FilteredAttributes(::Type{I}) where I<:Index = FilteredAttributes(I|>fieldnames)

"""
    length(indextotuple::FilteredAttributes) -> Int
    length(::Type{<:FilteredAttributes{N}}) where N -> Int

Get the length of the filtered attributes.
"""
Base.length(indextotuple::FilteredAttributes) = indextotuple |> typeof |> length
Base.length(::Type{<:FilteredAttributes{N}}) where {N} = N

"""
    (indextotuple::FilteredAttributes)(index::Index) -> Tuple

Convert an index to tuple by the "filtered attributes" method.
"""
@generated function (indextotuple::FilteredAttributes)(index::Index)
    exprs = [:(getfield(index, indextotuple.attributes[$i])) for i = 1:length(indextotuple)]
    return Expr(:tuple, exprs...)
end

"""
    filter(f::Function, indextotuple::FilteredAttributes) -> FilteredAttributes

Filter the attributes of a "filtered attributes" method.
"""
Base.filter(f::Function, indextotuple::FilteredAttributes) = FilteredAttributes(Tuple(attr for attr in indextotuple.attributes if f(attr)))

"""
    IDFConfig{I}(map::Function, pids::Union{AbstractVector{<:PID}, Tuple{}}=()) where {I<:Internal}

Configuration of the internal degrees of freedom at a lattice.

`map` maps a `PID` to an `Internal`.
"""
struct IDFConfig{I<:Internal, M<:Function, P<:PID} <: CompositeDict{P, I}
    map::M
    contents::Dict{P, I}
end
function IDFConfig{I}(map::Function, pids::Union{AbstractVector{<:PID}, Tuple{}}=()) where {I<:Internal}
    contents = Dict{pids|>eltype, I}()
    for pid in pids
        contents[pid] = map(pid)
    end
    IDFConfig(map, contents)
end

"""
    reset!(config::IDFConfig, pids) -> IDFConfig

Reset the idfconfig with new pids.
"""
function reset!(config::IDFConfig, pids)
    empty!(config)
    for pid in pids
        config[pid] = config.map(pid)
    end
    config
end

"""
    Table{I}(by::IndexToTuple) where {I<:Index}

Index-sequence table.
"""
struct Table{I<:Index, B<:IndexToTuple} <: CompositeDict{I, Int}
    by::B
    contents::Dict{I, Int}
end
Table{I}(by::IndexToTuple) where {I<:Index} = Table(by, Dict{I, Int}())

"""
    Table(indices::AbstractVector{<:Index}, by::IndexToTuple=directindextotuple) -> Table

Convert an sequence of indices to the corresponding index-sequence table.

The input indices will be converted to tuples by the `by` function with the duplicates removed. The resulting unique tuples are sorted, which determines the sequence of the input indices. Note that two indices have the same sequence if their converted tupels are equal to each other.
"""
function Table(indices::AbstractVector{<:Index}, by::IndexToTuple=directindextotuple)
    tuples = [by(index) for index in indices]
    permutation = sortperm(tuples, alg=Base.Sort.QuickSort)
    result = Table{indices|>eltype}(by)
    count = 1
    for i = 1:length(tuples)
        (i > 1) && (tuples[permutation[i]] != tuples[permutation[i-1]]) && (count += 1)
        result[indices[permutation[i]]] = count
    end
    result
end

"""
    Table(config::IDFConfig, by::IndexToTuple=directindextotuple) -> Table

Get the index-sequence table of the whole internal Hilbert spaces at a lattice.
"""
function Table(config::IDFConfig, by::IndexToTuple=directindextotuple)
    result = union(config|>keytype, config|>valtype|>eltype)[]
    for (pid, internal) in config
        for iid in internal
            push!(result, (result|>eltype)(pid, iid))
        end
    end
    Table(result, by)
end

"""
    union(tables::Table...) -> Table

Unite several index-sequence tables.

See [`Table`](@ref) for more details.
"""
function Base.union(tables::Table...)
    @assert mapreduce(table->table.by, ==, tables) "union error: all input tables should have the same `by` attribute."
    indices = (tables|>eltype|>keytype)[]
    for table in tables
        for index in keys(table)
            push!(indices, index)
        end
    end
    Table(indices, tables[1].by)
end

"""
    reverse(table::Table) -> Dict{Int, Set{<:Index}}

Convert an index-sequence table to a sequence-indices table.

Since different indices may correspond to the same sequence, the reverse is a one-to-many map.
"""
function Base.reverse(table::Table)
    result = Dict{Int, Set{table|>keytype}}()
    for (index, seq) in table
        haskey(result, seq) || (result[seq] = Set{table|>keytype}())
        push!(result[seq], index)
    end
    result
end

"""
    reset!(table::Table, indices::AbstractVector{<:Index}) -> Table
    reset!(table::Table, config::IDFConfig) -> Table

Reset a table.
"""
function reset!(table::Table, indices::AbstractVector{<:Index})
    empty!(table)
    tuples = [table.by(index) for index in indices]
    permutation = sortperm(tuples, alg=Base.Sort.QuickSort)
    count = 1
    for i = 1:length(tuples)
        (i > 1) && (tuples[permutation[i]] != tuples[permutation[i-1]]) && (count += 1)
        table[indices[permutation[i]]] = count
    end
    table
end
function reset!(table::Table, config::IDFConfig)
    indices = union(config|>keytype, config|>valtype|>eltype)[]
    for (pid, internal) in config
        for iid in internal
            push!(indices, (indices|>eltype)(pid, iid))
        end
    end
    reset!(table, indices)
end

"""
    LaTeX{SP, SB}(body) where {SP, SB}

LaTeX string representation.
"""
struct LaTeX{SP, SB, B}
    body::B
    function LaTeX{SP, SB}(body=nothing) where {SP, SB}
        @assert isa(SP, Tuple{Vararg{Symbol}}) && isa(SB, Tuple{Vararg{Symbol}}) "LaTeX error: SP and SB must be tuple of symbols."
        new{SP, SB, typeof(body)}(body)
    end
end
latexsuperscript(::Type{<:LaTeX{SP}}) where {SP} = SP
latexsubscript(::Type{<:LaTeX{SP, SB} where SP}) where {SB} = SB

@generated function oidcoord(vector::SVector{N, Float}) where N
    exprs = [:((vector[$i] === -0.0) ? 0.0 : vector[$i]) for i = 1:N]
    return :(SVector($(exprs...)))
end

"""
    OID(index::Index, ::Nothing, ::Nothing, seq::Union{Nothing, Int})
    OID(index::Index, rcoord::SVector{N, Float}, icoord::SVector{N, Float}, seq::Union{Nothing, Int}) where N
    OID(index::Index, rcoord::Vector{Float}, icoord::Vector{Float}, seq::Union{Nothing, Int})
    OID(index::Index; rcoord::Union{Nothing, SVector, Vector{Float}}=nothing, icoord::Union{Nothing, SVector, Vector{Float}}=nothing, seq::Union{Nothing, Int}=nothing)

Operator id.
"""
struct OID{I<:Index, RC<:Union{Nothing, SVector}, IC<:Union{Nothing, SVector}, S<:Union{Nothing, Int}} <: SimpleID
    index::I
    rcoord::RC
    icoord::IC
    seq::S
    OID(index::Index, ::Nothing, ::Nothing, seq::Union{Nothing, Int}) = new{typeof(index), Nothing, Nothing, typeof(seq)}(index, nothing, nothing, seq)
    function OID(index::Index, rcoord::SVector{N, Float}, icoord::SVector{N, Float}, seq::Union{Nothing, Int}) where N
        new{typeof(index), SVector{N, Float}, SVector{N, Float}, typeof(seq)}(index, oidcoord(rcoord), oidcoord(icoord), seq)
    end
end
function OID(index::Index, rcoord::Vector{Float}, icoord::Vector{Float}, seq::Union{Nothing, Int})
    OID(index, SVector{length(rcoord)}(rcoord), SVector{length(icoord)}(icoord), seq)
end
function OID(index::Index;
            rcoord::Union{Nothing, SVector, Vector{Float}}=nothing,
            icoord::Union{Nothing, SVector, Vector{Float}}=nothing,
            seq::Union{Nothing, Int}=nothing
            )
    OID(index, rcoord, icoord, seq)
end
totuple(::Nothing) = nothing
@generated totuple(v::SVector{N}) where {N} = Expr(:tuple, [:(v[$i]) for i = 1:N]...)
Base.hash(oid::OID{<:Index}, h::UInt) = hash((oid.index, totuple(oid.rcoord)), h)
Base.fieldnames(::Type{<:OID}) = (:index, :rcoord, :icoord, :seq)
idpropertynames(::Type{<:ID{OID}}) = (:indexes, :rcoords, :icoords, :seqs)

"""
    show(io::IO, oid::OID)

Show an operator id.
"""
function Base.show(io::IO, oid::OID)
    @printf io "OID(%s" oid.index
    (oid.rcoord === nothing) ? (@printf io ", :") : (@printf io ", %s" oid.rcoord)
    (oid.icoord === nothing) ? (@printf io ", :") : (@printf io ", %s" oid.icoord)
    @printf io ", %s)" (oid.seq === nothing) ? ":" : oid.seq
end

"""
    repr(oid::OID, l::LaTeX) -> String

LaTeX string representation of an oid.
"""
Base.repr(oid::OID, l::LaTeX) = @sprintf "%s^{%s}_{%s}" script(oid, l, Val(:B)) join(script(oid, l, Val(:SP)), ", ") join(script(oid, l, Val(:SB)), ", ")

"""
    adjoint(oid::OID) -> typeof(oid)
    adjoint(oid::ID{OID, N}) where N -> typeof(oid)

Get the adjoint of an operator id.
"""
Base.adjoint(oid::OID) = OID(oid.index', oid.rcoord, oid.icoord, oid.seq)
@generated Base.adjoint(oid::ID{OID, N}) where {N} = Expr(:call, :ID, [:(oid[$i]') for i = N:-1:1]...)

"""
    isHermitian(oid::ID{OID, N}) where N -> Bool

Judge whether an operator id is Hermitian.
"""
function isHermitian(oid::ID{OID, N}) where N
    for i = 1:((N+1)÷2)
        (oid[i]' == oid[N+1-i]) || return false
    end
    return true
end

"""
    script(oid::OID, ::Val{attr}) where attr -> String

Get the `:rcoord/:icoord` script of an oid.
"""
@generated function script(oid::OID, ::Val{attr}) where attr
    @assert attr in (:rcoord, :icoord) "script error: not supported attr($attr)."
    (fieldtype(oid, attr) <: Nothing) ? 'N' : (attr = QuoteNode(attr); :("[$(join(getfield(oid, $attr), ", "))]"))
end

"""
    script(oid::OID, l::LaTeX, ::Val{:B}) -> Any
    script(oid::OID, l::LaTeX, ::Val{:SP}) -> Tuple
    script(oid::OID, l::LaTeX, ::Val{:SB}) -> Tuple

Get the body/superscript/subscript of the latex string representation of an oid.
"""
@generated script(oid::OID, l::LaTeX, ::Val{:B}) = (fieldtype(l, :body) <: Nothing) ? :(oid.index.scope) : :(l.body)
@generated script(oid::OID, l::LaTeX, ::Val{:SP}) = Expr(:tuple, [:(script(oid, Val($super))) for super in QuoteNode.(l|>latexsuperscript)]...)
@generated script(oid::OID, l::LaTeX, ::Val{:SB}) = Expr(:tuple, [:(script(oid, Val($sub))) for sub in QuoteNode.(l|>latexsubscript)]...)

"""
    coordpresent

Indicate that the `:icoord` and `:rcoord` attributes in an oid should not be nothing.
"""
const coordpresent = Val(true)

"""
    coordabsent

Indicate that the `:icoord` and `:rcoord` attributes in an oid should be nothing
"""
const coordabsent = Val(false)

"""
    oidtype(I::Type{<:IID}, B::Type{<:AbstractBond}, ::Type{Nothing}, ::Val{true})
    oidtype(I::Type{<:IID}, B::Type{<:AbstractBond}, ::Type{<:Table}, ::Val{true})
    oidtype(I::Type{<:IID}, B::Type{<:AbstractBond}, ::Type{Nothing}, ::Val{false})
    oidtype(I::Type{<:IID}, B::Type{<:AbstractBond}, ::Type{<:Table}, ::Val{false})

Get the compatible oid type.
"""
oidtype(I::Type{<:IID}, B::Type{<:AbstractBond}, ::Type{Nothing}, ::Val{true}) = OID{union(B|>pidtype, I), SVector{B|>dimension, Float}, SVector{B|>dimension, Float}, Nothing}
oidtype(I::Type{<:IID}, B::Type{<:AbstractBond}, ::Type{<:Table}, ::Val{true}) = OID{union(B|>pidtype, I), SVector{B|>dimension, Float}, SVector{B|>dimension, Float}, Int}
oidtype(I::Type{<:IID}, B::Type{<:AbstractBond}, ::Type{Nothing}, ::Val{false}) = OID{union(B|>pidtype, I), Nothing, Nothing, Nothing}
oidtype(I::Type{<:IID}, B::Type{<:AbstractBond}, ::Type{<:Table}, ::Val{false}) = OID{union(B|>pidtype, I), Nothing, Nothing, Int}

"""
    angle(id::ID{OID}, vectors::AbstractVector{<:AbstractVector{Float}}, values::AbstractVector{Float}) -> Float

Get the total twist phase of an id.
"""
@generated function Base.angle(id::ID{OID}, vectors::AbstractVector{<:AbstractVector{Float}}, values::AbstractVector{Float})
    Expr(:call, :+, [:(angle(id[$i], vectors, values)) for i = 1:rank(id)]...)
end

"""
    Operator{V<:Number, I<:ID{OID}} <: Element{V, I}

Abstract type for an operator.
"""
abstract type Operator{V<:Number, I<:ID{OID}} <: Element{V, I} end
function (O::Type{<:Operator})( value,
                                indexes::NTuple{N, Index};
                                rcoords::Union{Nothing, NTuple{N, SVector{M, Float}}}=nothing,
                                icoords::Union{Nothing, NTuple{N, SVector{M, Float}}}=nothing,
                                seqs::Union{Nothing, NTuple{N, Int}}=nothing
                                ) where {N, M}
    (rcoords === nothing) && (rcoords = ntuple(i->nothing, N))
    (icoords === nothing) && (icoords = ntuple(i->nothing, N))
    (seqs === nothing) && (seqs = ntuple(i->nothing, N))
    return O(value, ID(OID, indexes, rcoords, icoords, seqs))
end

const latexformats = Dict{Symbol, LaTeX}()
"""
    latexformat(T::Type{<:Operator}) -> LaTeX
    latexformat(T::Type{<:Operator}, l::LaTeX) -> LaTeX

Get/Set the latex format for a subtype of `Operator`.
"""
latexformat(T::Type{<:Operator}) = latexformats[nameof(T)]
latexformat(T::Type{<:Operator}, l::LaTeX) = latexformats[nameof(T)] = l

"""
    show(io::IO, opt::Operator)
    show(io::IO, ::MIME"text/latex", opt::Operator)

Show an operator.
"""
Base.show(io::IO, opt::Operator) = @printf io "%s(%s, %s)" nameof(typeof(opt)) decimaltostr(opt.value) opt.id
Base.show(io::IO, ::MIME"text/latex", opt::Operator) = show(io, MIME"text/latex"(), latexstring(repr(opt)))

"""
    adjoint(opt::Operator) -> Operator

Get the adjoint of an operator.
"""
Base.adjoint(opt::Operator) = rawtype(typeof(opt))(opt.value', opt.id')

"""
    repr(opt::Operator, l::Union{LaTeX, Nothing}=nothing) -> String

Get the latex string representation of an operator.
"""
Base.repr(opt::Operator, ::Nothing=nothing) = repr(opt, latexformat(typeof(opt)))
function Base.repr(opt::Operator, l::LaTeX)
    (rank(opt) == 0) && return replace(valuetolatextext(opt.value), " "=>"")
    return @sprintf "%s%s" valuetostr(opt.value) join(NTuple{rank(opt), String}(repr(opt.id[i], l) for i = 1:rank(opt)), "")
end
function valuetostr(v)
    (v == 1) && return ""
    (v == -1) && return "-"
    result = valuetolatextext(v)
    if occursin(" ", result) || (isa(v, Complex) && (real(v) ≠ 0) && (imag(v) ≠ 0))
        bra, ket = occursin("(", result) ? ("[", "]") : ("(", ")")
        result = @sprintf "%s%s%s" bra replace(result, " "=>"") ket
    end
    return result
end
valuetolatextext(value::Union{Real, Complex}) = decimaltostr(value)
function valuetolatextext(value)
    io = IOBuffer()
    if showable(MIME"text/latex"(), value)
        show(IOContext(io, :limit=>false), MIME"text/latex"(), value)
    else
        show(IOContext(io, :limit=>false), MIME"text/plain"(), value)
    end
    return replace(replace(String(take!(io)), "\\begin{equation*}" => ""), "\\end{equation*}" => "")
end

"""
    isHermitian(opt::Operator) -> Bool

Judge whether an operator is Hermitian.
"""
isHermitian(opt::Operator) = isa(opt.value, Real) && isHermitian(opt.id)

"""
    rcoord(opt::Operator) -> SVector

Get the whole rcoord of an operator.
"""
@generated function rcoord(opt::Operator)
    (rank(opt) == 1) && return :(opt.id[1].rcoord)
    (rank(opt) == 2) && return :(opt.id[1].rcoord - opt.id[2].rcoord)
    error("rcoord error: not supported rank($(rank(opt))) of $(nameof(opt)).")
end

"""
    icoord(opt::Operator) -> SVector

Get the whole icoord of an operator.
"""
@generated function icoord(opt::Operator)
    (rank(opt) == 1) && return :(opt.id[1].icoord)
    (rank(opt) == 2) && return :(opt.id[1].icoord - opt.id[2].icoord)
    error("icoord error: not supported rank($(rank(opt))) of $(nameof(opt)).")
end

"""
    sequence(opt::Operator, table=nothing) -> NTuple{rank(opt), Int}

Get the sequence of the oids of an operator according to a table.
"""
@generated function sequence(opt::Operator, table=nothing)
    (table <: Nothing) && return :(opt.id.seqs::NTuple{rank(opt), Int})
    return Expr(:tuple, [:(get(table, opt.id[$i].index, nothing)) for i = 1:rank(opt)]...)
end

"""
    otype

Get the compatible operator type from a term type, a bond type and a table type.
"""
function otype end

"""
    Operators(opts::Operator...)

A set of operators.

Type alias for `Elements{<:ID{OID}, <:Operator}`.
"""
const Operators{I<:ID{OID}, O<:Operator} = Elements{I, O}
Operators(opts::Operator...) = Elements(opts...)

"""
    adjoint(opts::Operators) -> Operators

Get the adjoint of a set of operators.
"""
function Base.adjoint(opts::Operators)
    result = Operators{opts|>keytype, opts|>valtype}()
    for opt in values(opts)
        nopt = opt |> adjoint
        result[nopt.id] = nopt
    end
    return result
end

"""
    repr(opts::Operators, l::Union{LaTeX, Nothing}=nothing) -> String

Get the latex string representation of a set of operators.
"""
function Base.repr(opts::Operators, l::Union{LaTeX, Nothing}=nothing)
    result = String[]
    for (i, opt) in enumerate(values(opts))
        rep = repr(opt, l)
        (i > 1) && (rep[1] != '-') && push!(result, "+")
        push!(result, rep)
    end
    return join(result, "")
end

"""
    show(io::IO, ::MIME"text/latex", opts::Operators)

Show latex formed operators.
"""
Base.show(io::IO, ::MIME"text/latex", opts::Operators) = show(io, MIME"text/latex"(), latexstring(repr(opts)))

"""
    summary(io::IO, opts::Operators)

Print a brief description of a set of operators to an io.
"""
Base.summary(io::IO, opts::Operators) = @printf io "Operators{%s}" valtype(opts)

"""
    isHermitian(opts::Operators) -> Bool

Judge whether a set of operators as a whole is Hermitian.
"""
isHermitian(opts::Operators) = opts == opts'

"""
    twist(operator::Operator, vectors::AbstractVector{<:AbstractVector{Float}}, values::AbstractVector{Float}) -> Operator

Twist an operator.
"""
function twist(operator::Operator, vectors::AbstractVector{<:AbstractVector{Float}}, values::AbstractVector{Float})
    replace(operator, value=operator.value*exp(1im*angle(operator.id, vectors, values)))
end

"""
    Boundary{Names}(values::AbstractVector{Float}, vectors::AbstractVector{<:AbstractVector{Float}}) where Names
    Boundary()

Boundary twist of operators.
"""
struct Boundary{Names, V<:AbstractVector{Float}}
    values::Vector{Float}
    vectors::Vector{V}
    function Boundary{Names}(values::AbstractVector{Float}, vectors::AbstractVector{<:AbstractVector{Float}}) where Names
        @assert length(Names) == length(values) == length(vectors) "Boundary error: dismatched names, values and vectors."
        new{Names, eltype(vectors)}(convert(Vector{Float}, values), vectors)
    end
end
const boundaryemptyvalues = Float[]
const boundaryemptyvectors = SVector{0, Float}[]
Boundary() = Boundary{()}(boundaryemptyvalues, boundaryemptyvectors)

"""
    ==(bound1::Boundary, bound2::Boundary) -> Bool

Judge whether two boundaries conditions are equivalent to each other.
"""
Base.:(==)(bound1::Boundary, bound2::Boundary) = ==(efficientoperations, bound1, bound2)

"""
    isequal(bound1::Boundary, bound2::Boundary) -> Bool

Judge whether two boundaries conditions are equivalent to each other.
"""
Base.isequal(bound1::Boundary, bound2::Boundary) = isequal(efficientoperations, bound1, bound2)

"""
    (bound::Boundary)(operator::Operator) -> Operator
    (bound::Boundary{()})(operator::Operator) -> Operator

Get the boundary twisted operator.
"""
(bound::Boundary)(operator::Operator) = twist(operator, bound.vectors, bound.values)
(bound::Boundary{()})(operator::Operator) = operator

"""
    angle(bound::Boundary, operator::Operator) -> Float
    angle(bound::Boundary{()}, operator::Operator) -> Int

Get the boundary twist phase of an operator.
"""
Base.angle(bound::Boundary, operator::Operator) = angle(operator.id, bound.vectors, bound.values)
Base.angle(bound::Boundary{()}, operator::Operator) = 0

"""
    update!(bound::Boundary{Names}, args...; kwargs...) where Names -> Boundary

Update the values of the boundary twisted phase.
"""
@generated function update!(bound::Boundary{Names}, args...; kwargs...) where Names
    return Expr(:block, [:(bound.values[$i] = get(kwargs, $name, bound.values[$i])) for (i, name) in enumerate(QuoteNode.(Names))]..., :(bound))
end

end #module


text:
# Install all necessary packages upon the first use of this repository
using Pkg
Pkg.add("DataFrames")
Pkg.add("CSV")
Pkg.add("Combinatorics")
Pkg.add("Distributions")
Pkg.add("JuMP")
Pkg.add("GAMS")
Pkg.add("Octavian")
Pkg.add("LoopVectorization")
Pkg.add("CUDA")

ext: jl

max_stars_repo_name: beyondatlas/splitdeliveries

max_issues_repo_name: beyondatlas/splitdeliveries

max_forks_repo_name: beyondatlas/splitdeliveries


text:
function _isavailable_xclip()
    return success(pipeline(`which xclip`))
end

"""
    _xclip() -> AbstractMatrix{<:Colorant}

Paste an image from clipboard using `xclip`
"""
function _xclip()
    img_buf = IOBuffer()

    # Pipe clipboard image to buffer
    if success(pipeline(`xclip -selection clipboard -t image/png -o`; stdout=img_buf))
        try
            # Load image from buffer
            img = load(img_buf)
            return img
        catch
            error("No image in clipboard")
        end
    else
        error("No image in clipboard")
    end
end

"""
    _xclip(img::AbstractMatrix{<:Colorant})

Copy an image to clipboard using `xclip`
"""
function _xclip(img::AbstractMatrix{<:Colorant})
    img_buf = IOBuffer()

    # Save given image to buffer
    save(Stream{format"PNG"}(img_buf), img)

    # Copy to clipboard
    open(`xclip -selection clipboard -t image/png`, "w", stdout) do f
        print(f, String(take!(img_buf)))
    end
end


text:
function OLSestimator(y, x)
    estimate = inv(x' * x) * (x' * y)
    return estimate
end

max_stars_repo_name: jungangl/forecast-machine-learning

max_issues_repo_name: jungangl/forecast-machine-learning

max_forks_repo_name: jungangl/forecast-machine-learning


text:
module PkgTest

using ADMIXTURE, Tar, Test

@info "Download HAPMAP3 data"
download("http://dalexander.github.io/admixture/hapmap3-files.tar.gz",
         joinpath(pwd(), "hapmap3.tar"))
Tar.extract("hapmap3.tar", joinpath(pwd(), "hapmap3"))
HAPMAP3_FILE = "hapmap3/hapmap3"

@testset "help" begin
run(`$ADMIXTURE_EXE --help`)
end

@testset "hapmap3.bed (default)" begin
k = 3
P, Q = admixture(HAPMAP3_FILE * ".bed", k)
@test size(P) == (13928, 3)
@test size(Q) == (324, 3)
pfile = "hapmap3.$k.P"
qfile = "hapmap3.$k.Q"
@test isfile(qfile)
@test isfile(pfile)
rm(qfile, force = true)
rm(pfile, force = true)
end

@testset "hapmap3.bed (-j4, -B3, -c, -s)" begin
k = 3
P, Q = admixture(HAPMAP3_FILE * ".bed", k,
j=8, B=3, C=5, c=5, s=123)
@test size(P) == (13928, 3)
@test size(Q) == (324, 3)
pfile = "hapmap3.$k.P"
qfile = "hapmap3.$k.Q"
sfile = "hapmap3.$k.Q_se"
bfile = "hapmap3.$k.Q_bias"
@test isfile(qfile)
@test isfile(pfile)
@test isfile(sfile)
@test isfile(bfile)
rm(qfile, force = true)
rm(pfile, force = true)
rm(sfile, force = true)
rm(bfile, force = true)
end

@testset "hapmap3.bed (-l, -e)" begin
k, l, e = 3, 500, 0.1
P, Q = admixture(HAPMAP3_FILE * ".bed", k, l=l, e=e, j=8, C=5)
@test size(P) == (13928, 3)
@test size(Q) == (324, 3)
pfile = "hapmap3.$k.P.lambda.$l"
qfile = "hapmap3.$k.Q.lambda.$l"
@test isfile(qfile)
@test isfile(pfile)
rm(qfile, force = true)
rm(pfile, force = true)
end

@info "Clean up HAPMAP3 data"
rm("hapmap3.tar", force = true)
rm("hapmap3", recursive = true)

end # module PkgTest


text:
Float64(x::DoubleFloat{T}) where {T<:IEEEFloat} = Float64(HI(x))
Float32(x::DoubleFloat{T}) where {T<:IEEEFloat} = Float32(Float64(x))
Float16(x::DoubleFloat{T}) where {T<:IEEEFloat} = Float16(Float64(x))

Int128(x::DoubleFloat{T}) where {T<:IEEEFloat} = Int128(round(Base.BigInt, Base.BigFloat(HI(x)) + Base.BigFloat(LO(x))))
Int64(x::DoubleFloat{T}) where {T<:IEEEFloat} = Int64(round(Base.BigInt, Base.BigFloat(HI(x)) + Base.BigFloat(LO(x))))
Int32(x::DoubleFloat{T}) where {T<:IEEEFloat} = Int32(round(Base.BigInt, Base.BigFloat(HI(x)) + Base.BigFloat(LO(x))))
Int16(x::DoubleFloat{T}) where {T<:IEEEFloat} = Int16(round(Base.BigInt, Base.BigFloat(HI(x)) + Base.BigFloat(LO(x))))
Int8(x::DoubleFloat{T}) where {T<:IEEEFloat} = Int8(round(Base.BigInt, Base.BigFloat(HI(x)) + Base.BigFloat(LO(x))))

Base.BigFloat(x::DoubleFloat{T}) where {T<:AbstractFloat} = Base.BigFloat(HI(x)) + Base.BigFloat(LO(x))

Base.BigFloat(x::DoubleFloat{DoubleFloat{T}}) where {T<:IEEEFloat} =
    Base.BigFloat(HI(HI(x))) + Base.BigFloat(LO(HI(x))) + Base.BigFloat(HI(LO(x))) + Base.BigFloat(LO(LO(x)))

for (F,D) in ((:(Base.Float64), :Double64), (:(Base.Float32), :Double32), (:(Base.Float16), :Double16))
  @eval begin
    function $D(x::Base.BigFloat)
        hi = $F(x)
        lo = $F(x - hi)
        return $D(hi, lo)
    end
    $D(x::Base.BigInt) = $D(Base.BigFloat(x))
  end
end

function DoubleFloat{DoubleFloat{T}}(x::Base.BigFloat) where {T<:IEEEFloat}
    hihi = T(x)
    hilo = T(x - hihi)
    lohi = T(x - hihi - hilo)
    lolo = T(x - hihi - hilo - lohi)
    hi = DoubleFloat(hihi, hilo)
    lo = DoubleFloat(lohi, lolo)
    return DoubleFloat(hi, lo)
end
DoubleFloat{DoubleFloat{T}}(x::Base.BigInt) where {T<:IEEEFloat} =
    DoubleFloat{DoubleFloat{T}}(Base.BigFloat(x))

DoubleFloat{T}(x::DoubleFloat{DoubleFloat{T}}) where {T<:IEEEFloat} = HI(x)
DoubleFloat{DoubleFloat{T}}(x::DoubleFloat{T}) where {T<:IEEEFloat} =
    DoubleFloat{DoubleFloat{T}}(x, DoubleFloat(zero(T)))

Double64(x::Irrational{S}) where {S} = Double64(Base.BigFloat(x))
Double32(x::Irrational{S}) where {S} = Double32(Base.BigFloat(x))
Double16(x::Irrational{S}) where {S} = Double16(Base.BigFloat(x))


text:
const AGVec=[
"ARDRegression",
"AdaBoostClassifier",
"AdaBoostRegressor",
"AdditiveChi2Sampler",
"BayesianRidge",
"BernoulliNB",
"BernoulliRBM",
"Binarizer",
"Birch",
"CCA",
"CalibratedClassifierCV",
"ComplementNB",
"DecisionTreeClassifier",
"DecisionTreeRegressor",
"DictionaryLearning",
"ElasticNet",
"ElasticNetCV",
"ExtraTreesClassifier",
"ExtraTreesRegressor",
"FactorAnalysis",
"FastICA",
"FunctionTransformer",
"GaussianNB",
"GaussianProcessClassifier",
"GaussianProcessRegressor",
"GaussianRandomProjection",
"GradientBoostingClassifier",
"GradientBoostingRegressor",
"HuberRegressor",
"IncrementalPCA",
"Isomap",
"KBinsDiscretizer",
"KMeans",
"KNeighborsClassifier",
"KNeighborsRegressor",
"KernelPCA",
"KernelRidge",
"LabelBinarizer",
"LabelEncoder",
"LabelPropagation",
"LabelSpreading",
"Lars",
"LarsCV",
"Lasso",
"LassoCV",
"LassoLars",
"LassoLarsCV",
"LassoLarsIC",
"LatentDirichletAllocation",
"LinearDiscriminantAnalysis",
"LinearRegression",
"LinearSVC",
"LinearSVR",
"LocallyLinearEmbedding",
"LogisticRegression",
"LogisticRegressionCV",
"MLPClassifier",
"MLPRegressor",
"MaxAbsScaler",
"MinMaxScaler",
"MiniBatchDictionaryLearning",
"MiniBatchKMeans",
"MiniBatchSparsePCA",
"MissingIndicator",
"MultiLabelBinarizer",
"MultiTaskElasticNet",
"MultiTaskElasticNetCV",
"MultiTaskLasso",
"MultiTaskLassoCV",
"MultinomialNB",
"NMF",
"NearestCentroid",
"Normalizer",
"NuSVC",
"NuSVR",
"Nystroem",
"OneHotEncoder",
"OrdinalEncoder",
"OrthogonalMatchingPursuit",
"OrthogonalMatchingPursuitCV",
"PCA",
"PLSCanonical",
"PLSRegression",
"PLSSVD",
"PassiveAggressiveClassifier",
"PassiveAggressiveRegressor",
"Perceptron",
"PolynomialFeatures",
"PowerTransformer",
"QuadraticDiscriminantAnalysis",
"QuantileTransformer",
"RANSACRegressor",
"RBFSampler",
"RadiusNeighborsClassifier",
"RadiusNeighborsRegressor",
"RandomForestClassifier",
"RandomForestRegressor",
"RandomTreesEmbedding",
"Ridge",
"RidgeCV",
"RidgeClassifier",
"RidgeClassifierCV",
"RobustScaler",
"SGDClassifier",
"SGDRegressor",
"SVC",
"SVR",
"SimpleImputer",
"SkewedChi2Sampler",
"SparsePCA",
"SparseRandomProjection",
"StandardScaler",
"TheilSenRegressor",
"TransformedTargetRegressor",
"TruncatedSVD"]


text:
module CUSOLVER

using ..CuArrays
using ..CuArrays: libcusolver, @allowscalar, unsafe_free!, @argout, @workspace

using ..CUBLAS: cublasFillMode_t, cublasOperation_t, cublasSideMode_t, cublasDiagType_t
using ..CUSPARSE: cusparseMatDescr_t

using CUDAapi

using CUDAdrv
using CUDAdrv: CUstream

using CUDAnative

using CEnum

# core library
include("libcusolver_common.jl")
include("error.jl")
include("libcusolver.jl")

# low-level wrappers
include("util.jl")
include("wrappers.jl")

# high-level integrations
include("linalg.jl")

const created_dense_handles = IdDict{CuContext,cusolverDnHandle_t}()
const created_sparse_handles = IdDict{CuContext,cusolverSpHandle_t}()
const active_dense_handles = Vector{Union{Nothing,cusolverDnHandle_t}}()
const active_sparse_handles = Vector{Union{Nothing,cusolverSpHandle_t}}()

function dense_handle()
    tid = Threads.threadid()
    if @inbounds active_dense_handles[tid] === nothing
        ctx = context()
        active_dense_handles[tid] = get!(created_dense_handles, ctx) do
            handle = cusolverDnCreate()
            atexit(()->CUDAdrv.isvalid(ctx) && cusolverDnDestroy(handle))
            handle
        end
    end
    @inbounds active_dense_handles[tid]
end

function sparse_handle()
    tid = Threads.threadid()
    if @inbounds active_sparse_handles[tid] === nothing
        ctx = context()
        active_sparse_handles[tid] = get!(created_sparse_handles, ctx) do
            handle = cusolverSpCreate()
            atexit(()->CUDAdrv.isvalid(ctx) && cusolverSpDestroy(handle))
            handle
        end
    end
    @inbounds active_sparse_handles[tid]
end

function __init__()
    resize!(active_dense_handles, Threads.nthreads())
    fill!(active_dense_handles, nothing)

    resize!(active_sparse_handles, Threads.nthreads())
    fill!(active_sparse_handles, nothing)

    CUDAnative.atcontextswitch() do tid, ctx
        # we don't eagerly initialize handles, but do so lazily when requested
        active_dense_handles[tid] = nothing
        active_sparse_handles[tid] = nothing
    end
end

end


text:
function nlp_cvx_001_011(
    optimizer,
    objective_tol,
    primal_tol,
    dual_tol,
    termination_target = TERMINATION_TARGET_LOCAL,
    primal_target = PRIMAL_TARGET_LOCAL,
)
    model = Model(optimizer)

    @variable(model, x)
    @variable(model, y)

    @objective(model, Min, (x - 1)^2 + (y - 2)^2)
    @constraint(model, x + y <= 5)
    @constraint(model, 2 * x - y <= 3)
    @constraint(model, 3 * x + 9 * y >= -10)
    @constraint(model, 10 * x - y >= -20)
    @constraint(model, -x + 2 * y <= 8)

    optimize!(model)

    check_status(model, FEASIBLE_PROBLEM, termination_target, primal_target)
    check_objective(model, 0.0, tol = objective_tol)
    return check_solution([x, y], [1.0, 2.0], tol = primal_tol)
end


text:
import Term.consoles: console_height,
        console_width,
        console,
        err_console,
        Console,
        cursor_position,
        up,
        beginning_previous_line,
        down,
        clear,
        hide_cursor,
        show_cursor,
        line,
        erase_line
import Term: tprint, tprintln

println("\nTesting tprint, stdout temporarily disabled")

@suppress_out begin
    @testset "\e[34mTPRINT" begin
        @test_nothrow tprint("string")
        @test_nothrow tprint("[red]adasd[/red]")
        @test_nothrow tprint("[blue on_green]adasda")
        @test_nothrow tprint("[red]dadas[green]insdai[/green]outssdrse[blue]fsfsf[/blue]")
        @test_nothrow tprint(Panel("test"))
        @test_nothrow tprint(TextBox("test"))
        @test_nothrow tprint(1)
        @test_nothrow tprint(:x)
        @test_nothrow tprint(1, Panel("test"), "test")
        @test_nothrow tprintln("test")
        @test_nothrow tprintln(Panel("test"))
        @test_nothrow tprintln(1, Panel("test"), "test")

        @test_nothrow tprint(stdout, "string")
        @test_nothrow tprint(stdout, "[red]adasd[/red]")
        @test_nothrow tprint(stdout, "[blue on_green]adasda")
        @test_nothrow tprint(stdout, "[red]dadas[green]insdai[/green]outssdrse[blue]fsfsf[/blue]")
        @test_nothrow tprint(stdout, Panel("test"))
        @test_nothrow tprint(stdout, TextBox("test"))
        @test_nothrow tprint(stdout, 1)
        @test_nothrow tprint(stdout, :x)
        @test_nothrow tprint(stdout, 1, Panel("test"), "test")
        @test_nothrow tprintln(stdout, "test")
        @test_nothrow tprintln(stdout, Panel("test"))
        @test_nothrow tprintln(stdout, 1, Panel("test"), "test")
    end
end

@testset "\e[34mCONSOLE" begin
    @test console_height() == displaysize(stdout)[1]
    @test console_height(stdout) == displaysize(stdout)[1]

    @test console_width() == displaysize(stdout)[2]
    @test console_width(stdout) == displaysize(stdout)[2]

    @test Console(stdout) == Console()

    @test_nothrow cursor_position()
    @test_nothrow up()
    @test_nothrow beginning_previous_line()
    @test_nothrow down()
    @test_nothrow clear()
    @test_nothrow hide_cursor()
    @test_nothrow show_cursor()
    @test_nothrow line()

    @test_nothrow cursor_position(stdout)
    @test_nothrow up(stdout)
    @test_nothrow beginning_previous_line(stdout)
    @test_nothrow down(stdout)
    @test_nothrow clear(stdout)
    @test_nothrow hide_cursor(stdout)
    @test_nothrow show_cursor(stdout)
    @test_nothrow line(stdout)

end


text:
import Pkg; Pkg.activate("."); Pkg.instantiate();
include(ARGS[1])
include(ARGS[2])
println("Loading questions ...")
Knet.seed!(11131994)
trnqstns = getQdata(o[:dhome],"train")
valqstns = getQdata(o[:dhome],"val")
println("Loading dictionaries ... ")
qvoc,avoc,i2w,i2a = getDicts(o[:dhome],"dic")
sets = []
push!(sets,miniBatch(trnqstns;B=64))
push!(sets,miniBatch(valqstns;B=64))
trnqstns=nothing;
valqstns=nothing;
#MODEL
#gpu(0)
@show arrtype
if o[:mfile] !=nothing && isfile(o[:mfile])
    M,Mrun,o = loadmodel(o[:mfile])
else
    M    = MACNetwork(o);
    Mrun = MACNetwork(o);
end

for (wr,wi) in zip(params(Mrun),params(M));
    wr.value[:] = wi.value[:]
end
Knet.gc()
#FEATS
trnfeats = loadFeatures(o[:dhome],"train";h5=o[:h5])
valfeats = loadFeatures(o[:dhome],"val";h5=o[:h5])
M,Mrun = train!(M,Mrun,sets,(trnfeats,valfeats),o)

max_stars_repo_name: feyzaakyurek/MAC-Network

max_issues_repo_name: feyzaakyurek/MAC-Network

max_forks_repo_name: feyzaakyurek/MAC-Network


text:
"""
    nodevalue(node)

Get the value associated with a node in a tree.  This removes wrappers such as [`Indexed`](@ref) or [`TreeCursor`](@ref)s.

By default, this function is the identity.

**OPTIONAL**: This should be implemented with any tree for which nodes have some "value" apart from the node itself.
For example, integers cannot themselves be tree nodes, to create a tree in which the "nodes" are integers one can
do something like
```julia
struct IntNode
    value::Int
    children::Vector{IntNode}
end

AbstractTrees.nodevalue(n::IntNode) = n.value
```
"""
nodevalue(node) = node

"""
    nodevalue(tree, node_index)

Get the value of the node specified by `node_index` from the indexed tree object `tree`.

By default, this falls back to `tree[node_index]`.

**OPTIONAL**: Indexed trees only require this if the fallback to `getindex` is not sufficient.
"""
nodevalue(tree, idx) = tree[idx]

"""
    children(node)

Get the immediate children of node `node`.

By default, every object is a parent node of an empty set of children.  This is to make it simpler to define
trees with nodes of different types, for example arrays are trees regardless of their `eltype`.

**REQUIRED**: This is required for all tree nodes with non-empty sets of children.  If it is not possible to infer
the children from the node alone, this should be defined for a wrapper object which does.
"""
children(node) = ()

"""
    nextsibling(node)

Get the next sibling (child of the same parent) of the tree node `node`.  The returned node should be the same as
the node that would be returned after `node` when iterating over `(children ∘ parent)(node)`.

**OPTIONAL**: This function is required for nodes with the [`StoredSiblings`](@ref) trait.  There is no default
definition.
"""
function nextsibling end

"""
    prevsibling(node)

Get the previous sibling (child of the same parent) of the tree node `node`.  The returned node should be the same
as the node that would be returned prior to `node` when iterating over `(children ∘ parent)(node)`.

**OPTIONAL**: This function is optional in all cases.  Default AbstractTrees method assume that it is impossible to
obtain the previous sibling and all iterators act in the "forward" direction.
"""
function prevsibling end

"""
    ischild(node1, node2; equiv=(===))

Check if `node1` is a child of `node2`.

By default this iterates through `children(node2)`, so performance may be improved by adding a
specialized method for given node type.

Equivalence is established with the `equiv` function.  New methods of this function should include this
argument or else it will fall back to `===`.
"""
ischild(node1, node2; equiv=(≡)) = any(node -> equiv(node, node1), children(node2))

"""
    parent(node)

Get the immediate parent of a node `node`.

By default all objects are considered nodes of a trivial tree with no children and no parents.  That is,
the default method is simply `parent(node) = nothing`.

**OPTIONAL**: The 1-argument version of this function must be implemented for nodes with the [`StoredParents`](@ref)
trait.
"""
parent(node) = nothing

"""
    isroot(x)

Whether `x` is the absolute root of a tree.  More specifically, this returns `true` if `parent(x) ≡ nothing`,
or `parent(root, x) ≡ nothing`.  That is, while any node is the root of some tree, this function only returns
true for nodes which have parents which cannot be obtained with the `AbstractTrees` interface.
"""
isroot(root, x) = isnothing(parent(root, x))
isroot(x) = (isnothing ∘ parent)(x)

"""
    intree(node, root; equiv=(≡))

Check if `node` is a member of the tree rooted at `root`.

By default this traverses through the entire tree in search of `node`, and so may be slow if a
more specialized method has not been implemented for the given tree type.

Equivalence is established with the `equiv` function.  Note that new methods should also define `equiv` or calls
may fall back to the default method.

See also: [`isdescendant`](@ref)
"""
intree(node, root; equiv=(≡)) = any(n -> equiv(n, node), PreOrderDFS(root))

"""
    isdescendant(node1, node2; equiv=(≡))

Check if `node1` is a descendant of `node2`. This isequivalent to checking whether `node1` is a
member of the subtree rooted at `node2` (see [`intree`](@ref)) except that a node cannot be a
descendant of itself.

Internally this calls `intree(node1, node2)` and so may be slow if a specialized method of that
function is not available.

Equivalence is established with the `equiv` function.  Note that new methods should also define `equiv` or calls
may fall back to the default method.
"""
isdescendant(node1, node2; equiv=(≡)) = !equiv(node1, node2) && intree(node1, node2; equiv)

"""
    treesize(node)

Get the size of the tree rooted at `node`.

By default this recurses through all nodes in the tree and so may be slow if a more specialized
method has not been implemented for the given type.
"""
treesize(node) = 1 + mapreduce(treesize, +, children(node), init=0)

"""
    treebreadth(node)

Get the number of leaves in the tree rooted at `node`. Leaf nodes have a breadth of one.

By default this recurses through all nodes in the tree and so may be slow if a more specialized
method has not been implemented for the given type.
"""
treebreadth(node) = isempty(children(node)) ? 1 : mapreduce(treebreadth, +, children(node))

"""
    treeheight(node)

Get the maximum depth from `node` to any of its descendants. Leaf nodes have a height of zero.

By default this recurses through all nodes in the tree and so may be slow if a more specialized
method has not been implemented for the given type.
"""
treeheight(node) = isempty(children(node)) ? 0 : 1 + mapreduce(treeheight, max, children(node))

"""
    descendleft(node)

Descend from the node `node` to the first encountered leaf node by recursively calling
[`children`](@ref) and taking the first child.
"""
function descendleft(node)
    ch = children(node)
    isempty(ch) && return node
    descendleft(first(ch))
end

"""
    getroot(node)

Get the root of the tree containing node `node`.  This requires `node` to have the trait [`StoredParents`](@ref).
"""
getroot(node) = getroot(ParentLinks(node), node)
function getroot(::StoredParents, node)
    p = parent(node)
    while true
        isnothing(p) && return node
        node = p
        p = parent(p)
    end
end


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

using Markdown
using InteractiveUtils

# ╔═╡ 0a95c7a9-959a-4d91-9c76-266d352c8ec6
begin
	using PlutoUI
	PlutoUI.TableOfContents(title = "Contents")
end

# ╔═╡ 0b614b64-d774-4be2-b6fc-c6586d6ce46b
using Plots

# ╔═╡ ce37949c-fa81-11eb-2c5f-5356851bed48
md"""
# The Statistics of Card Shuffles
"""

# ╔═╡ 2137cb5a-cf1c-4d31-91a7-edf88c4c3f79
md"""
## Objectives
- Realistically **simulate** the two most common card shuffles
- Lay out a method for **measuring randomness** in a deck of cards
- Compare the two shuffle techniques in regard to their effectiveness
"""

# ╔═╡ 96838eb9-d7ce-4ff2-a0f5-9d9d13d292fc
md"""
## Introduction
In this case study we will give a practical approach to comparing different card shuffles. Simulating card shuffles in a realistic way is not as trivial as it sounds, deciding when a deck is well shuffled is even trickier. For the purpose of this case study we will always work with a deck of 52 distinct cards.
"""

# ╔═╡ 39301101-8962-4db1-a746-c865b0d59db3
md"""
## The Deck of Cards
The first question we have to ask ourselves is how we are going to simulate shuffles on a computer. We will represent the deck of 52 cards with an array containing the integers 1 to 52, initially in order, with 1 being the top card by convention:
"""

# ╔═╡ 4d5e1966-aa3e-4690-9957-33d672ae353f
deck = collect(1:52)

# ╔═╡ 95f00951-0d5c-4757-8826-56ebc3aca32b
md"""
We also need a way to neatly visualise our shuffles. The Julia colour functionality (from the 'Colors' Package) comes in very handy here. The following function displays the deck as a horizontal strip where each card is encoded by a unique colour in the range from blue to red.
"""

# ╔═╡ e54f1fa4-c040-4d9f-99ea-59bfeccdcb3f
displayDeck(deck) = [RGB{Float32}(x/52,0.3,1-x/52) for x in deck]

# ╔═╡ 9d80001b-b967-4cab-b785-978a8c4055cb
displayDeck(deck)

# ╔═╡ 9a596318-209c-4eef-b8a9-50cbb11b2cc0
md"""
## Simulating Card Shuffles
"""

# ╔═╡ 9fb354b9-a7ca-475d-ac3f-1c88d1972d58
md"""
### The Riffle Shuffle

The riffle shuffle is probably the most famous shuffling technique. To perform a riffle shuffle, approximately half of the deck is held in each hand with the thumbs pointing inwards. Then cards are released simultaneous by both thumbs so that they interleave while falling to the table. A perfect riffle shuffle is one where the cards alternate perfectly. There are two types of perfect riffle shuffles, one where the top card moves to be second from the top (called an in-shuffle), and one where the top and bottom cards are preserved (called an out-shuffle).

To simulate a realistic riffle shuffle we will make use of the _**Gilbert–Shannon–Reeds Model**_. To generate a random permutation according to this model, we flip a fair coin 52 times, to determine for each position of the shuffled deck whether it came from the first packet or the second packet. Then we split the initial deck into two packets whose sizes are the number of tails and the number of heads flipped, and use the same coin flip sequence to determine from the bottom of which packet to pull each card of the shuffled deck. This algorithm has been reported to be a good match for experimentally observed outcomes of human riffle shuffling.
"""

# ╔═╡ fa788983-e7e3-48ce-b874-8378563869a3
function riffle(deck, n = 1)
	if n == 0 return copy(deck) end
	bits = rand(Bool, 52)
	newDeck = zeros(Int, 52)
	(l, r) = (1, sum(bits)+1)
	for i in 1:52
		if bits[i] == 1
			newDeck[i] = deck[l]
			l += 1
		else
			newDeck[i] = deck[r]
			r += 1
		end
	end
	return riffle(newDeck, n-1)
end

# ╔═╡ 3f4e23d9-3102-4a1b-b763-ebb6e9264b9a
md"""
In this procedure, $n$ denotes the number of riffles performed sequentially.
"""

# ╔═╡ 61674df8-b398-4ba7-9913-f32822617828
displayDeck(riffle(deck,1))

# ╔═╡ 063aaaa4-1225-4b4b-89f3-7ff3bc205c74
displayDeck(riffle(deck,2))

# ╔═╡ 449066ba-0e05-4c0c-9083-ac1298dc50d0
displayDeck(riffle(deck,3))

# ╔═╡ e21b7bd3-5df7-4eec-8563-dafe24076c4f
md"""
As we increase $n$, the order of the deck looks more and more random, just as expected. After only 3 shuffles however, there is still some clearly visible structure present.
"""

# ╔═╡ e17dba39-871d-4c65-8d66-6fc0ef708c17
md"""
### The Overhand Shuffle

The overhand shuffle is the easiest and most widespread shuffling technique. To perform the shuffle, the deck is gradually transferred from one hand to the other by sliding off small packets from the top of the deck with the thumb of the receiving hand. The process is repeated several times. The randomness of the whole shuffle is increased by the number of small packets in each iteration as well as the number of iterations performed.

To simulate an overhand shuffle, we will pick each of the $51$ positions between adjacient cards as a 'cutting point' with some probability $p$, independent of each other. We then just reverse the order of the resulting packets definied by these cutting points. While the optimal value of $p$ is $1/2$, practically the deck is usually only split into approximately 10 packets. We will therefore use a generous value of $p = 1/5$ to get an expected number of $10.2$ cutting points corresponding to $11.2$ packets.
"""

# ╔═╡ 672a8b21-9b9b-4223-81ea-abed8fad9d0e
function overhand(deck, n = 1, p = 0.2)
	if n == 0 return copy(deck) end
	cuts = push!([i for i in 51:-1:1 if rand() < p], 0)
	newDeck = []
	lastcut = 52
	for c in cuts
		append!(newDeck, deck[c+1:lastcut])
		lastcut = c
	end
	return overhand(newDeck, n-1, p)
end

# ╔═╡ c65b75e0-b974-4d02-b68a-94533310ee32
md"""
Again, $n$ denotes the number of iterations of the shuffle performed.
"""

# ╔═╡ 95c25530-33f6-4de4-acc8-439f039a61a1
displayDeck(overhand(1:52,1))

# ╔═╡ f3e87927-5568-47bc-abcc-fc30afcc129f
displayDeck(overhand(1:52,2))

# ╔═╡ ed9d5dbe-64cd-462f-b937-4fc7880f2dc3
displayDeck(overhand(1:52,3))

# ╔═╡ 1a304723-2f76-4ae9-aa99-638f6e405db4
md"""
Compared to the riffle shuffle, it seems like the overhand shuffle doesn't randomize the deck as quickly. After 3 overhand shuffles there are still quite a few blocks of consecutive cards that have not been seperated. Let's see how we can make the 'effectiveness' of these shuffles more concrete.
"""

# ╔═╡ 626314cb-a77b-4a6a-ac08-132276887030
md"""
## Meassuring Randomness
"""

# ╔═╡ c571311e-5946-4f06-8e9d-d5f8d8ed3430
md"""
### The Kullback–Leibler divergence
Given a reference probability distribution $Q$, the Kullback–Leibler divergence is a measure of how much a second probability distribution $P$ differs from $Q$:

$D_\text{KL}(P\parallel Q) = \sum _x P(x)\log \left(\frac {P(x)}{Q(x)}\right)$

where the sum is over all elements of the probability space in question. Note that the expression is not symmetric in $P$ and $Q$. This is because similarly to a hypothesis test, the distribution $Q$ should be taken as the predicted distribution whereas $P$ is the observed distribution.
"""

# ╔═╡ 62e5ddbf-f908-4b47-a9f8-fee28d82beea
md"""
Unfortunately, we cannot apply this measure to the entire probability space of all permutations since $52! \approx 8.069\times 10^{67}$ is way too large to iterate through. Instead, we will analyse the distribution of final positions of a single card in the deck. If this distribution is close to uniform we can safely assume that the deck is well shuffled. Also note that since the shuffle techniques in consideration treat all cards about equally, we will focus on the card that is initially on top of the deck. If anything, this card will be shuffled least well, as in the beginning it can only 'move' in one direction.
"""

# ╔═╡ d5f0b623-22d3-4476-9d8d-4045fb03650c
function topCardDist(shuffle, n, m)
	dist = zeros(52)
	deck = collect(1:52)
	for i in 1:m
		dist[argmin(shuffle(deck, n))] += 1/m
	end
	return dist
end

# ╔═╡ 257972d2-fcef-48ff-81d3-25d5661a4151
md"""
In this procedure, $n$ denotes the number of sequential interations of the shuffle and $m$ is the number of data points collected for the distribution. We can now use the kullback–leibler divergence to get a metric of how 'far away' a distribution is from the desired, uniform distribution:
"""

# ╔═╡ 11263177-37bb-45de-8310-a3e612d8e652
function KL(dist)
	res = 0.0
	for p in dist
		if p == 0 continue end
		res += p*log(52 * p)
	end
	return res
end

# ╔═╡ 4804d7ac-15ff-4614-8065-43aefecfb56f
md"""
Let us use this measure of randomness to compare the two shuffles:
"""

# ╔═╡ c5c392e8-12ec-438b-9e37-58e36227eaf4
md"""
##### Top Card Distribution of the Riffle Shuffle
"""

# ╔═╡ 2c73ded2-216a-44e0-8c21-c816c289bec3
begin
plot(xlims = (1,52), xlabel = "Position", ylabel = "Frequency")
plot!(topCardDist(riffle, 1, 1000000), label = "1 Iteration")
plot!(topCardDist(riffle, 2, 1000000), label = "2 Iterations")
plot!(topCardDist(riffle, 3, 1000000), label = "3 Iterations")
plot!(topCardDist(riffle, 4, 1000000), label = "4 Iterations")
plot!(topCardDist(riffle, 5, 1000000), label = "5 Iterations")
plot!(topCardDist(riffle, 6, 1000000), label = "6 Iterations")
plot!(topCardDist(riffle, 7, 1000000), label = "7 Iterations")
end

# ╔═╡ 637e1c56-feb2-42e0-9c39-f7ad33616d31
begin
plot(legend = false, xticks = 1:10, ylims = (-0.05,1))
plot!(ylabel = "Kullback–Leibler Divergence", xlabel = "Iterations")
plot!([KL(topCardDist(riffle, n, 100000)) for n in 1:10])
end

# ╔═╡ 96e6723a-0fa7-4cd3-a9b4-fb1fa0dffa40
md"""
As expected, with increased number of iteration the final position of the top card tends to be uniformly distributed. From this data it seems like after 7 iterations of the riffle shuffle there is not much to be gained from doing more iterations.
"""

# ╔═╡ 16077fbd-689f-45bb-b063-1b4aeefe8c59
md"""
##### Top Card Distribution of the Overhand Shuffle
"""

# ╔═╡ eae5a4eb-cc4e-402a-b96c-e036c6838b64
begin
plot(xlims = (1,52), xlabel = "Position", ylabel = "Frequency")
plot!(topCardDist(overhand, 1, 1000000), label = "1 Iteration")
plot!(topCardDist(overhand, 2, 1000000), label = "2 Iterations")
plot!(topCardDist(overhand, 3, 1000000), label = "3 Iterations")
plot!(topCardDist(overhand, 4, 1000000), label = "4 Iterations")
plot!(topCardDist(overhand, 5, 1000000), label = "5 Iterations")
plot!(topCardDist(overhand, 6, 1000000), label = "6 Iterations")
plot!(topCardDist(overhand, 7, 1000000), label = "7 Iterations")
end

# ╔═╡ 4de522e2-8aba-4465-b9d5-4d77d3451687
md"""
Other than for the riffle shuffle, the shape of the distribution alternates between having its peak at the very bottom or the very top of the deck. This is to be expected, since one iteration of the overhand shuffle reverses the deck, roughly speaking. We also note that the convergence to the uniform distribution seems to be much slower than for the riffle shuffle.
"""

# ╔═╡ b8bdb3c3-a57f-4f4e-a20e-2600602d5b81
begin
plot(xticks = 1:2:41, ylims = (-.05,1))
plot!(ylabel = "Kullback–Leibler Divergence", xlabel = "Iterations")
plot!([KL(topCardDist(overhand, n, 10000)) for n in 1:41], label = "Overhand Shuffle")
plot!([KL(topCardDist(riffle, n, 10000)) for n in 1:41], label = "Riffle Shuffle")
end

# ╔═╡ d462dbb3-790b-43b7-98ef-39c2427a0512
md"""
We conclude that the riffle shuffle is the supervior shuffling technique, at least under this metric of effectiveness. The data shows that it takes more than 40 iterations of the overhand shuffle to achieve the same degree of uniformity as riffling the deck 8 times.
"""

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"

[compat]
Plots = "~1.20.1"
PlutoUI = "~0.7.9"
"""

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

[[Adapt]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "3.3.1"

[[ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"

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

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

[[Bzip2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c3598e525718abcc440f69cc6d5f60dda0a1b61e"
uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
version = "1.0.6+5"

[[Cairo_jll]]
deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "e2f47f6d8337369411569fd45ae5753ca10394c6"
uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
version = "1.16.0+6"

[[ColorSchemes]]
deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"]
git-tree-sha1 = "9995eb3977fbf67b86d0a0a0508e83017ded03f2"
uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
version = "3.14.0"

[[ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.0"

[[Colors]]
deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40"
uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
version = "0.12.8"

[[Compat]]
deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"]
git-tree-sha1 = "344f143fa0ec67e47917848795ab19c6a455f32c"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.32.0"

[[CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"

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

[[DataAPI]]
git-tree-sha1 = "ee400abb2298bd13bfc3df1c412ed228061a2385"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.7.0"

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

[[DataValueInterfaces]]
git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
version = "1.0.0"

[[Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"

[[DelimitedFiles]]
deps = ["Mmap"]
uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"

[[Distributed]]
deps = ["Random", "Serialization", "Sockets"]
uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"

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

[[EarCut_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "92d8f9f208637e8d2d28c664051a00569c01493d"
uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5"
version = "2.1.5+1"

[[Expat_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f"
uuid = "2e619515-83b5-522b-bb60-26c02a35a201"
version = "2.2.10+0"

[[FFMPEG]]
deps = ["FFMPEG_jll"]
git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8"
uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
version = "0.4.1"

[[FFMPEG_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "LibVPX_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"]
git-tree-sha1 = "3cc57ad0a213808473eafef4845a74766242e05f"
uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5"
version = "4.3.1+4"

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

[[Fontconfig_jll]]
deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "35895cf184ceaab11fd778b4590144034a167a2f"
uuid = "a3f928ae-7b40-5064-980b-68af3947d34b"
version = "2.13.1+14"

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

[[FreeType2_jll]]
deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "cbd58c9deb1d304f5a245a0b7eb841a2560cfec6"
uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7"
version = "2.10.1+5"

[[FriBidi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91"
uuid = "559328eb-81f9-559d-9380-de523a88c83c"
version = "1.0.10+0"

[[GLFW_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"]
git-tree-sha1 = "dba1e8614e98949abfa60480b13653813d8f0157"
uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89"
version = "3.3.5+0"

[[GR]]
deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "Serialization", "Sockets", "Test", "UUIDs"]
git-tree-sha1 = "182da592436e287758ded5be6e32c406de3a2e47"
uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
version = "0.58.1"

[[GR_jll]]
deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "d59e8320c2747553788e4fc42231489cc602fa50"
uuid = "d2c73de3-f751-5644-a686-071e5b155ba9"
version = "0.58.1+0"

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

[[Gettext_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046"
uuid = "78b55507-aeef-58d4-861c-77aaff3498b1"
version = "0.21.0+0"

[[Glib_jll]]
deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "7bf67e9a481712b3dbe9cb3dac852dc4b1162e02"
uuid = "7746bdde-850d-59dc-9ae8-88ece973131d"
version = "2.68.3+0"

[[Grisu]]
git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2"
uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe"
version = "1.0.2"

[[HTTP]]
deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"]
git-tree-sha1 = "44e3b40da000eab4ccb1aecdc4801c040026aeb5"
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
version = "0.9.13"

[[IniFile]]
deps = ["Test"]
git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8"
uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f"
version = "0.5.0"

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

[[IterTools]]
git-tree-sha1 = "05110a2ab1fc5f932622ffea2a003221f4782c18"
uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
version = "1.3.0"

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

[[JLLWrappers]]
deps = ["Preferences"]
git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.3.0"

[[JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.2"

[[JpegTurbo_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943"
uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8"
version = "2.1.0+0"

[[LAME_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c"
uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d"
version = "3.100.1+0"

[[LZO_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6"
uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac"
version = "2.10.1+0"

[[LaTeXStrings]]
git-tree-sha1 = "c7f1c695e06c01b95a67f0cd1d34994f3e7db104"
uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
version = "1.2.1"

[[Latexify]]
deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"]
git-tree-sha1 = "a4b12a1bd2ebade87891ab7e36fdbce582301a92"
uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
version = "0.15.6"

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

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

[[LibGit2]]
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"

[[LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"

[[LibVPX_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "12ee7e23fa4d18361e7c2cde8f8337d4c3101bc7"
uuid = "dd192d2f-8180-539f-9fb4-cc70b1dcf69a"
version = "1.10.0+0"

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

[[Libffi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "761a393aeccd6aa92ec3515e428c26bf99575b3b"
uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490"
version = "3.2.2+0"

[[Libgcrypt_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"]
git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae"
uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4"
version = "1.8.7+0"

[[Libglvnd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"]
git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf"
uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29"
version = "1.3.0+3"

[[Libgpg_error_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9"
uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8"
version = "1.42.0+0"

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

[[Libmount_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73"
uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9"
version = "2.35.0+0"

[[Libtiff_jll]]
deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"]
git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9"
uuid = "89763e89-9b03-5906-acba-b20f662cd828"
version = "4.3.0+0"

[[Libuuid_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066"
uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700"
version = "2.36.0+0"

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

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

[[MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "0fb723cd8c45858c22169b2e42269e53271a6df7"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.7"

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

[[MbedTLS]]
deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"]
git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe"
uuid = "739be429-bea8-5141-9913-cc70e7f3736d"
version = "1.0.3"

[[MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"

[[Measures]]
git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f"
uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
version = "0.3.1"

[[Missings]]
deps = ["DataAPI"]
git-tree-sha1 = "4ea90bd5d3985ae1f9a908bd4500ae88921c5ce7"
uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
version = "1.0.0"

[[Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"

[[NaNMath]]
git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb"
uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
version = "0.3.5"

[[NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"

[[Ogg_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7937eda4681660b4d6aeeecc2f7e1c81c8ee4e2f"
uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051"
version = "1.3.5+0"

[[OpenSSL_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "15003dcb7d8db3c6c857fda14891a539a8f2705a"
uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
version = "1.1.10+0"

[[Opus_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720"
uuid = "91d4177d-7536-5919-b921-800302f37372"
version = "1.3.2+0"

[[OrderedCollections]]
git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.1"

[[PCRE_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488"
uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc"
version = "8.44.0+0"

[[Parsers]]
deps = ["Dates"]
git-tree-sha1 = "477bf42b4d1496b454c10cce46645bb5b8a0cf2c"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.0.2"

[[Pixman_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29"
uuid = "30392449-352a-5448-841d-b1acce4e97dc"
version = "0.40.1+0"

[[Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

[[PlotThemes]]
deps = ["PlotUtils", "Requires", "Statistics"]
git-tree-sha1 = "a3a964ce9dc7898193536002a6dd892b1b5a6f1d"
uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
version = "2.0.1"

[[PlotUtils]]
deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"]
git-tree-sha1 = "501c20a63a34ac1d015d5304da0e645f42d91c9f"
uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043"
version = "1.0.11"

[[Plots]]
deps = ["Base64", "Contour", "Dates", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs"]
git-tree-sha1 = "8365fa7758e2e8e4443ce866d6106d8ecbb4474e"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
version = "1.20.1"

[[PlutoUI]]
deps = ["Base64", "Dates", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "Suppressor"]
git-tree-sha1 = "44e225d5837e2a2345e69a1d1e01ac2443ff9fcb"
uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
version = "0.7.9"

[[Preferences]]
deps = ["TOML"]
git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.2"

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

[[Qt5Base_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"]
git-tree-sha1 = "ad368663a5e20dbb8d6dc2fddeefe4dae0781ae8"
uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1"
version = "5.15.3+0"

[[REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[[Random]]
deps = ["Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[RecipesBase]]
git-tree-sha1 = "b3fb709f3c97bfc6e948be68beeecb55a0b340ae"
uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
version = "1.1.1"

[[RecipesPipeline]]
deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"]
git-tree-sha1 = "2a7a2469ed5d94a98dea0e85c46fa653d76be0cd"
uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c"
version = "0.3.4"

[[Reexport]]
git-tree-sha1 = "5f6c21241f0f655da3952fd60aa18477cf96c220"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.1.0"

[[Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.1.3"

[[SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"

[[Scratch]]
deps = ["Dates"]
git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda"
uuid = "6c6a2e73-6563-6170-7368-637461726353"
version = "1.1.0"

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

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

[[Showoff]]
deps = ["Dates", "Grisu"]
git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de"
uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
version = "1.0.3"

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

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

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

[[StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "3240808c6d463ac46f1c1cd7638375cd22abbccb"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.2.12"

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

[[StatsAPI]]
git-tree-sha1 = "1958272568dc176a1d881acb797beb909c785510"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.0.0"

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

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

[[Suppressor]]
git-tree-sha1 = "a819d77f31f83e5792a76081eee1ea6342ab8787"
uuid = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
version = "0.2.0"

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

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

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

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

[[Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[[URIs]]
git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355"
uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
version = "1.3.0"

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

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

[[Wayland_jll]]
deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23"
uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89"
version = "1.19.0+0"

[[Wayland_protocols_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll"]
git-tree-sha1 = "2839f1c1296940218e35df0bbb220f2a79686670"
uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91"
version = "1.18.0+4"

[[XML2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a"
uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a"
version = "2.9.12+0"

[[XSLT_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"]
git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a"
uuid = "aed1982a-8fda-507f-9586-7b0439959a61"
version = "1.1.34+0"

[[Xorg_libX11_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"]
git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527"
uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc"
version = "1.6.9+4"

[[Xorg_libXau_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e"
uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec"
version = "1.0.9+4"

[[Xorg_libXcursor_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd"
uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724"
version = "1.2.0+4"

[[Xorg_libXdmcp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4"
uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05"
version = "1.1.3+4"

[[Xorg_libXext_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3"
uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3"
version = "1.3.4+4"

[[Xorg_libXfixes_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4"
uuid = "d091e8ba-531a-589c-9de9-94069b037ed8"
version = "5.0.3+4"

[[Xorg_libXi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"]
git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246"
uuid = "a51aa0fd-4e3c-5386-b890-e753decda492"
version = "1.7.10+4"

[[Xorg_libXinerama_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"]
git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123"
uuid = "d1454406-59df-5ea1-beac-c340f2130bc3"
version = "1.1.4+4"

[[Xorg_libXrandr_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631"
uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484"
version = "1.5.2+4"

[[Xorg_libXrender_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96"
uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa"
version = "0.9.10+4"

[[Xorg_libpthread_stubs_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb"
uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74"
version = "0.1.0+3"

[[Xorg_libxcb_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"]
git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6"
uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b"
version = "1.13.0+3"

[[Xorg_libxkbfile_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2"
uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a"
version = "1.1.0+4"

[[Xorg_xcb_util_image_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97"
uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b"
version = "0.4.0+1"

[[Xorg_xcb_util_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"]
git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1"
uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5"
version = "0.4.0+1"

[[Xorg_xcb_util_keysyms_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00"
uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7"
version = "0.4.0+1"

[[Xorg_xcb_util_renderutil_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e"
uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e"
version = "0.3.9+1"

[[Xorg_xcb_util_wm_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67"
uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361"
version = "0.4.1+1"

[[Xorg_xkbcomp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"]
git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b"
uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4"
version = "1.4.2+4"

[[Xorg_xkeyboard_config_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"]
git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d"
uuid = "33bec58e-1273-512f-9401-5d533626f822"
version = "2.27.0+4"

[[Xorg_xtrans_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845"
uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10"
version = "1.4.0+3"

[[Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"

[[Zstd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6"
uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
version = "1.5.0+0"

[[libass_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "acc685bcf777b2202a904cdcb49ad34c2fa1880c"
uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0"
version = "0.14.0+4"

[[libfdk_aac_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7a5780a0d9c6864184b3a2eeeb833a0c871f00ab"
uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280"
version = "0.1.6+4"

[[libpng_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c"
uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f"
version = "1.6.38+0"

[[libvorbis_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"]
git-tree-sha1 = "c45f4e40e7aafe9d086379e5578947ec8b95a8fb"
uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a"
version = "1.3.7+0"

[[nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"

[[p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"

[[x264_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d713c1ce4deac133e3334ee12f4adff07f81778f"
uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a"
version = "2020.7.14+2"

[[x265_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "487da2f8f2f0c8ee0e83f39d13037d6bbf0a45ab"
uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76"
version = "3.0.0+3"

[[xkbcommon_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"]
git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6"
uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd"
version = "0.9.1+5"
"""

# ╔═╡ Cell order:
# ╟─ce37949c-fa81-11eb-2c5f-5356851bed48
# ╟─2137cb5a-cf1c-4d31-91a7-edf88c4c3f79
# ╟─96838eb9-d7ce-4ff2-a0f5-9d9d13d292fc
# ╟─39301101-8962-4db1-a746-c865b0d59db3
# ╠═4d5e1966-aa3e-4690-9957-33d672ae353f
# ╟─95f00951-0d5c-4757-8826-56ebc3aca32b
# ╠═e54f1fa4-c040-4d9f-99ea-59bfeccdcb3f
# ╠═9d80001b-b967-4cab-b785-978a8c4055cb
# ╟─9a596318-209c-4eef-b8a9-50cbb11b2cc0
# ╟─9fb354b9-a7ca-475d-ac3f-1c88d1972d58
# ╠═fa788983-e7e3-48ce-b874-8378563869a3
# ╟─3f4e23d9-3102-4a1b-b763-ebb6e9264b9a
# ╠═61674df8-b398-4ba7-9913-f32822617828
# ╠═063aaaa4-1225-4b4b-89f3-7ff3bc205c74
# ╠═449066ba-0e05-4c0c-9083-ac1298dc50d0
# ╟─e21b7bd3-5df7-4eec-8563-dafe24076c4f
# ╟─e17dba39-871d-4c65-8d66-6fc0ef708c17
# ╠═672a8b21-9b9b-4223-81ea-abed8fad9d0e
# ╟─c65b75e0-b974-4d02-b68a-94533310ee32
# ╠═95c25530-33f6-4de4-acc8-439f039a61a1
# ╠═f3e87927-5568-47bc-abcc-fc30afcc129f
# ╠═ed9d5dbe-64cd-462f-b937-4fc7880f2dc3
# ╟─1a304723-2f76-4ae9-aa99-638f6e405db4
# ╟─626314cb-a77b-4a6a-ac08-132276887030
# ╟─c571311e-5946-4f06-8e9d-d5f8d8ed3430
# ╟─62e5ddbf-f908-4b47-a9f8-fee28d82beea
# ╠═d5f0b623-22d3-4476-9d8d-4045fb03650c
# ╟─257972d2-fcef-48ff-81d3-25d5661a4151
# ╠═11263177-37bb-45de-8310-a3e612d8e652
# ╟─4804d7ac-15ff-4614-8065-43aefecfb56f
# ╟─c5c392e8-12ec-438b-9e37-58e36227eaf4
# ╟─2c73ded2-216a-44e0-8c21-c816c289bec3
# ╟─637e1c56-feb2-42e0-9c39-f7ad33616d31
# ╟─96e6723a-0fa7-4cd3-a9b4-fb1fa0dffa40
# ╟─16077fbd-689f-45bb-b063-1b4aeefe8c59
# ╟─eae5a4eb-cc4e-402a-b96c-e036c6838b64
# ╟─4de522e2-8aba-4465-b9d5-4d77d3451687
# ╟─b8bdb3c3-a57f-4f4e-a20e-2600602d5b81
# ╟─d462dbb3-790b-43b7-98ef-39c2427a0512
# ╟─0a95c7a9-959a-4d91-9c76-266d352c8ec6
# ╟─0b614b64-d774-4be2-b6fc-c6586d6ce46b
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


text:
module Schrute

export theOffice

using CSV
using DataFrames

const DATA = joinpath(@__DIR__, "theoffice.csv")

"""
    theOffice()

Returns a Data Frame with 12 columns and 55130 rows.
"""
function theOffice()
    df = CSV.read(DATA)
    select!(df, Not(:Column1))
    return df
end

end # module


text:
module Smooth

#Using
using Random
using Distances
using LightGraphs, SimpleWeightedGraphs
using Rectangle
using Dates
# using GraphPlot

# Canvas
export Canvas
export initialize

#Cluster
export Cluster
export add_point_to_cluster
export is_inside_cluster

#LATP
export latp_algorithm

#MobileUser
export MobileUser
export move

include("Cluster.jl")
include("Canvas.jl")
include("LATP.jl")
include("Utils.jl")
include("MobileUser.jl")

end


text:
using NeuroStudies
using Documenter

DocMeta.setdocmeta!(NeuroStudies, :DocTestSetup, :(using NeuroStudies); recursive=true)

makedocs(;
    modules=[NeuroStudies],
    authors="Zachary P. Christensen <zchristensen7@gmail.com> and contributors",
    repo="https://github.com/Tokazama/NeuroStudies.jl/blob/{commit}{path}#{line}",
    sitename="NeuroStudies.jl",
    format=Documenter.HTML(;
        prettyurls=get(ENV, "CI", "false") == "true",
        canonical="https://Tokazama.github.io/NeuroStudies.jl",
        assets=String[],
    ),
    pages=[
        "Home" => "index.md",
    ],
)

deploydocs(;
    repo="github.com/Tokazama/NeuroStudies.jl",
)


text:
using BenchmarkTools
using Random
using GibbsTypePriors

# Define a parent BenchmarkGroup to contain our suite
const SUITE = BenchmarkGroup()

# Add some child groups to our benchmark suite. The most relevant BenchmarkGroup constructor
# for this case is BenchmarkGroup(tags::Vector). These tags are useful for
# filtering benchmarks by topic, which we'll cover in a later section.
SUITE["utf8"] = BenchmarkGroup(["string", "unicode"])

# Add some benchmarks to the "utf8" group
teststr = String(join(rand(MersenneTwister(1), 'a':'d', 10^4)))
SUITE["utf8"]["replace"] = @benchmarkable replace($teststr, "a" => "b")
SUITE["utf8"]["join"] = @benchmarkable join($teststr, $teststr)
SUITE["utf8"]["plots"] = BenchmarkGroup()

# # Add some benchmarks to the "trig" group
# SUITE["trigonometry"] = BenchmarkGroup(["math", "triangles"])
# SUITE["trigonometry"]["circular"] = BenchmarkGroup()
# for f in (sin, cos, tan)
#     for x in (0.0, pi)
#         SUITE["trigonometry"]["circular"][string(f), x] = @benchmarkable ($f)($x)
#     end
# end
#
# SUITE["trigonometry"]["hyperbolic"] = BenchmarkGroup()
# for f in (sin, cos, tan)
#     for x in (0.0, pi)
#         SUITE["trigonometry"]["hyperbolic"][string(f), x] = @benchmarkable ($f)($x)
#     end
# end

SUITE["Cnk"] = BenchmarkGroup()
SUITE["Cnk"]["direct"] = @benchmarkable GibbsTypePriors.Cnk(6, 5, 0.5)
SUITE["Cnk"]["recursive"] = @benchmarkable GibbsTypePriors.Cnk_rec(6, 5, 0.5)
SUITE["Cnk"]["recursive_arb"] = @benchmarkable GibbsTypePriors.Cnk_rec(6, 5, GibbsTypePriors.RR(0.5))
SUITE["Cnk"]["recursive_arb_long"] = @benchmarkable GibbsTypePriors.Cnk_rec(60, 5, GibbsTypePriors.RR(0.5))

SUITE["Vnk"] = BenchmarkGroup()
SUITE["Vnk"]["direct"] = @benchmarkable GibbsTypePriors.Vnk_NGG(950,50, 0.5, 0.2)

max_stars_repo_name: konkam/GibbsTypePriors

max_issues_repo_name: konkam/GibbsTypePriors

max_forks_repo_name: konkam/GibbsTypePriors


text:
module ChebyshevApprox

using LinearAlgebra
using ThreadPools

include("structures.jl")
include("chebyshev_nodes.jl")
include("chebyshev_extrema.jl")
include("chebyshev_extended.jl")
include("vertesi_nodes.jl")
include("chebyshev_quadrature.jl")
include("normalize_node.jl")
include("chebyshev_polynomial.jl")
include("chebyshev_weights.jl")
include("chebyshev_evaluate.jl")
include("chebyshev_derivative.jl")
include("clenshaw_evaluate_generated.jl")

export ChebPoly,
       ChebInterpRoots,
       ChebInterpExtrema,
       ChebInterpExtended,
       ChebInterpVertesi

export chebyshev_nodes,
       chebyshev_extrema,
       chebyshev_extended,
       vertesi_nodes,
       chebyshev_quadrature,
       chebyshev_polynomial,
       chebyshev_weights,
       chebyshev_weights_extrema,
       chebyshev_weights_extended,
       chebyshev_weights_vertesi,
       chebyshev_weights_threaded,
       chebyshev_weights_extrema_threaded,
       chebyshev_weights_extended_threaded,
       chebyshev_weights_vertesi_threaded,
       chebyshev_evaluate,
       cheb_interp,
       chebyshev_derivative,
       chebyshev_gradient,
       clenshaw_evaluate

end

max_issues_repo_name: RJDennis/ChebyshevApprox

max_forks_repo_name: RJDennis/ChebyshevApprox


text:
# This file was generated, do not modify it. # hide
X = [1  2; 3 4]