text:
"""
This function finds the most frequent labels of neighbors
and randomly returns one of them
"""
function maxvote{T}(label_count::Dict{Int,T})
  max_count = maximum(values(label_count))
  candidate_labels = Int[]
  for (k,v) in label_count
    if v == max_count
      push!(candidate_labels, k)
    end
  end
  sample(candidate_labels)
end

"""
Applies the value of label for each neighbor
and calls maxVote function
Use multinomial sampling for speaker rule
Use maximum vote for listener rule
"""
function applyvote!{V}(v::V, g::AbstractGraph{V}, node_memory::Vector{Dict{Int,Int}}, β::Float64=1.0)
  v_neighbors = out_neighbors(v, g)
  v_idx = vertex_index(v, g)
  if length(v_neighbors)>0
    label_list = Dict{Int, Int}()
    for u in v_neighbors
      u_idx = vertex_index(u, g)
      label = sample(collect(keys(node_memory[u_idx])), WeightVec(collect(values(node_memory[u_idx])).^β))
      if haskey(label_list, label)
        label_list[label] += 1
      else
        label_list[label] = 1
      end
    end
    # listener chose a received label to add to memory
    selected_label = maxvote(label_list)
    # add the selected label to the memory
    if haskey(node_memory[v_idx], selected_label)
      node_memory[v_idx][selected_label] += 1
    else
      node_memory[v_idx][selected_label] = 1
    end
  end
end

"""
Applies the value of label for each neighbor
and calls maxVote function
Use multinomial sampling for speaker rule
Use neighbor strength driven for listener rule
"""
function applyvote!{V}(v::V, g::AbstractGraph{V}, node_memory::Vector{Dict{Int,Int}}, ns::Vector{Int}, β::Float64=1.0)
  v_edges = out_edges(v, g)
  v_idx = vertex_index(v, g)
  if length(v_edges)>0
    label_list = Dict{Int, Int}()
    for e in v_edges
      e_idx = edge_index(e, g)
      u = target(e, g)
      u_idx = vertex_index(u, g)
      label = sample(collect(keys(node_memory[u_idx])), WeightVec(collect(values(node_memory[u_idx])).^β))
      if haskey(label_list, label)
        label_list[label] += 1 + ns[e_idx]
      else
        label_list[label] = 1 + ns[e_idx]
      end
    end
    # listener chose a received label to add to memory
    selected_label = maxvote(label_list)
    # add the selected label to the memory
    if haskey(node_memory[v_idx], selected_label)
      node_memory[v_idx][selected_label] += 1
    else
      node_memory[v_idx][selected_label] = 1
    end
  end
end

function slpa{V}(g::AbstractGraph{V}, β::Float64=1.0, iterations::Int=20)
  node_memory = Dict{Int,Int}[]
  for i=1:num_vertices(g)
    push!(node_memory, {i=>1})
  end
  for i=1:iterations
    order = shuffle(collect(vertices(g)))
    for v in order
      applyvote!(v, g, node_memory, β)
    end
  end
  node_memory
end

function slpa{V}(g::AbstractGraph{V}, ns::Vector{Int}, β::Float64=1.0, iterations::Int=20)
  node_memory = Dict{Int,Int}[]
  for i=1:num_vertices(g)
    push!(node_memory, {i=>1})
  end
  for i=1:iterations
    # shuffe nodes order
    order = shuffle(collect(vertices(g)))
    for v in order
      applyvote!(v, g, node_memory, ns, β)
    end
  end
  node_memory
end

function slpa{V}(g::AbstractGraph{V}; r::Float64=0.2, β::Float64=1.0, iterations::Int=20)
  node_memory = slpa(g, β, iterations)
  post_processing!(node_memory, r)
  node_memory
end

function slpa{V}(g::AbstractGraph{V}, ns::Vector{Int}; r::Float64=0.2, β::Float64=1.0, iterations::Int=20)
  node_memory = slpa(g, ns, β, iterations)
  post_processing!(node_memory, r)
  node_memory
end

# performs post processing to remove the labels that are below the threshhold
# r∈[0,1], if the probability is less than r, remove it during post processing
function post_processing!(node_memory::Vector{Dict{Int,Int}}, r::Real)
    for memory in node_memory
        tempmemory = copy(memory)
        sum_count = sum(values(memory))
        threshold = sum_count*r
        for (k,v) in memory
            if v < threshold
                delete!(memory, k)
            end
        end

        # if r is too large to lead to some node_memory empty, we will select label with the max_count
        if isempty(memory)
            selected_label = maxvote(tempmemory)
            memory[selected_label] = tempmemory[selected_label]
        end
    end
end


text:
sir_ode = @ode_def SIRModel begin
    dS = -β * S * I
    dI = β * S * I - γ * I
    dR = γ * I
    end β γ

@model hierarchical_sir_model(grouped_sir, m_countries, country_pops, tspan = [0.0, 365.0], ::Type{T}=Float64) where {T<:Real} = begin
    let T = T, grouped_sir = grouped_sir, m_countries = m_countries, country_pops = country_pops, tspan = tspan

    timepoints = [size(grouped_sir[j], 2) for j in 1:m_countries]
    longest = maximum(timepoints)

    # hierarchical priors across countries
    #   locations
    β_loc ~ truncated(Normal(0, 0.5), 0, Inf)
    γ_loc ~ truncated(Normal(0, 0.5), 0, Inf)
    #   scales
    β_scale ~ truncated(Normal(0, 0.5), 0, Inf)
    γ_scale ~ truncated(Normal(0, 0.5), 0, Inf)

    β = Vector{T}(undef, m_countries)
    γ = Vector{T}(undef, m_countries)
    for j in 1:m_countries
        # prior on infection rate
        β[j] ~ LogNormal(β_loc, β_scale)
        # prior on recovery rate
        γ[j] ~ LogNormal(γ_loc, γ_scale)
    end

    # global prior over measurement noise
    σ ~ LogNormal(0, 2)

    init = Vector{T}(undef, 3)
    sol = Array{T, 2}(undef, 3, longest)

    # likelihood
    for j = 1:m_countries
        init = [(country_pops[j] - 100.0) / country_pops[j], 100.0 / country_pops[j], 0.0]
        sir_prob = ODEProblem(sir_ode, init, tspan)

        sol = concrete_solve(sir_prob, Tsit5(), init, [β[j], γ[j]]; saveat = 1:longest)

        if size(sol, 2) < timepoints[j]
            @logpdf() = zero(1) * sum(grouped_sir[j]) + -Inf
            return
        end

        grouped_sir[j] ~ arraydist([MvNormal(sol[:, i], σ) for i in 1:timepoints[j]])

    end
    end
end

ext: jl


text:
using TropicalTensors
using Test, Random
using Viznet
using Yao
using TropicalYao: hypercubicI

@testset "copy and reset gates" begin
    reg = join(zero_state(Float64, 2), rand_state(Float64, 6))
    focus!(reg, (2,))
    p1 = probs(reg)
    relax!(reg, (2,))
    @test measure(reg, 7; nshots=10) == zeros(10)

    # copy information from 2 to 7
    function gcp(::Type{T}) where T
        matblock(copytensor(T))
    end
    reg |> put(8, (2,7)=>gcp(Float64))
    focus!(reg, (7,))
    p2 = probs(reg)
    relax!(reg, (7,))
    @test_broken p1 ≈ p2
    # sum-reset gate
    function greset(::Type{T}) where T
        matblock([one(T) one(T); zero(T) zero(T)])
    end
    reg |> put(8, 7=>greset(Float64))
    @test measure(reg, 7; nshots=10) == zeros(10)
    focus!(reg, (2,))
    p3 = probs(reg)
    relax!(reg, (2,))
    @test_broken p3 ≈ p1
end

@testset "MaskedSquareLattice" begin
    lt = rand_maskedsquare(4, 4, 1.0)
    sq = SquareLattice(4, 4)
    @test length(TropicalTensors.sgvertices(lt)) == 16
    @test length(TropicalTensors.sgbonds(lt)) == length(bonds(sq, nth=1)) + length(bonds(sq, nth=2))
end

@testset "solve" begin
    lt = rand_maskedsquare(4, 4, 1.0)
    sg = rand_spinglass(Float32, lt; jt=Ferro(), ht=Zero())
    res = solve(sg)
    @test res.n == length(sgbonds(lt))
end

@testset "solve masked" begin
    lt = MaskedSquareLattice([1 1 1 1;
        1 1 0 1;
        1 1 1 1;
        1 1 1 0])
    sg = rand_spinglass(Float64, lt; jt=Ferro(), ht=Zero())
    res = solve(sg)
    @test res.n == 31
end

@testset "fallback cut" begin
    lt = MaskedSquareLattice([0 1; 1 0; 0 1])
    sg = Spinglass(lt, [-1,1], [0,0,0])
    @test solve(sg).n == 2
end

@testset "forwarddiff" begin
    L = 6
    lt = rand_maskedsquare(L, L, 0.8)
    hs = zeros(length(lt))
    Js = rand([-1,1.0], length(sgbonds(lt)))
    res = solve(lt, Js, hs; usecuda=false).n
    gs = ForwardDiff.gradient(x->(dn = solve(lt, eltype(x).(Js), x; usecuda=false).n; (@test ForwardDiff.value(dn)==res); dn), hs)
    function compute_loss(lt, Js, config)
        res = 0.0
        vs = vertices(lt)
        for (i, (src, dst)) in enumerate(sgbonds(lt))
            res += Js[i] * config[findfirst(==(src), vs)] * config[findfirst(==(dst), vs)]
        end
        return res
    end
    @test compute_loss(lt, Js, gs) == res
end


text:
# function SCIPcreate()
#     s = SCIP_t(Array(Ptr{SCIP}, 1))
#     SCIPcreate(s)
#     finalizer(s, s->SCIPfree(s))
#     return s
# end

# Convenience constructors/destructors
{% for type_name, (constructors, destructor) in parser.WRAPPED_TYPES.items() %}{% for constructor in constructors %}{% set sig = parser.checked_functions[constructor] %}{% set arg_types = sig[1] %}{% set arg_names = sig[2] %}{% if type_name == 'SCIP' %}function {{ constructor }}()
    scip = SCIP_t(Array(Ptr{SCIP}, 1))
    {{ constructor }}(scip)
    finalizer(scip, scip->{{ destructor }}(scip))
    return scip
end
{% else %}{% set arg_types2 = [arg_types[0]] + arg_types[2:] %}{% set orig_arg_names = parser.checked_functions_orig[constructor] %}{% set instance_var = orig_arg_names[1] %}function {{ constructor }}({{ arg_types2|join(', ') }})
    {{ instance_var }} = {{ type_name }}_t({{ 'Array(Ptr{%s}, 1)'|format(type_name) }})
    {{ constructor }}({{ orig_arg_names|join(', ') }})
    # TODO: figure out why this causes an exception.
    #finalizer({{ instance_var }}, {{ instance_var }}->{{ destructor }}({{ orig_arg_names[:2]|join(', ') }}))
    return {{ instance_var }}
end
{% endif %}
{% endfor %}{% endfor %}


text:
function H5ReadPhysicalParameter2D(
  h5obj::PyCall.PyObject;
  phptype::H5PhPType,
  xkey::String)

  h5geo = pyimport("h5geopy._h5geo")

  nullValue = h5obj.getNullValue()

  if phptype == VELOCITY
    php = transpose(h5obj.getTrace(0, typemax(Int), 0, typemax(Int), "km/s"))
    # Slowness squared [s^2/km^2]
    php = (1f0 ./ php).^2
  elseif phptype == DENSITY
    php = transpose(h5obj.getTrace(0, typemax(Int), 0, typemax(Int), "g/cm^3"))
  elseif phptype == THETA || phptype == PHI
    php = transpose(h5obj.getTrace(0, typemax(Int), 0, typemax(Int), "rad"))
  else
    php = transpose(h5obj.getTrace(0, typemax(Int), 0, typemax(Int)))
  end

  if isempty(php)
    @error "Unable to read PhysicalParameter. Probably data units incorrect/missing\n"
    return
  end

  if ndims(php) != 2
    @error "PhysicalParameter must be two dimensional array\n"
    return
  end

  # JUDI falls down if NaN are passed
  meanValue = mean(filter(!isnan, php))
  php[isnan.(php)] .= meanValue

  x = h5obj.getTraceHeader(xkey, 0, typemax(Int), h5obj.getLengthUnits(), "m")
  if length(x) < 2
    @error "$(xkey) can't have less than 2 points\n"
    return
  end

  # in case PhysicalParameter is not sorted
  x_ind, x = h5geo.sortv(x)
  php = php[x_ind .+ 1, :]   # C++ returned indexes starts from 0

  # Set up PhysicalParameter structure
  n = size(php)   # (x,y,z) or (x,z)
  d = (x[2]-x[1], abs(h5obj.getSampRate("m")))
  o = (x[1], h5obj.getSRD("m") * (-1))

  return JUDI.PhysicalParameter(php, n, d, o), 0   # the second parameter is the orientation
end

function H5ReadPhysicalParameter3D(
  h5obj::PyCall.PyObject;
  phptype::H5PhPType,
  xkey::String,
  ykey::String)

  h5geo = pyimport("h5geopy._h5geo")

  keylist = ["INLINE", "XLINE"]
  minlist = [-Inf, -Inf]
  maxlist = [Inf, Inf]
  if !h5obj.hasPKeySort(keylist[1])
    @info "Updating trace header limits and adding pkey sort: $pkey..."
    h5obj.updateTraceHeaderLimits(Int(1e7))
    h5obj.addPKeySort(keylist[1])
  end

  if phptype == VELOCITY
    php, il_xl, ind = h5obj.getSortedData(keylist, minlist, maxlist, 0, typemax(Int), "km/s")
    php = (1f0 ./ php).^2
  elseif phptype == DENSITY
    php, il_xl, ind = h5obj.getSortedData(keylist, minlist, maxlist, 0, typemax(Int), "g/cm^3")
  elseif phptype == THETA || phptype == PHI
    php, il_xl, ind = h5obj.getSortedData(keylist, minlist, maxlist, 0, typemax(Int), "rad")
  else
    php, il_xl, ind = h5obj.getSortedData(keylist, minlist, maxlist, 0, typemax(Int))
  end

  if isempty(php)
    @error "Unable to read PhysicalParameter. Probably data units incorrect/missing\n"
    return
  end

  # JUDI falls down if NaN are passed
  meanValue = mean(filter(!isnan, php))
  php[isnan.(php)] .= meanValue

  keylist = [xkey, ykey]
  xy = h5obj.getXYTraceHeaders(keylist, ind, "m", true)
  if isempty(xy)
    @error "Unable to read $(xkey) and $(ykey) trace headers. Probably length units incorrect/missing\n"
    return
  end

  _, uil, uil_from_size = h5geo.sort_unique(il_xl[:,1])
  _, uxl, _ = h5geo.sort_unique(il_xl[:,2])
  nsamp = h5obj.getNSamp()

  nil = length(uil)
  nxl = length(uxl)

  # if the number of XL of each IL is not constant return false
  if !all(uil_from_size[:,2] .== uil_from_size[1,2])
    @error "Selected traces can't be represented as cube\n"
    return
  end

  # p1/p2 - second point on the first IL/XL
  origin = Vector{Float32}(undef, 2)
  origin[1] = xy[1,1]
  origin[2] = xy[1,2]

  p1 = Vector{Float32}(undef, 2)
  p2 = Vector{Float32}(undef, 2)
  if nxl > 1
    p1[1] = xy[2,1]
    p1[2] = xy[2,2]
  else
    p1 = origin
  end

  if nil > 1
    p2[1] = xy[nxl+1,1]
    p2[2] = xy[nxl+1,2]
  else
    p2 = origin
  end

  orientation = 0
  if nxl > 1
    orientation = atan((p1[2]-origin[2])/(p1[1]-origin[1]))
  elseif nil > 1
    orientation = atan((p2[2]-origin[2])/(p2[1]-origin[1]))
  end

  p1_rot = rotate_2xN_array(p1-origin, -orientation) + origin
  p2_rot = rotate_2xN_array(p2-origin, -orientation) + origin
  dx = 0
  dy = 0
  if nxl > 1
    dx = p1_rot[1]-origin[1]
    if dx < 0
      dx = abs(dx)
      origin[1] = origin[1]-dx
      p1_rot[1] = p1_rot[1]+dx
    end
    dy = p2_rot[2]-origin[2]
    if dy < 0
      dy = abs(dy)
      origin[2] = origin[2]-dy
      p2_rot[2] = p2_rot[2]+dy
    end
  elseif nil > 1
    dx = p2_rot[1]-origin[1]
    if dx < 0
      dx = abs(dx)
      origin[1] = origin[1]-dx
      p2_rot[1] = p2_rot[1]+dx
    end
    dy = p1_rot[2]-origin[2]
    if dy < 0
      dy = abs(dy)
      origin[2] = origin[2]-dy
      p1_rot[2] = p1_rot[2]+dy
    end
  end

  php = reshape(php, nsamp, nxl, nil)
  php = permutedims(php, [2,3,1])

  # Set up PhysicalParameter structure
  n = size(php)   # (x,y,z)
  d = (dx, dy, abs(h5obj.getSampRate("m")))
  o = (origin[1], origin[2], h5obj.getSRD("m") * (-1))

  return JUDI.PhysicalParameter(php, n, d, o), orientation
end

function H5ReadPhysicalParameter(
  h5obj::PyCall.PyObject;
  phptype::H5PhPType,
  xkey::String,
  ykey::String)

  h5geo = pyimport("h5geopy._h5geo")

  if h5obj.getSurveyType() == h5geo.SurveyType.TWO_D
    return H5ReadPhysicalParameter2D(h5obj, phptype=phptype, xkey=xkey)
  elseif h5obj.getSurveyType() == h5geo.SurveyType.THREE_D
    return H5ReadPhysicalParameter3D(h5obj, phptype=phptype, xkey=xkey, ykey=ykey)
  else
    @error "H5Object is neither TWO_D nor THREE_D\n"
    return
  end
end

function H5WritePhysicalParameter(;
  cntName::String,
  objName::String,
  cntCreationType::PyCall.PyObject,
  objCreationType::PyCall.PyObject,
  php::JUDI.PhysicalParameter)

  if isnothing(cntName) || length(cntName) < 1
    @error "Container name is empty\n"
    return
  end

  if isnothing(objName) || length(objName) < 1
    @error "Object name is empty\n"
    return
  end

  if isnothing(php) || length(php.data) < 1
    @error "PhysicalParameter is empty\n"
    return
  end

  colada = pyimport("colada")
  h5geo = pyimport("h5geopy._h5geo")

  cnt = h5geo.createSeisContainerByName(cntName, cntCreationType)
  if isnothing(cnt)
    @error "Unable to create SeisContainer: $cntName\n"
    return
  end

  authName = colada.Util().CRSAuthName()
  authCode = string(colada.Util().CRSCode())

  p = h5geo.SeisParam()
  p.spatialReference = "$authName:$authCode"
  p.lengthUnits = colada.Util().lengthUnits()
  p.temporalUnits = colada.Util().timeUnits()
  p.domain = h5geo.Domain.TVD
  p.dataType = h5geo.SeisDataType.STACK

  dims = length(size(php.data))
  TRACE = Matrix{Float32}
  x0 = 0.0; y0 = 0.0; z0 = 0.0
  dx = 0.0; dy = 0.0; dz = 0.0
  nx = 1; ny = 1; nz = 1
  if dims == 2
    p.surveyType = h5geo.SurveyType.TWO_D
    x0 = php.o[1]; z0 = -php.o[2]
    dx = php.d[1]; dz = php.d[2]
    nx = php.n[1]; nz = php.n[2]
    nTrc = nx
    nSamp = nz
    TRACE = permutedims(php.data, (2,1))
  elseif dims == 3
    p.surveyType = h5geo.SurveyType.THREE_D
    x0 = php.o[1]; y0 = php.o[2]; z0 = -php.o[3]
    dx = php.d[1]; dy = php.d[2]; dz = php.d[3]
    nx = php.n[1]; ny = php.n[2]; nz = php.n[3]
    nTrc = nx*ny
    nSamp = nz
    TRACE = reshape(permutedims(php.data, (3,2,1)), (nz, nx*ny))
  else
    @error "PhysicalParameter dimensions is neither 2D or 3D\n"
    return
  end

  p.nTrc = nTrc
  p.nSamp = nSamp

  if nTrc < 1000
    p.trcChunk = nTrc
  else
    p.trcChunk = 1000
  end

  seis = cnt.createSeis(objName, p, objCreationType)
  if isnothing(seis)
    @error "Unable to create Seis: $objName\n"
    return
  end

  # don't forget to set samp rate
  seis.setSampRate(length(php.d) == 2 ? -php.d[2] : -php.d[3], "m")

  val = seis.generateSTKGeometry(x0, dx, nx, y0, dy, ny, z0)
  if isnothing(val)
    @error "Unable to create generate STK geometry for Seis: $objName\n"
    return
  end

  val = seis.writeTrace(TRACE)
  if isnothing(val)
    @error "Unable to write traces: $objName\n"
    return
  end

  seis.getH5File().flush()
end


text:
#=
test_string:
- Julia version: 1.5.0
- Author: shisa
- Date: 2020-08-08
=#

module TestString
    # packages
    using Test

    # external modules
    include("string.jl")
    include("IsUnique/is_unique_chars.jl")
    include("IsUnique/is_unique_bit_vector.jl")
    include("Permutation/check_permutation_sort.jl")
    include("Permutation/check_permutation_count.jl")
    include("URLify/urlify.jl")
    include("Rotation/rotate_string.jl")

    # method
    function test()
        @testset "String" begin
            @test_throws StringIndexError String.get_str2_unicode(2)
            @test_nowarn String.main()
        end
        @testset "IsUnique" begin
            @test UniqueCharChecker.check_unique("abcdefg") == true
            @test UniqueCharChecker.check_unique("aaaaaaaaaaaa") == false
            @test UniqueCharChecker.check_unique("aAbBcCdD") == true
            @test UniqueCharBitChecker.check_unique("axgilnrewqczpoh") == true
            @test UniqueCharBitChecker.check_unique("bbbbbbbb") == false
        end
        @testset "Permutation" begin
            @test SortPermuChecker.check_permu_sort("test", "sett") == true
            @test SortPermuChecker.check_permu_sort("test", "ttew") == false
            @test SortPermuChecker.check_permu_sort("hoge", "hogee") == false
            @test CountPermuChecker.check_permu_count("test", "sett") == true
            @test CountPermuChecker.check_permu_count("abcdefg", "aabbccd") == false
            @test CountPermuChecker.check_permu_count("geeksfor", "forgeeks") == true
        end
        @testset "URLify" begin
            @test URLify.replace_space(" Mr John Smith ") == "Mr%20John%20Smith"
            @test URLify.replace_space("GEEKS FOR GEEKS   ") == "GEEKS%20FOR%20GEEKS"
        end
        @testset "Rotation" begin
            @test Rotation.rotate_left("GeeksForGeeks", 2) == "eksForGeeksGe"
            @test Rotation.rotate_right("GeeksForGeeks", 2) == "ksGeeksForGee"
        end
    end
end

if abspath(PROGRAM_FILE) == @__FILE__
    using .TestString
    TestString.test()
end

max_stars_repo_name: ShisatoYano/JuliaPractice

max_issues_repo_name: ShisatoYano/JuliaPractice

max_forks_repo_name: ShisatoYano/JuliaPractice


text:
# test simple solving
Random.seed!(1234)
sA = sprand(20, 20, 0.1)
b = rand(20)
A = collect(sA)

@test fnnls(sA, b) ≈ fnnls(A, b)
@test nnls(sA, b) ≈ nnls(A, b)
@test pivot(sA, b) ≈ pivot(A, b)
@test nonneg_lsq(sA,b;alg=:pivot, variant=:cache) ≈ nonneg_lsq(A,b;alg=:pivot, variant=:cache)


text:
#######################################################################################################################
module Rename
########################################################################################################################
# imports and exports
using Debugger
using Glob
using JLD

export rename_files

########################################################################################################################

function rename_files()
    fnames = Glob.glob("./ienks-transform/*")
    for name in fnames
        split_name = split(name, "_")
        tmp = [split_name[1:end-7]; ["nens"]; split_name[end-4:end]]
        rename = ""
        string_len = (length(tmp)-1)
        for i in 1:string_len
            rename *= tmp[i] * "_"
        end
        rename *= tmp[end]
        @bp
        print(rename)
        my_command = `mv $name $rename`
        run(my_command)
    end
 end

########################################################################################################################

end

max_stars_repo_name: sukhreens/DataAssimilationBenchmarks

max_issues_repo_name: sukhreens/DataAssimilationBenchmarks

max_forks_repo_name: sukhreens/DataAssimilationBenchmarks


text:
function makeColorColumn(indices::Array{Int,1}, n::Int)::Array{String,1}
    colors = Array{String}(undef, n)
    for i in 1:n
        if i in indices
            colors[i] = " 😔 "
        else
            colors[i] = ""
        end
    end
    return colors
end

function detectOutliers(setting::RegressionSetting; methods=[])

    X = designMatrix(setting)
    y = responseVector(setting)
    return detectOutliers(X, y, methods=methods)

end

function detectOutliers(X::Array{Float64,2}, y::Array{Float64,1}; methods=[])
    if length(methods) == 0
        methods = [
            "hs93",
            "ks89",
            "py95",
            "smr98",
            "lts",
            "sat13",
            "sat15",
            "asm20",
            "bch",
            "bacon",
            "imon2005"
            ]
    end

    n, p = size(X)
    num_algs = length(methods)

    outlier_matrix = DataFrame()

    for method in methods
        if method == "hs93"
            try
                result = hs93(X, y)["outliers"]
            catch
                result = Int[]
            end
        elseif method == "ks89"
            try
                result = ks89(X, y)["outliers"]
            catch
                result = Int[]
            end
        elseif method == "py95"
            result = py95(X, y)["outliers"]
        elseif method == "smr98"
            result = smr98(X, y)["outliers"]
        elseif method == "lts"
            try
                result = lts(X, y)["outliers"]
            catch
                result = Int[]
            end
        elseif method == "sat13"
            result = satman2013(X, y)["outliers"]
        elseif method == "sat15"
            result = satman2015(X, y)["outliers"]
        elseif method == "asm20"
            try
                result = asm2000(X, y)["outliers"]
            catch
                result = Int[]
            end
        elseif method == "bch"
            try
                result = bch(X, y)["outliers"]
            catch
                result = Int[]
            end
        elseif method == "bacon"
            try
                _, p = size(X)
                result = bacon(X, y, m=p + 1)["outliers"]
            catch
                result = Int[]
            end
        elseif method == "imon2005"
            try
                result = imon2005(X, y)["outliers"]
            catch
                result = Int[]
            end
        else
            @error "Method not found " method
            result = Int[]
        end
        outlier_matrix[:, method] = makeColorColumn(result, n)
    end

    return outlier_matrix
end

max_stars_repo_name: jbytecode/LinRegOutliers

max_issues_repo_name: jbytecode/LinRegOutliers

max_forks_repo_name: jbytecode/LinRegOutliers


text:
# ---
# title: 1482. Minimum Number of Days to Make m Bouquets
# id: problem1482
# author: Tian Jun
# date: 2020-10-31
# difficulty: Medium
# categories: Array, Binary Search
# link: <https://leetcode.com/problems/minimum-number-of-days-to-make-m-bouquets/description/>
# hidden: true
# ---
#
# Given an integer array `bloomDay`, an integer `m` and an integer `k`.
#
# We need to make `m` bouquets. To make a bouquet, you need to use `k`
# **adjacent flowers** from the garden.
#
# The garden consists of `n` flowers, the `ith` flower will bloom in the
# `bloomDay[i]` and then can be used in  **exactly one** bouquet.
#
# Return _the minimum number of days_ you need to wait to be able to make `m`
# bouquets from the garden. If it is impossible to make `m` bouquets return
# **-1**.
#
#
#
# **Example 1:**
#
#
#
#     Input: bloomDay = [1,10,3,10,2], m = 3, k = 1
#     Output: 3
#     Explanation: Let's see what happened in the first three days. x means flower bloomed and _ means flower didn't bloom in the garden.
#     We need 3 bouquets each should contain 1 flower.
#     After day 1: [x, _, _, _, _]   // we can only make one bouquet.
#     After day 2: [x, _, _, _, x]   // we can only make two bouquets.
#     After day 3: [x, _, x, _, x]   // we can make 3 bouquets. The answer is 3.
#
#
# **Example 2:**
#
#
#
#     Input: bloomDay = [1,10,3,10,2], m = 3, k = 2
#     Output: -1
#     Explanation: We need 3 bouquets each has 2 flowers, that means we need 6 flowers. We only have 5 flowers so it is impossible to get the needed bouquets and we return -1.
#
#
# **Example 3:**
#
#
#
#     Input: bloomDay = [7,7,7,7,12,7,7], m = 2, k = 3
#     Output: 12
#     Explanation: We need 2 bouquets each should have 3 flowers.
#     Here's the garden after the 7 and 12 days:
#     After day 7: [x, x, x, x, _, x, x]
#     We can make one bouquet of the first three flowers that bloomed. We cannot make another bouquet from the last three flowers that bloomed because they are not adjacent.
#     After day 12: [x, x, x, x, x, x, x]
#     It is obvious that we can make two bouquets in different ways.
#
#
# **Example 4:**
#
#
#
#     Input: bloomDay = [1000000000,1000000000], m = 1, k = 1
#     Output: 1000000000
#     Explanation: You need to wait 1000000000 days to have a flower ready for a bouquet.
#
#
# **Example 5:**
#
#
#
#     Input: bloomDay = [1,10,2,9,3,8,4,7,5,6], m = 4, k = 2
#     Output: 9
#
#
#
#
# **Constraints:**
#
#   * `bloomDay.length == n`
#   * `1 <= n <= 10^5`
#   * `1 <= bloomDay[i] <= 10^9`
#   * `1 <= m <= 10^6`
#   * `1 <= k <= n`
#
#
## @lc code=start
using LeetCode

## add your code here:
## @lc code=end


text:
function getwallpositions2(i, j, paramsx0,paramsy0,paramsx1,paramsy1,paramsdx,paramsdy,paramsnx,paramsny)

northy = paramsy0+(i-1)*paramsdy;
southy = paramsy0+i*paramsdy;

westx = paramsx0+(j-1)*paramsdx;
eastx = paramsx0+j*paramsdx;

return northy, eastx, southy, westx;

end


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

JLLWrappers.@generate_main_file_header("WCS")
JLLWrappers.@generate_main_file("WCS", UUID("550c8279-ae0e-5d1b-948f-937f2608a23e"))
end  # module WCS_jll


text:
# This file is mostly generated by `scripts/generate_precompile.jl`

function _precompile_()
    ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
    try; @assert(Base.precompile(Tuple{typeof(Juno._progress),Expr,Expr})); catch err; @debug err; end
    try; @assert(Base.precompile(Tuple{typeof(Juno._progress),Expr,Float64,Expr,Symbol,Symbol,typeof(Juno._for),Vector{Symbol},Vector{Expr},Expr})); catch err; @debug err; end
    try; @assert(Base.precompile(Tuple{typeof(Juno._progress),Expr})); catch err; @debug err; end
    try; @assert(Base.precompile(Tuple{typeof(Juno._progress),String,Expr})); catch err; @debug err; end
    try; @assert(Base.precompile(Tuple{typeof(Juno._progress),String,Float64,Expr,Expr,Expr,typeof(Juno._comprehension),Vector{Symbol},Vector{Expr},Expr})); catch err; @debug err; end
    try; @assert(Base.precompile(Tuple{typeof(Juno._progress),String,Float64,Expr,Symbol,Symbol,typeof(Juno._for),Vector{Symbol},Vector{Expr},Expr})); catch err; @debug err; end
    try; @assert(Base.precompile(Tuple{typeof(Juno._progress),String,Float64,Expr,Symbol,Symbol,typeof(Juno._for),Vector{Symbol},Vector{Symbol},Expr})); catch err; @debug err; end
    try; @assert(Base.precompile(Tuple{typeof(Juno.isactive)})); catch err; @debug err; end
    try; @assert(Base.precompile(Tuple{typeof(Juno.notify),String})); catch err; @debug err; end
    try; @assert(Base.precompile(Tuple{typeof(Juno.plotsize)})); catch err; @debug err; end
    try; @assert(Base.precompile(Tuple{typeof(selector),Vector{String}})); catch err; @debug err; end
    try; isdefined(Juno, Symbol("#4#8")) && Base.precompile(Tuple{getfield(Juno, Symbol("#4#8")),Expr}); catch err; @debug err; end
    try; isdefined(Juno, Symbol("#5#9")) && Base.precompile(Tuple{getfield(Juno, Symbol("#5#9")),Expr}); catch err; @debug err; end
    try; isdefined(Juno, Symbol("#6#10")) && Base.precompile(Tuple{getfield(Juno, Symbol("#6#10")),Expr}); catch err; @debug err; end
    try; isdefined(Juno, Symbol("#7#11")) && Base.precompile(Tuple{getfield(Juno, Symbol("#7#11")),Expr}); catch err; @debug err; end
end


text:
visbox = MeshCat.Visualizer()
viscylinder = MeshCat.Visualizer()
vissphere = MeshCat.Visualizer()
vispyramid = MeshCat.Visualizer()
vismesh = MeshCat.Visualizer()

animation = MeshCat.Animation(Dict{MeshCat.SceneTrees.Path,MeshCat.AnimationClip}(), 1)

ConstrainedDynamicsVis.preparevis!(storagebox, 1, linkbox.shape, animation, visbox["bundle/bodyshape"], nothing, true, false)
@test true
ConstrainedDynamicsVis.preparevis!(storagecylinder, 1, linkcylinder.shape, animation, viscylinder["bundle/bodyshape"], nothing, true, false)
@test true
ConstrainedDynamicsVis.preparevis!(storagesphere, 1, linksphere.shape, animation, vissphere["bundle/bodyshape"], nothing, true, false)
@test true
ConstrainedDynamicsVis.preparevis!(storagepyramid, 1, linkpyramid.shape, animation, vispyramid["bundle/bodyshape"], nothing, true, false)
@test true
ConstrainedDynamicsVis.preparevis!(storagemesh, 1, linkmesh.shape, animation, vismesh["bundle/bodyshape"], nothing, true, false)
@test true


text:
const A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0]

cost(M::PowerManifold, p) = -0.5 * norm(transpose(p[M, 1]) * A * p[M, 2])^2

function egrad(M::PowerManifold, X::Array)
    U = X[M, 1]
    V = X[M, 2]
    AV = A * V
    AtU = transpose(A) * U
    AR = similar(X)
    AR[:, :, 1] .= -AV * (transpose(AV) * U)
    AR[:, :, 2] .= -AtU * (transpose(AtU) * V)
    return AR
end
struct EGrad{T,TM}
    M::TM
    A::Matrix{T}
end
function (e::EGrad)(Y::Array, X::Array)
    U = X[e.M, 1]
    V = X[e.M, 2]
    AV = A * V
    AtU = transpose(A) * U
    view(Y, :, :, 1) .= -AV * (transpose(AV) * U)
    view(Y, :, :, 2) .= -AtU * (transpose(AtU) * V)
    return Y
end

rgrad(M::PowerManifold, p) = project(M, p, egrad(M, p))
struct RGrad{T,TM}
    egrad::EGrad{T,TM}
end
function RGrad(M::PowerManifold, A::Matrix{T}) where {T}
    return RGrad{T,typeof(M)}(EGrad{T,typeof(M)}(M, A))
end
function (r::RGrad)(M::PowerManifold, X, p)
    return project!(M, X, p, r.egrad(X, p))
end

function e2rHess(M::Grassmann, p, X, e_grad, e_hess)
    return project(M, p, project(M, p, e_hess) - X * (p' * e_grad))
end
function e2rhess!(M::Grassmann, Y, p, X, e_grad, e_Hess)
    project!(M, Y, p, e_Hess)
    Y .-= X * (p' * e_grad)
    return project!(M, Y, p, Y)
end

function eHess(M::AbstractManifold, X::Array{Float64,3}, H::Array{Float64,3})
    U = X[M, 1]
    V = X[M, 2]
    Udot = H[M, 1]
    Vdot = H[M, 2]
    AV = A * V
    AtU = transpose(A) * U
    AVdot = A * Vdot
    AtUdot = transpose(A) * Udot
    R = similar(X)
    #! format: off
    view(R, :, :, 1) .= -(
            AVdot * transpose(AV) * U +
            AV * transpose(AVdot) * U +
            AV * transpose(AV) * Udot
        )
    view(R, :, :, 2) .= -(
            AtUdot * transpose(AtU) * V +
            AtU * transpose(AtUdot) * V +
            AtU * transpose(AtU) * Vdot
        )
    #! format: on
    return R
end
struct EHess{T,TM}
    M::TM
    A::Matrix{T}
end
function (e::EHess)(Y, X, H)
    U = X[e.M, 1]
    V = X[e.M, 2]
    Udot = H[e.M, 1]
    Vdot = H[e.M, 2]
    AV = e.A * V
    AtU = transpose(e.A) * U
    AVdot = e.A * Vdot
    AtUdot = transpose(e.A) * Udot
    #! format: off
    view(Y, :, :, 1) .= -AVdot * transpose(AV) * U - AV * transpose(AVdot) * U - AV * transpose(AV) * Udot
    view(Y, :, :, 2) .= AtUdot * transpose(AtU) * V + AtU * transpose(AtUdot) * V + AtU * transpose(AtU) * Vdot
    #! format: on
    return Y
end

function rhess(M::PowerManifold, p, X)
    eG = egrad(M, p)
    eH = eHess(M, p, X)
    Ha = similar(p)
    for i in 1:2
        e2rhess!(
            M.manifold,
            view(Ha, :, :, i),
            view(p, :, :, i),
            view(X, :, :, i),
            view(eG, :, :, i),
            view(eH, :, :, i),
        )
    end
    return Ha
end
struct RHess{T,TM}
    e_grad!::EGrad{T,TM}
    e_hess!::EHess{T,TM}
    G::Array{T,3}
    H::Array{T,3}
end
function RHess(M::AbstractManifold, A::Matrix{T}, p) where {T}
    return RHess{T,typeof(M)}(
        EGrad(M, A), EHess(M, A), zeros(T, size(A, 1), p, 2), zeros(T, size(A, 1), p, 2)
    )
end
function (r::RHess)(M::PowerManifold, Y, p, X)
    r.e_grad!(r.G, p)
    r.e_hess!(r.H, p, X)
    for i in 1:2
        e2rhess!(
            M.manifold,
            view(Y, :, :, i),
            view(p, :, :, i),
            view(X, :, :, i),
            view(r.G, :, :, i),
            view(r.H, :, :, i),
        )
    end
    return Y
end


text:
export TestCase, runtestsuite

struct TestSuite
    # functionname::Symbol
    cases::Array{TestCase}

    # Common code that should be executed in the grader, solution, and
    # submission contexts.
    # TODO: setupcode doesn't really work right now, oops.
    # This is because the test cases will be defined in terms of the setup
    # code and thus we can't deserialize it. So we'd have to load the setup
    # code separately and load it first.
    # Which I don't want to deal with right now.
    #setupcode::Union{Expr, Nothing}
    setupcode::Nothing
end

TestSuite(cases) = TestSuite(cases, nothing)

struct TestSuiteResult
    # Time elapsed during testing (including the time taken to load the student
    # submission but excluding time taken to setup ComparativeAutograder
    # process internals).
    elapsed_time::Float64

    # The array of produced TestCaseResult's.
    results::Array{TestCaseResult}
end

"""
    runtestsuite(f, suite)

Run the test suite on the specified function.
"""
function runtestsuite(f::Function, suite::TestSuite)::TestSuiteResult
    results = []
    start_time = Base.time()
    for case in suite.cases
        push!(results, runtestcase(f, case))
    end
    end_time = Base.time()
    elapsed_time = end_time - start_time
    @debug "Finished executing TestSuite." elapsed_time
    return TestSuiteResult(
        elapsed_time,
        results,
    )
end


text:
# example from http://openfst.org/twiki/bin/view/FST/ConcatDoc
sym=Dict("$(Char(i))"=>i for i=97:122)

A = WFST(sym)
add_arc!(A,1=>2,"<eps>"=>"<eps>")
add_arc!(A,2=>2,"a"=>"p", 2)
add_arc!(A,2=>3,"b"=>"q", 3)
add_arc!(A,3=>3,"c"=>"r", 4)
add_arc!(A,3=>2,"<eps>"=>"<eps>", 5)
initial!(A,1)
final!(A,1)
final!(A,3,5)
#println(A)

B = WFST(sym)
add_arc!(B,1=>1,"a"=>"p",2)
add_arc!(B,1=>2,"b"=>"q",3)
add_arc!(B,2=>2,"c"=>"r",4)
initial!(B,1)
final!(B,2,5)
#println(A)

W,D = typeofweight(A),Int

C = A*B
#println(C)
@test size(C) == (5,10)
@test get_initial(C; single=false) == Dict(1=>one(W))
@test get_final(C; single=false) == Dict(5=>W(5))
@test C[1][1] == Arc{W,D}(0,0,one(W),2)
@test C[1][2] == Arc{W,D}(0,0,one(W),4)
@test C[2][1] == Arc{W,D}(sym["a"],sym["p"],W(2),2)
@test C[2][2] == Arc{W,D}(sym["b"],sym["q"],W(3),3)
@test C[3][1] == Arc{W,D}(sym["c"],sym["r"],W(4),3)
@test C[3][2] == Arc{W,D}(0,0,W(5),2)
@test C[3][3] == Arc{W,D}(0,0,W(5),4)
@test C[4][1] == Arc{W,D}(sym["a"],sym["p"],W(2),4)
@test C[4][2] == Arc{W,D}(sym["b"],sym["q"],W(3),5)
@test C[5][1] == Arc{W,D}(sym["c"],sym["r"],W(4),5)

B = WFST(sym,["z"]); initial!(B,1); final!(B,2)
@test_throws ErrorException A*B
B = WFST(["z"],sym); initial!(B,1); final!(B,2)
@test_throws ErrorException A*B
B = WFST(sym; W = ProbabilityWeight{Float32}); initial!(B,1); final!(B,2)
@test_throws ErrorException A*B
###
### with deterministic acyclic WFSTs
W = ProbabilityWeight{Float64}
isym=Dict("$(Char(i))"=>i for i=97:122)
osym=Dict(Char(i)=>i for i=97:122)
A = WFST(isym,osym; W = W)
add_arc!(A,1=>2,"a"=>'a',1)
add_arc!(A,2=>4,"b"=>'b',2)
add_arc!(A,2=>3,"c"=>'c',3)
add_arc!(A,3=>4,"d"=>'d',4)
add_arc!(A,1=>4,"e"=>'e',5)
initial!(A,1)
final!(A,3,6)
final!(A,4,7)
println(A)

B = WFST(isym,osym; W = W)
add_arc!(B,1=>2,"x"=>'x',8)
add_arc!(B,1=>3,"y"=>'y',9)
initial!(B,1)
final!(B,2,10)
final!(B,3,11)
println(B)

pas = collectpaths(A)
pbs = collectpaths(B)
C = A*B
pcs = collectpaths(C)
@test all([pa*pb in pcs for pa in pas, pb in pbs])

C = B*A
pcs = collectpaths(C)
@test all([pb*pa in pcs for pa in pas, pb in pbs])

C = A*A
pcs = collectpaths(C)
@test all([pa*pa in pcs for pa in pas, pb in pbs])

C = B*B
pcs = collectpaths(C)
@test all([pb*pb in pcs for pa in pas, pb in pbs])


text:
"""
    AbstractDifference

Supertype for differences.
"""
abstract type AbstractDifference end

"""
    VectorDifference{Tm<:AbstractVector,Ta<:AbstractVector,Tr<:AbstractVector} <: AbstractDifference

Vector difference.
"""
struct VectorDifference{Tm<:AbstractVector,Ta<:AbstractVector,Tr<:AbstractVector} <: AbstractDifference
    modinds::Vector{Int}
    addinds::Vector{Int}
    reminds::Vector{Int}
    modvals::Tm
    addvals::Ta
    remvals::Tr
end

"""
    MatrixDifference{Tm<:AbstractVector,Ta<:AbstractVector,Tr<:AbstractVector} <: AbstractDifference

Matrix difference.
"""
struct MatrixDifference{Tm<:AbstractVector,Ta<:AbstractVector,Tr<:AbstractVector} <: AbstractDifference
    modinds::NTuple{2,Vector{Int}}
    addinds::NTuple{2,Vector{Int}}
    reminds::NTuple{2,Vector{Int}}
    modvals::Tm
    addvals::Ta
    remvals::Tr
end

"""
    DictDifference{Tm<:AbstractDict,Ta<:AbstractDict,Tr<:AbstractDict} <: AbstractDifference

Dictionary difference.
"""
struct DictDifference{Tm<:AbstractDict,Ta<:AbstractDict,Tr<:AbstractDict} <: AbstractDifference
    modvals::Tm
    addvals::Ta
    remvals::Tr
end

"""
    NamedTupleDifference{Tm<:NamedTuple,Ta<:NamedTuple,Tr<:NamedTuple} <: AbstractDifference

Named tuple difference.
"""
struct NamedTupleDifference{Tm<:NamedTuple,Ta<:NamedTuple,Tr<:NamedTuple} <: AbstractDifference
    modvals::Tm
    addvals::Ta
    remvals::Tr
end

"""
    SetDifference{Tc,Ta,Tr} <: AbstractDifference

Set difference.
"""
struct SetDifference{Tc,Ta,Tr} <: AbstractDifference
    comvals::Set{Tc}
    addvals::Set{Ta}
    remvals::Set{Tr}
end

# Equality operator
function Base.:(==)(a::Ta, b::Tb) where {Ta<:AbstractDifference,Tb<:AbstractDifference}
    a === b && return true
    nameof(Ta) == nameof(Tb) || return false
    fields = fieldnames(Ta)
    fields === fieldnames(Tb) || return false
    for f in fields
        getfield(a, f) == getfield(b, f) || return false
    end
    return true
end

# Hash code
function Base.hash(a::T, h::UInt) where {T<:AbstractDifference}
    hashval = hash(:T, h)
    for f in fieldnames(T)
        hashval = hash(getfield(a, f), hashval)
    end
    return hashval
end

"""
    added_indices(a::Union{VectorDifference,MatrixDifference})

Access the added indices.
"""
added_indices(a::Union{VectorDifference,MatrixDifference}) = a.addinds

"""
    removed_indices(a::Union{VectorDifference,MatrixDifference})

Access the removed indices.
"""
removed_indices(a::Union{VectorDifference,MatrixDifference}) = a.reminds

"""
    modified_indices(a::Union{VectorDifference,MatrixDifference})

Access the modified indices.
"""
modified_indices(a::Union{VectorDifference,MatrixDifference}) = a.modinds

"""
    added(a::AbstractDifference)

Access the added elements.
"""
added(a::AbstractDifference) = a.addvals

"""
    removed(a::AbstractDifference)

Access the removed elements.
"""
removed(a::AbstractDifference) = a.remvals

"""
    modified(a::Union{VectorDifference,MatrixDifference,DictDifference,NamedTupleDifference})

Access the modified elements.
"""
modified(a::Union{VectorDifference,MatrixDifference,DictDifference,NamedTupleDifference}) =
    a.modvals

"""
    common(a::SetDifference)

Access the common elements.
"""
common(a::SetDifference) = a.comvals


text:
module CirrusCI

export iscirrus

iscirrus() = parse(Bool, get(ENV, "CIRRUS_CI", "false"))

end # module


text:
### convlayers

@doc raw"""
    function layerBackProp(
        cLayer::ConvLayer,
        model::Model,
        actFun::SoS,
        Ao::AbstractArray,
        labels::AbstractArray,
    ) where {SoS<:Union{Type{softmax},Type{σ}}}

Derive the loss function to the input of the activation function when activation is either `softmax` or `σ`

# Return

- `dZ::AbstractArray` := the derivative of the loss function to the input of the activation function
"""
function layerBackProp(
    cLayer::ConvLayer,
    model::Model,
    actFun::SoS,
    Ao::AbstractArray,
    labels::AbstractArray,
) where {SoS<:Union{Type{softmax},Type{σ}}}

    lossFun = model.lossFun
    dlossFun = Symbol("d", lossFun)
    Y = labels
    dZ = eval(:($dlossFun($Ao, $Y)))

    return dZ
end #softmax or σ layerBackProp

@doc raw"""
    function layerBackProp(
        cLayer::ConvLayer,
        model::Model,
        FCache::Dict{Layer, Dict{Symbol, AbstractArray}},
        BCache::Dict{Layer, Dict{Symbol, AbstractArray}},
        Ai::AbstractArray = Array{Any,1}(undef,0),
        Ao::AbstractArray = Array{Any,1}(undef,0),
        dAo::AbstractArray = Array{Any,1}(undef,0);
        labels::AbstractArray = Array{Any,1}(undef,0),
        kwargs...
    )

Performs the layer back propagation for a `ConvLayer`

# Arguments

- `cLayer::ConvLayer`

- `model::Model`

- `FCache` := the cache of the forward propagation step

- `BCache` := the cache of so far done back propagation

- for test purpose
    Ai
    Ao
    dAo

- `labels` := when `cLayer` is an output `Layer`

# Return

- `Dict(:dA => dAi)`
"""
function layerBackProp(
    cLayer::CL,
    model::Model,
    FCache::Dict{Layer, Dict{Symbol, AbstractArray}},
    BCache::Dict{Layer, Dict{Symbol, AbstractArray}},
    Ai::AbstractArray = Array{Any,1}(undef,0),
    Ao::AbstractArray = Array{Any,1}(undef,0),
    dAo::AbstractArray = Array{Any,1}(undef,0);
    labels::AbstractArray = Array{Any,1}(undef,0),
    kwargs...
) where {CL <: ConvLayer}

    kwargs = Dict{Symbol, Any}(kwargs...)
    NNlib = getindex(kwargs, :NNlib; default=true)
    img2col = getindex(kwargs, :img2col; default=true)

    if length(Ai) == 0
        Ai = FCache[cLayer.prevLayer][:A]
    end
    if length(Ao) == 0
        Ao = FCache[cLayer][:A]
    end
    m = size(Ao)[end]

    regulization, λ = model.regulization, model.λ

    actFun = cLayer.actFun

    dZ = []
    if cLayer.actFun == model.outLayer.actFun
        dZ = layerBackProp(cLayer, model, eval(:($actFun)), Ao, labels)
    elseif length(dAo) != 0
        dActFun = Symbol("d", cLayer.actFun)

        Z = FCache[cLayer][:Z]

        dZ = dAo .* eval(:($dActFun($Z)))
    elseif all(
        i -> (i.backCount == cLayer.nextLayers[1].backCount),
        cLayer.nextLayers,
    )
        dAo = []
        for nextLayer in cLayer.nextLayers
            try
                dAo .+= getLayerSlice(cLayer, nextLayer, BCache)
            catch e
                dAo = getLayerSlice(cLayer, nextLayer, BCache) #need to initialize dA
            end #try/catch
        end #for

        dActFun = Symbol("d", cLayer.actFun)

        Z = FCache[cLayer][:Z]

        dZ = dAo .* eval(:($dActFun($Z)))

    else #in case not every next layer done backprop
        return Dict(:dA => Array{Any,1}(undef,0))

    end #if all(i->(i.backCount==cLayer.nextLayers[1].backCount), cLayer.nextLayers)

    dAi = zeros(promote_type(eltype(Ai),eltype(dZ)), size(Ai))

    if NNlib
        dNNConv!(cLayer, Ai, dAi, dZ)
    elseif img2col
        dimg2colConvolve!(cLayer, Ai, dAi, dZ)
    else
        dconvolve!(cLayer, Ai, dAi, dZ)
    end #if NNlib

    cLayer.backCount += 1

    return Dict(:dA => dAi)
end #function layerBackProp(cLayer::Input

### Pooling Layers

#import only the needed parts not to have conflict
import NNlib.∇maxpool, NNlib.∇meanpool, NNlib.∇maxpool!, NNlib.∇meanpool!, NNlib.PoolDims

@doc raw"""
layerBackProp(
    cLayer::PoolLayer,
    model::Model,
    FCache::Dict{Layer, Dict{Symbol, AbstractArray}},
    BCache::Dict{Layer, Dict{Symbol, AbstractArray}},
    Ai::AbstractArray = Array{Any,1}(undef,0),
    Ao::AbstractArray = Array{Any,1}(undef,0),
    dAo::AbstractArray = Array{Any,1}(undef,0);
    labels::AbstractArray = Array{Any,1}(undef,0),
    kwargs...
)

Performs the layer back propagation for a `PoolLayer`

# Arguments

- `cLayer::ConvLayer`

- `model::Model`

- `FCache` := the cache of the forward propagation step

- `BCache` := the cache of so far done back propagation

- for test purpose
    Ai
    Ao
    dAo

- `labels` := when `cLayer` is an output `Layer`

# Return

- `Dict(:dA => dAi)`
"""
function layerBackProp(
    cLayer::PL,
    model::Model,
    FCache::Dict{Layer, Dict{Symbol, AbstractArray}},
    BCache::Dict{Layer, Dict{Symbol, AbstractArray}},
    Ai::AbstractArray = Array{Any,1}(undef,0),
    Ao::AbstractArray = Array{Any,1}(undef,0),
    dAo::AbstractArray = Array{Any,1}(undef,0);
    labels::AbstractArray = Array{Any,1}(undef,0),
    kwargs...
) where {PL <: PoolLayer}

    kwargs = Dict{Symbol, Any}(kwargs...)

    fastPool = getindex(kwargs, :fastPool; default=true)
    NNlib = getindex(kwargs, :NNlib; default=true)
    if length(Ai) == 0
        Ai = FCache[cLayer.prevLayer][:A]
    end
    if length(Ao) == 0
        Ao = FCache[cLayer][:A]
    end

    padS = paddingSize(cLayer, Ai)

    if length(dAo) == 0
        if all(
            i -> (i.backCount == cLayer.nextLayers[1].backCount),
            cLayer.nextLayers,
        )
            dAo = []
            for nextLayer in cLayer.nextLayers
                try
                    dAo .+= getLayerSlice(cLayer, nextLayer, BCache)
                catch e
                    dAo = getLayerSlice(cLayer, nextLayer, BCache) #need to initialize dA
                end #try/catch
            end #for
        else
            return Dict(:dA => Array{Any,1}(undef,0))
        end #if all(i->(i.backCount==cLayer.nextLayers[1].backCount), cLayer.nextLayers)
    end #if dA==nothing

    dAi = zeros(promote_type(eltype(Ai), eltype(dAo)), size(Ai))

    if NNlib
        pooldims = PoolDims(Ai, cLayer.f, stride = cLayer.s, padding = padS)
        if cLayer isa MaxPoolLayer
            ∇maxpool!(dAi, dAo, Ao, Ai, pooldims)
        elseif cLayer isa AveragePoolLayer
            ∇meanpool!(dAi, dAo, Ao, Ai, pooldims)
        end #if cLayer isa MaxPoolLayer

    elseif cLayer.s == cLayer.f && fastPool
        dfastPooling!(cLayer, Ai, dAi, Ao, dAo)
    else
        dpooling!(cLayer, Ai, dAi, Ao, dAo)

    end #if NNlib

    cLayer.backCount += 1
    return Dict(:dA => dAi)

end #unction layerBackProp(cLayer::PL,


text:
# uses the A2T style network to create a stochastic policy
struct ISPolicy <: Policy
    network
    mdp
    action_probability::Function
    rng
end

# Get the value of being in state s
function POMDPs.value(p::ISPolicy, s)
    v = p.network(convert_s(Array{Float32,1}, s, p.mdp))
    @assert length(v) == 1
    v[1]
end

# Get the value of being in state s and taking action a
function POMDPs.value(p::ISPolicy, s, a)
    mdp = p.mdp
    sp, r = gen(mdp, s, a, p.rng)
    r + discount(mdp)*(!isterminal(mdp, sp))*value(p, sp)
end

function Distributions.logpdf(policy::ISPolicy, s, a)
    mdp = policy.mdp
    us = [value(policy, s, a)*policy.action_probability(mdp, s, a) for a in actions(policy.mdp, s)]
    if sum(us) == 0
        us = [policy.action_probability(mdp, s, a) for a in actions(policy.mdp, s)]
    end
    p = value(policy, s, a)*policy.action_probability(mdp, s, a) / sum(us)
    return (p == 0) ? log(policy.action_probability(mdp, s, a)) : log(p)
end

Distributions.logpdf(policy::ISPolicy, h::SimHistory) = sum([logpdf(policy, s, a) for (s,a) in eachstep(h, (:s, :a))])

# Choose an action based on the probability of failure. Return action and prob
function action_and_probability(p::ISPolicy, s)
    mdp = p.mdp
    vs = [p.action_probability(mdp, s, a)*value(p, s, a) for a in actions(mdp, s)]
    @assert all(vs .>= 0)
    all(vs .== 0) && (vs = [p.action_probability(mdp, s, a) for a in actions(mdp, s)])
    vs ./= sum(vs)
    ai = rand(p.rng, Categorical(vs))
    actions(mdp)[ai], vs[ai]
end

# Choose an action based on the probability of failure.
POMDPs.action(p, s) = action_and_probability(p, s)[1]


text:
#Tree and List Widget Overview — Overview of GtkTreeModel, GtkTreeView, and friends
#GtkTreeModel — The tree interface used by GtkTreeView
#GtkTreeSelection — The selection object for GtkTreeView
#GtkTreeViewColumn — A visible column in a GtkTreeView widget
#GtkTreeView — A widget for displaying both trees and lists
#GtkTreeView drag-and-drop — Interfaces for drag-and-drop support in GtkTreeView
#GtkCellView — A widget displaying a single row of a GtkTreeModel
#GtkIconView — A widget which displays a list of icons in a grid
#GtkTreeSortable — The interface for sortable models used by GtkTreeView
#GtkTreeModelSort — A GtkTreeModel which makes an underlying tree model sortable
#GtkTreeModelFilter — A GtkTreeModel which hides parts of an underlying tree model
#GtkCellLayout — An interface for packing cells
#GtkCellRenderer — An object for rendering a single cell on a GdkDrawable
#GtkCellEditable — Interface for widgets which can are used for editing cells
#GtkCellRendererAccel — Renders a keyboard accelerator in a cell
#GtkCellRendererCombo — Renders a combobox in a cell
#GtkCellRendererPixbuf — Renders a pixbuf in a cell
#GtkCellRendererProgress — Renders numbers as progress bars
#GtkCellRendererSpin — Renders a spin button in a cell
#GtkCellRendererText — Renders text in a cell
#GtkCellRendererToggle — Renders a toggle button in a cell
#GtkCellRendererSpinner — Renders a spinning animation in a cell
#GtkListStore — A list-like data structure that can be used with the GtkTreeView
#GtkTreeStore — A tree-like data structure that can be used with the GtkTreeView

#GtkComboBox — A widget used to choose from a list of items
#GtkComboBoxText — A simple, text-only combo box
#needs GObject #not defined #requires BinaryBuilder  ,
#= 1.Mutable  2. GtkComboBoxText 3. GtkListStore  4. GtkTreeStore 5. GtkTreeModel 6.  treeStore 7. GtkTreeStore 8. GtkTreeModelSort
9.GtkTreeModelFilterLeaf 10.GtkListStore 11. GtkTreeModelFilter 12. GtkCellRenderer 13.GtkTreeView  14.GtkCellLayout  15. GtkCellLayout=#
GtkListStore
import Base: pushfirst!
import Mutable
import Gtk #requires precompile()

GtkComboBoxTextLeaf(with_entry::Bool = false) = GtkComboBoxTextLeaf(
    if with_entry
        ccall((:gtk_combo_box_text_new_with_entry, libgtk), Ptr{GObject}, ())
    else
        ccall((:gtk_combo_box_text_new, libgtk), Ptr{GObject}, ())
    end)
push!(cb::GtkComboBoxText, text::AbstractString) =
    (ccall((:gtk_combo_box_text_append_text, libgtk), Nothing, (Ptr{GObject}, Ptr{UInt8}), cb, bytestring(text)); cb)
pushfirst!(cb::GtkComboBoxText, text::AbstractString) =
    (ccall((:gtk_combo_box_text_prepend_text, libgtk), Nothing, (Ptr{GObject}, Ptr{UInt8}), cb, bytestring(text)); cb)
insert!(cb::GtkComboBoxText, i::Integer, text::AbstractString) =
    (ccall((:gtk_combo_box_text_insert_text, libgtk), Nothing, (Ptr{GObject}, Cint, Ptr{UInt8}), cb, i - 1, bytestring(text)); cb)

push!(cb::GtkComboBoxText, id::Union{AbstractString,Symbol}, text::AbstractString) =
    (ccall((:gtk_combo_box_text_append, libgtk), Nothing, (Ptr{GObject}, Ptr{UInt8}, Ptr{UInt8}), cb, id, bytestring(text)); cb)
pushfirst!(cb::GtkComboBoxText, id::Union{AbstractString,Symbol}, text::AbstractString) =
    (ccall((:gtk_combo_box_text_prepend, libgtk), Nothing, (Ptr{GObject}, Ptr{UInt8}, Ptr{UInt8}), cb, id, bytestring(text)); cb)
insert!(cb::GtkComboBoxText, i::Integer, id::Union{AbstractString,Symbol}, text::AbstractString) =
    (ccall((:gtk_combo_box_text_insert, libgtk), Nothing, (Ptr{GObject}, Cint, Ptr{UInt8}, Ptr{UInt8}), cb, i - 1, id, bytestring(text)); cb)

empty!(cb::GtkComboBoxText) =
    (ccall((:gtk_combo_box_text_remove_all, libgtk), Nothing, (Ptr{GObject},), cb); cb)

delete!(cb::GtkComboBoxText, i::Integer) =
    (ccall((:gtk_combo_box_text_remove, libgtk), Nothing, (Ptr{GObject}, Cint), cb, i - 1); cb)

struct GtkTreeIter
    stamp::Cint
    user_data::Ptr{Nothing}
    user_data2::Ptr{Nothing}
    user_data3::Ptr{Nothing}
    GtkTreeIter() = new(0, C_NULL, C_NULL, C_NULL)
end
#TODO: Mutable
const TRI = Union{Mutable{GtkTreeIter},GtkTreeIter} #Struct{GtkTreeIter} #TODO:Mutable
zero(::Type{GtkTreeIter}) = GtkTreeIter()
copy(ti::GtkTreeIter) = ti
copy(ti::Mutable{GtkTreeIter}) = mutable(ti[])
show(io::IO, iter::GtkTreeIter) = print("GtkTreeIter(...)")

Base.cconvert(::Type{Ref{GtkTreeIter}}, x::GtkTreeIter) = Ref(x)
Base.cconvert(::Type{Ref{GtkTreeIter}}, x::Gtk.Mutable{GtkTreeIter}) = Ref(x[]) #TODO:Gtk

### GtkTreePath

# for debugging purpose
# immutable _GtkTreePath
#    depth::Cint
#    alloc::Cint
#    indices::Ptr{Cint}
# end

mutable struct GtkTreePath <: GBoxed #TODO:GBoxed
    handle::Ptr{GtkTreePath}
    function GtkTreePath(pathIn::Ptr{GtkTreePath}, own::Bool = false)
        x = new(own ? pathIn :
                ccall((:gtk_tree_path_copy, Gtk.libgtk), Ptr{GtkTreePath}, (Ptr{GtkTreePath},), pathIn)
        )
        f = x::GtkTreePath -> ccall((:gtk_tree_path_free, libgtk), Nothing, (Ptr{GtkTreePath},), x.handle)
        finalizer(f, x)
        x
    end
end
GtkTreePath() = GtkTreePath(ccall((:gtk_tree_path_new, libgtk), Ptr{GtkTreePath}, ()), true)
copy(path::GtkTreePath) = GtkTreePath(path.handle)

next(path::GtkTreePath) = ccall((:gtk_tree_path_next, libgtk), Nothing, (Ptr{GtkTreePath},), path)
prev(path::GtkTreePath) = ccall((:gtk_tree_path_prev, libgtk), Cint, (Ptr{GtkTreePath},), path) != 0
up(path::GtkTreePath) = ccall((:gtk_tree_path_up, libgtk), Cint, (Ptr{GtkTreePath},), path) != 0
down(path::GtkTreePath) = ccall((:gtk_tree_path_down, libgtk), Nothing, (Ptr{GtkTreePath},), path)
string(path::GtkTreePath) = bytestring(ccall((:gtk_tree_path_to_string, libgtk), Ptr{UInt8},
    (Ptr{GtkTreePath},), path))

### add indices for a store 1-based

## Get an iter corresponding to an index specified as a string
function iter_from_string_index(store, index::AbstractString)
    iter = Gtk.mutable(GtkTreeIter)
    Gtk.G_.iter_from_string(GtkTreeModel(store), iter, index)
    if !isvalid(store, iter)
        error("invalid index: $index")
    end
    iter[]
end

#---GtkListStore
### GtkListStore definition  #ERROR: GObject not defined (Requires binary builder )
#5. Leafs
function GtkListStoreLeaf(types::Type...)
    gtypes = GLib.gtypes(types...)
    handle = ccall((:gtk_list_store_newv, libgtk), Ptr{GObject}, (Cint, Ptr{GLib.GType}), length(types), gtypes)
    GtkListStoreLeaf(handle)
end

GtkListStoreLeaf(combo::GtkComboBoxText) = GtkListStoreLeaf(ccall((:gtk_combo_box_get_model, libgtk), Ptr{GObject}, (Ptr{GObject},), combo))

typeof(GtkListStoreLeaf)
## insert before
function insert!(listStore::GtkListStoreLeaf, iter::TRI, values)
    newiter = Gtk.mutable(GtkTreeIter)
    ccall((:gtk_list_store_insert_before, Gtk.libgtk), Nothing, (Ptr{GObject}, Ptr{GtkTreeIter}, Ref{GtkTreeIter}), listStore, newiter, iter)
    list_store_set_values(listStore, newiter, values)
    newiter[]
end

## insert into a list store after index
function insert!(listStore::GtkListStoreLeaf, index::Int, values)
    index > length(listStore) && return (push!(listStore, values))

    iter = iter_from_index(listStore, index)
    insert!(listStore, iter, values)
end

deleteat!(listStore::GtkListStoreLeaf, index::Int) = delete!(listStore, iter_from_index(listStore, index))
pop!(listStore::GtkListStoreLeaf) = deleteat!(listStore, length(listStore))
popfirst!(listStore::GtkListStoreLeaf) = deleteat!(listStore, 1)

## index is integer for a liststore, vector of ints for tree
iter_from_index(store::GtkListStore, index::Int) = iter_from_string_index(store, string(index - 1))
index_from_iter(store::GtkListStore, iter::TRI) = parse(Int, get_string_from_iter(GtkTreeModel(store), iter)) + 1

function list_store_set_values(store::GtkListStore, iter, values)
    for (i, value) in enumerate(values)
        ccall((:gtk_list_store_set_value, Gtk.libgtk), Nothing, (Ptr{GObject}, Ptr{GtkTreeIter}, Cint, Ptr{Gtk.GValue}),
            store, iter, i - 1, Gtk.gvalue(value))
    end
end #TODO:GtkListStore not defined

function push!(listStore::GtkListStore, values::Tuple)
    iter = mutable(GtkTreeIter)
    ccall((:gtk_list_store_append, libgtk), Nothing, (Ptr{GObject}, Ptr{GtkTreeIter}), listStore, iter)

    list_store_set_values(listStore, iter, values)
    iter[]
end

function pushfirst!(listStore::GtkListStore, values::Tuple)
    iter = mutable(GtkTreeIter)
    ccall((:gtk_list_store_prepend, libgtk), Nothing, (Ptr{GObject}, Ptr{GtkTreeIter}), listStore, iter)
    list_store_set_values(listStore, iter, values)
    iter[]
end

function delete!(listStore::GtkListStore, iter::TRI)
    # not sure what to do with the return value here
    deleted = ccall((:gtk_list_store_remove, libgtk), Cint, (Ptr{GObject}, Ref{GtkTreeIter}), listStore, iter)
    listStore
end

deleteat!(listStore::GtkListStore, iter::TRI) = delete!(listStore, iter)

empty!(listStore::GtkListStore) =
    ccall((:gtk_list_store_clear, libgtk), Nothing, (Ptr{GObject},), listStore)

## by index

isvalid(listStore::GtkListStore, iter::TRI) =
    ccall((:gtk_list_store_iter_is_valid, libgtk), Cint,
        (Ptr{GObject}, Ref{GtkTreeIter}), listStore, iter) != 0

function length(listStore::GtkListStore)
    _len = ccall((:gtk_tree_model_iter_n_children, libgtk), Cint, (Ptr{GObject}, Ptr{GtkTreeIter}), listStore, C_NULL)
    return convert(Int, _len)
end

size(listStore::GtkListStore) = (length(listStore), ncolumns(GtkTreeModel(listStore)))

getindex(store::GtkListStore, row::Int, column) = getindex(store, iter_from_index(store, row), column)
getindex(store::GtkListStore, row::Int) = getindex(store, iter_from_index(store, row))

function setindex!(store::GtkListStore, value, index::Int, column::Integer)
    setindex!(store, value, Gtk.iter_from_index(store, index), column)
end

### GtkTreeStore
# 6 Leafs
function GtkTreeStoreLeaf(types::Type...)
    gtypes = GLib.gtypes(types...)
    handle = ccall((:gtk_tree_store_newv, libgtk), Ptr{GObject}, (Cint, Ptr{GLib.GType}), length(types), gtypes)
    GtkTreeStoreLeaf(handle)
end

iter_from_index(store::GtkTreeStoreLeaf, index::Vector{Int}) = iter_from_string_index(store, join(index .- 1, ":"))

function tree_store_set_values(treeStore::GtkTreeStoreLeaf, iter, values)
    for (i, value) in enumerate(values)
        ccall((:gtk_tree_store_set_value, Gtk.libgtk), Nothing, (Ptr{GObject}, Ref{GtkTreeIter}, Cint, Ptr{Gtk.GValue}),
            treeStore, iter, i - 1, gvalue(value))
    end
    iter[]
end

#TODO: treeStore GtkTreeStore
## index can be :parent or :sibling
## insertion can be :after or :before
function insert!(treeStore::GtkTreeStoreLeaf, piter::TRI, values; how::Symbol = :parent, where::Symbol = :after)

    ## insert by index
    function insert!(treeStore::GtkTreeStoreLeaf, index::Vector{Int}, values; how::Symbol = :parent, where::Symbol = :after)
        iter = iter_from_index(treeStore, index)
        insert!(treeStore, iter, values; how = how, where = where)
    end

    function splice!(treeStore::GtkTreeStoreLeaf, index::Vector{Int})
        iter = iter_from_index(treeStore, index)
        delete!(treeStore, iter)
    end

    function push!(treeStore::GtkTreeStore, values::Tuple, parent = nothing)
        iter = mutable(GtkTreeIter)
        if parent === nothing #compare against nothing with ===
            ccall((:gtk_tree_store_append, libgtk), Nothing, (Ptr{GObject}, Ptr{GtkTreeIter}, Ptr{Nothing}), treeStore, iter, C_NULL)
        else
            ccall((:gtk_tree_store_append, libgtk), Nothing, (Ptr{GObject}, Ptr{GtkTreeIter}, Ref{GtkTreeIter}), treeStore, iter, parent)
        end

        tree_store_set_values(treeStore, iter, values)
        iter[]
    end

    function pushfirst!(treeStore::GtkTreeStore, values::Tuple, parent = nothing)
        iter = mutable(GtkTreeIter)
        if parent === nothing #compare against nothing with ===
            ccall((:gtk_tree_store_prepend, libgtk), Nothing, (Ptr{GObject}, Ptr{GtkTreeIter}, Ptr{Nothing}), treeStore, iter, C_NULL)
        else
            ccall((:gtk_tree_store_prepend, libgtk), Nothing, (Ptr{GObject}, Ptr{GtkTreeIter}, Ref{GtkTreeIter}), treeStore, iter, parent)
        end

        tree_store_set_values(treeStore, iter, values)
        iter[]
    end

    iter = Gtk.mutable(GtkTreeIter)
    if how == :parent
        if where == :after
            ccall((:gtk_tree_store_insert_after, Gtk.libgtk), Nothing, (Ptr{GObject}, Ptr{GtkTreeIter}, Ref{GtkTreeIter}, Ptr{Nothing}), treeStore, iter, piter, C_NULL)
        else
            ccall((:gtk_tree_store_insert_before, Gtk.libgtk), Nothing, (Ptr{GObject}, Ptr{GtkTreeIter}, Ref{GtkTreeIter}, Ptr{Nothing}), treeStore, iter, piter, C_NULL)
        end
    else
        if where == :after
            ccall((:gtk_tree_store_insert_after, Gtk.libgtk), Nothing, (Ptr{GObject}, Ptr{GtkTreeIter}, Ref{Nothing}, Ref{GtkTreeIter}), treeStore, iter, C_NULL, piter)
        else
            ccall((:gtk_tree_store_insert_before, Gtk.libgtk), Nothing, (Ptr{GObject}, Ptr{GtkTreeIter}, Ref{Nothing}, Ref{GtkTreeIter}), treeStore, iter, C_NULL, piter)
        end
    end

    tree_store_set_values(treeStore, iter, values)
end

#TODO: GtkTreeStore
function delete!(treeStore::GtkTreeStore, iter::TRI)
    # not sure what to do with the return value here
    deleted = ccall((:gtk_tree_store_remove, libgtk), Cint, (Ptr{GObject}, Ref{GtkTreeIter}), treeStore, iter)
    treeStore
end

deleteat!(treeStore::GtkTreeStore, iter::TRI) = delete!(treeStore, iter)

empty!(treeStore::GtkTreeStore) =
    ccall((:gtk_tree_store_clear, libgtk), Nothing, (Ptr{GObject},), treeStore)

isvalid(treeStore::GtkTreeStore, iter::TRI) =
    ccall((:gtk_tree_store_iter_is_valid, libgtk), Cint,
        (Ptr{GObject}, Ref{GtkTreeIter}), treeStore, iter) != 0

isancestor(treeStore::GtkTreeStore, iter::TRI, descendant::TRI) =
    ccall((:gtk_tree_store_is_ancestor, libgtk), Cint,
        (Ptr{GObject}, Ref{GtkTreeIter}, Ref{GtkTreeIter}),
        treeStore, iter, descendant) != 0

depth(treeStore::GtkTreeStore, iter::TRI) =
    ccall((:gtk_tree_store_iter_depth, libgtk), Cint, (Ptr{GObject}, Ref{GtkTreeIter}), treeStore, iter)

## get index store[iter], store[iter, column], store[index], store[index, column]
getindex(store::Union{GtkTreeStore,GtkListStore}, iter::TRI, column::Integer) = getindex(GtkTreeModel(store), iter, column)
getindex(store::Union{GtkTreeStore,GtkListStore}, iter::TRI) = getindex(GtkTreeModel(store), iter)

getindex(store::GtkTreeStore, row::Vector{Int}, column) = getindex(store, iter_from_index(store, row), column)
getindex(store::GtkTreeStore, row::Vector{Int}) = getindex(store, iter_from_index(store, row))

function setindex!(store::GtkTreeStore, value, index::Vector{Int}, column::Integer)
    setindex!(store, value, Gtk.iter_from_index(store, index), column)
end
#-- GtkListStore
function setindex!(store::Union{GtkListStore,GtkTreeStore}, value, iter::TRI, column::Integer)
    Gtk.G_.value(store, Gtk.mutable(iter), column - 1, gvalue(value))
end
-
#---end of GtkListStore

### #TODO:GtkTreeModelFilter
#1 Leaf
#TODO: GObject
GtkTreeModelFilterLeaf(child_model::GObject) = GtkTreeModelFilterLeaf(
    ccall((:gtk_tree_model_filter_new, libgtk), Ptr{GObject}, (Ptr{GObject}, Ptr{Nothing}), child_model, C_NULL))
#---GtkTreeModelFilter
function convert_iter_to_child_iter(model::GtkTreeModelFilter, filter_iter::TRI)
    child_iter = mutable(GtkTreeIter)
    ccall((:gtk_tree_model_filter_convert_iter_to_child_iter, libgtk), Nothing,
        (Ptr{GObject}, Ptr{GtkTreeIter}, Ptr{GtkTreeIter}),
        model, child_iter, mutable(filter_iter))
    child_iter[]
end

function convert_child_iter_to_iter(model::GtkTreeModelFilter, child_iter::TRI)
    filter_iter = mutable(GtkTreeIter)
    ccall((:gtk_tree_model_filter_convert_child_iter_to_iter, libgtk), Nothing,
        (Ptr{GObject}, Ptr{GtkTreeIter}, Ref{GtkTreeIter}),
        model, filter_iter, child_iter)
    filter_iter[]
end
#--end of GtkTreeModelFilter

#--GObject
GtkTreeModelSortLeaf(child_model::GObject) = GtkTreeModelSortLeaf(
    ccall((:gtk_tree_model_sort_new_with_model, libgtk), Ptr{GObject}, (Ptr{GObject},), child_model))
#--- GtkTreeModelSort
function convert_iter_to_child_iter(model::GtkTreeModelSort, sort_iter::TRI)
    child_iter = mutable(GtkTreeIter)
    ccall((:gtk_tree_model_sort_convert_iter_to_child_iter, libgtk), Nothing,
        (Ptr{GObject}, Ptr{GtkTreeIter}, Ref{GtkTreeIter}),
        model, child_iter, sort_iter)
    child_iter[]
end

function convert_child_iter_to_iter(model::GtkTreeModelSort, child_iter::TRI)
    sort_iter = mutable(GtkTreeIter)
    ccall((:gtk_tree_model_sort_convert_child_iter_to_iter, libgtk), Nothing,
        (Ptr{GObject}, Ptr{GtkTreeIter}, Ref{GtkTreeIter}),
        model, sort_iter, child_iter)
    sort_iter[]
end
#--- end of GtkTreeModelSort

### #TODO: GtkTreeModel

function getindex(treeModel::GtkTreeModel, iter::TRI, column::Integer)
    val = mutable(GValue())
    ccall((:gtk_tree_model_get_value, libgtk), Nothing, (Ptr{GObject}, Ref{GtkTreeIter}, Cint, Ptr{GValue}),
        treeModel, iter, column - 1, val)
    val[Any]
end

function getindex(treeModel::GtkTreeModel, iter::TRI)
    ntuple(i -> treeModel[iter, i], ncolumns(treeModel))
end

function setindex!(treeModel::GtkTreeModel, value, iter::TRI, column::Integer)
    G_.value(treeModel, mutable(iter), column - 1, gvalue(value))
end

function setindex!(treeModel::GtkTreeModel, values, iter::TRI)
    for (i, v) in enumerate(values)
        G_.value(treeModel, mutable(iter), i - 1, gvalue(v))
    end
end

ncolumns(treeModel::GtkTreeModel) =
    ccall((:gtk_tree_model_get_n_columns, libgtk), Cint, (Ptr{GObject},), treeModel)

## add in gtk_tree_model iter functions to traverse tree

## Most gtk function pass in a Mutable Iter and return a bool
## Update iter to point to first iterm
function get_iter_first(treeModel::GtkTreeModel, iter = Mutable{GtkTreeIter})
    ret = ccall((:gtk_tree_model_get_iter_first, libgtk), Cint,
        (Ptr{GObject}, Ptr{GtkTreeIter}),
        treeModel, iter)
    ret != 0
end

#TODO: Mutable
## return (Bool, iter)
function get_iter_next(treeModel::GtkTreeModel, iter::Mutable{GtkTreeIter})
    ret = ccall((:gtk_tree_model_iter_next, libgtk), Cint,
        (Ptr{GObject}, Ptr{GtkTreeIter}),
        treeModel, iter)
    ret != 0
end

## update iter to point to previous.
## return Bool
function get_iter_previous(treeModel::GtkTreeModel, iter::Mutable{GtkTreeIter})
    ret = ccall((:gtk_tree_model_iter_previous, libgtk), Cint,
        (Ptr{GObject}, Ptr{GtkTreeIter}),
        treeModel, iter)
    ret != 0
end

## update iter to point to first child of parent iter
## return Bool
function iter_children(treeModel::GtkTreeModel, iter::Mutable{GtkTreeIter}, piter::TRI)
    ret = ccall((:gtk_tree_model_iter_children, libgtk), Cint,
        (Ptr{GObject}, Ptr{GtkTreeIter}, Ptr{GtkTreeIter}),
        treeModel, iter, mutable(piter))
    ret != 0
end

## return boolean, checks if there is a child
function iter_has_child(treeModel::GtkTreeModel, iter::TRI)
    ret = ccall((:gtk_tree_model_iter_has_child, libgtk), Cint,
        (Ptr{GObject}, Ref{GtkTreeIter}),
        treeModel, iter)
    ret != 0
end

## return number of children for iter
function iter_n_children(treeModel::GtkTreeModel, iter::TRI)
    ret = ccall((:gtk_tree_model_iter_n_children, libgtk), Cint,
        (Ptr{GObject}, Ref{GtkTreeIter}),
        treeModel, iter)
    ret
end

#--- Mutable
## update iter pointing to nth child n in 1:nchildren)
## As a special case, if parent is NULL, then the n-th root node is set
## return boolean
function iter_nth_child(treeModel::GtkTreeModel, iter::Mutable{GtkTreeIter}, parent_iter::Union{TRI,Nothing}, n::Int)
    parent_iter = isnothing(parent_iter) ? C_NULL : mutable(parent_iter)
    ret = ccall((:gtk_tree_model_iter_nth_child, libgtk), Cint,
        (Ptr{GObject}, Ptr{GtkTreeIter}, Ptr{GtkTreeIter}, Cint),
        treeModel, iter, parent_iter, n - 1) # 0-based
    ret != 0
end

## return Bool
function iter_parent(treeModel::GtkTreeModel, iter::Mutable{GtkTreeIter}, citer::TRI)
    ret = ccall((:gtk_tree_model_iter_parent, libgtk), Cint,
        (Ptr{GObject}, Ptr{GtkTreeIter}, Ref{GtkTreeIter}),
        treeModel, iter, citer)
    ret != 0
end

## these mutate iter to point to new object.
next(treeModel::GtkTreeModel, iter::Mutable{GtkTreeIter}) = get_iter_next(treeModel, iter)
prev(treeModel::GtkTreeModel, iter::Mutable{GtkTreeIter}) = get_iter_previous(treeModel, iter)
up(treeModel::GtkTreeModel, iter::Mutable{GtkTreeIter}) = iter_parent(treeModel, iter, copy(iter))
down(treeModel::GtkTreeModel, iter::Mutable{GtkTreeIter}) = iter_children(treeModel, iter, copy(iter))
#---end of Mutable
length(treeModel::GtkTreeModel, iter::TRI) = iter_n_children(treeModel, iter)
string(treeModel::GtkTreeModel, iter::TRI) = get_string_from_iter(treeModel, iter)

## index is Int[] 1-based
#--- GtkTreeModel
#--- treeModel
index_from_iter(treeModel::GtkTreeModel, iter::TRI) = map(int, split(get_string_from_iter(treeModel, iter), ":")) + 1

## string is of type "0:1:0" (0-based)
function get_string_from_iter(treeModel::GtkTreeModel, iter::TRI)
    val = ccall((:gtk_tree_model_get_string_from_iter, libgtk), Ptr{UInt8},
        (Ptr{GObject}, Ref{GtkTreeIter}),
        treeModel, iter)
    val = bytestring(val)
end
#----end GtkTreeModel
#TODO:GtkTreeStore
## An iterator to walk a tree, e.g.,
## for iter in Gtk.TreeIterator(store) ## or Gtk.TreeIterator(store, piter)
##   println(store[iter, 1])
## end
#--- TreeIterator
mutable struct TreeIterator
    store::GtkTreeStore
    model::GtkTreeModel
    iter::Union{Nothing,TRI}
end
TreeIterator(store::GtkTreeStore, iter = nothing) = TreeIterator(store, GtkTreeModel(store), iter)
Base.IteratorSize(::TreeIterator) = Base.SizeUnknown()

## iterator interface for depth first search
function start_(x::TreeIterator)
    isa(x.iter, Nothing) ? nothing : mutable(copy(x.iter))
end

function done_(x::TreeIterator, state)

    iter = mutable(GtkTreeIter)

    isa(state, Nothing) && return (!Gtk.get_iter_first(x.model, iter))   # special case root

    state = copy(state)

    ## we are not done if:
    iter_has_child(x.model, state) && return (false) # state has child
    next(x.model, copy(state)) && return (false) # state has sibling

    # or a valid ancestor of piter has a sibling
    up(x.model, state) || return (true)

    while isa(x.iter, Nothing) || isancestor(x.store, x.iter, state)
        next(x.model, copy(state)) && return (false) # has a sibling
        up(x.model, state) || return (true)
    end
    return (true)
end

function next_(x::TreeIterator, state)
    iter = mutable(GtkTreeIter)

    if isa(state, Nothing)      # special case root
        Gtk.get_iter_first(x.model, iter)
        return (iter, iter)
    end

    state = copy(state)

    if iter_has_child(x.model, state)
        down(x.model, state)
        return (state, state)
    end

    cstate = copy(state)
    next(x.model, cstate) && return (cstate, cstate)

    up(x.model, state)

    while isa(x.iter, Nothing) || isancestor(x.store, x.iter, state)
        cstate = copy(state)
        next(x.model, cstate) && return (cstate, cstate) # return the sibling of state
        up(x.model, state)
    end
    error("next not found")
end

iterate(x::TreeIterator, state = start_(x)) = done_(x, state) ? nothing : next_(x, state)

#TODO: Replace by accessor
function iter(treeModel::GtkTreeModel, path::GtkTreePath)
    it = mutable(GtkTreeIter)
    ret = ccall((:gtk_tree_model_get_iter, libgtk), Cint, (Ptr{GObject}, Ptr{GtkTreeIter}, Ptr{GtkTreePath}),
        treeModel, it, path) != 0
    ret, it[]
end

#TODO: Replace by accessor (accessor is wrong)
function path(treeModel::GtkTreeModel, iter::TRI)
    GtkTreePath(ccall((:gtk_tree_model_get_path, libgtk), Ptr{GtkTreePath},
        (Ptr{GObject}, Ref{GtkTreeIter}),
        treeModel, iter))
end
#---end of treeModel
depth(path::GtkTreePath) = ccall((:gtk_tree_path_get_depth, libgtk), Cint,
    (Ptr{GtkTreePath},), path)
#ERROR- invalid type #forReview
#---Leafs

### GtkTreeSortable

### -----#TODO:GtkCellRenderer
### GtkCellRenderer #Uncommentme
#= #TODO fix problems #add corresponding files (?)
GtkCellRendererAccelLeaf() = GtkCellRendererAccelLeaf(
    ccall((:gtk_cell_renderer_accel_new, libgtk), Ptr{GObject}, ()))

GtkCellRendererComboLeaf() = GtkCellRendererComboLeaf(
    ccall((:gtk_cell_renderer_combo_new, libgtk), Ptr{GObject}, ()))

GtkCellRendererPixbufLeaf() = GtkCellRendererPixbufLeaf(
    ccall((:gtk_cell_renderer_pixbuf_new, libgtk), Ptr{GObject}, ()))

GtkCellRendererProgressLeaf() = GtkCellRendererProgressLeaf(
    ccall((:gtk_cell_renderer_progress_new, libgtk), Ptr{GObject}, ()))

GtkCellRendererSpinLeaf() = GtkCellRendererSpinLeaf(
    ccall((:gtk_cell_renderer_spin_new, libgtk), Ptr{GObject}, ()))

GtkCellRendererTextLeaf() = GtkCellRendererTextLeaf(
    ccall((:gtk_cell_renderer_text_new, libgtk), Ptr{GObject}, ()))

GtkCellRendererToggleLeaf() = GtkCellRendererToggleLeaf(
    ccall((:gtk_cell_renderer_toggle_new, libgtk), Ptr{GObject}, ()))

GtkCellRendererSpinnerLeaf() = GtkCellRendererSpinnerLeaf(
    ccall((:gtk_cell_renderer_spinner_new, libgtk), Ptr{GObject}, ()))
    =#

# 2 Leafs
GtkTreeViewColumnLeaf() = GtkTreeViewColumnLeaf(ccall((:gtk_tree_view_column_new, libgtk), Ptr{GObject}, ()))#possible method call error #TODO: #Error in: GtkTreeViewColumnLeaf, ccall,gtk_tree_view_column_new,libgtk,GObject ?
function GtkTreeViewColumnLeaf(renderer::GtkCellRenderer, mapping)
    treeColumn = GtkTreeViewColumnLeaf()
    pushfirst!(treeColumn, renderer)
    for (k, v) in mapping
        add_attribute(treeColumn, renderer, string(k), v)
    end
    treeColumn
end #TODO: GtkCellRenderer

function GtkTreeViewColumnLeaf(title::AbstractString, renderer::GtkCellRenderer, mapping)
    set_gtk_property!(GtkTreeViewColumnLeaf(renderer, mapping), :title, title)
end

### GtkTreeView #TODO: GtkTreeModel
#1 Leaf

GtkTreeViewLeaf() = GtkTreeViewLeaf(ccall((:gtk_tree_view_new, libgtk), Ptr{GObject}, ()))
GtkTreeViewLeaf(treeStore::GtkTreeModel) = GtkTreeViewLeaf(
    ccall((:gtk_tree_view_new_with_model, libgtk), Ptr{GObject}, (Ptr{GObject},), treeStore))

#GtkTreeViewColumn #TODO: GtkTreeViewColumn, Base.pushfirst!
empty!(treeColumn::GtkTreeViewColumn) =
    ccall((:gtk_tree_view_column_clear, libgtk), Nothing, (Ptr{GObject},), treeColumn)

function pushfirst!(treeColumn::GtkTreeViewColumn, renderer::GtkCellRenderer, expand::Bool = false)
    ccall((:gtk_tree_view_column_pack_start, libgtk), Nothing,
        (Ptr{GObject}, Ptr{GObject}, Cint), treeColumn, renderer, expand)
    treeColumn
end

function push!(treeColumn::GtkTreeViewColumn, renderer::GtkCellRenderer, expand::Bool = false)
    ccall((:gtk_tree_view_column_pack_end, libgtk), Nothing,
        (Ptr{GObject}, Ptr{GObject}, Cint), treeColumn, renderer, expand)
    treeColumn
end

add_attribute(treeColumn::GtkTreeViewColumn, renderer::GtkCellRenderer,
    attribute::AbstractString, column::Integer) =
    ccall((:gtk_tree_view_column_add_attribute, libgtk), Nothing,
        (Ptr{GObject}, Ptr{GObject}, Ptr{UInt8}, Cint), treeColumn, renderer, bytestring(attribute), column)
#----end of GtkCellRendered
### GtkTreeSelection #TODO:
function selected(selection::GtkTreeSelection)
    hasselection(selection) || error("No selection for GtkTreeSelection")

    model = mutable(Ptr{GtkTreeModel})
    iter = mutable(GtkTreeIter)

    ret = ccall((:gtk_tree_selection_get_selected, libgtk), Cint,
        (Ptr{GObject}, Ptr{Ptr{GtkTreeModel}}, Ptr{GtkTreeIter}), selection, model, iter) != 0

    !ret && error("No selection of GtkTreeSelection")

    iter[]
end

function selected_rows(selection::GtkTreeSelection)
    hasselection(selection) || return GtkTreeIter[]

    model = Ref{Ptr{GtkTreeModel}}()

    paths = GLib.GList(ccall((:gtk_tree_selection_get_selected_rows, libgtk),
        Ptr{GLib._GList{Ptr{GtkTreePath}}},
        (Ptr{GObject}, Ptr{Ptr{GtkTreeModel}}),
        selection, model))

    iters = GtkTreeIter[]
    for path in paths
        it = Ref{GtkTreeIter}()
        ret = ccall((:gtk_tree_model_get_iter, libgtk), Cint, (Ptr{GObject}, Ptr{GtkTreeIter}, Ptr{GtkTreePath}),
            model[], it, path) != 0
        ret && push!(iters, it[])
    end

    iters
end

#--- TODO: GtkTreeSelection
length(selection::GtkTreeSelection) =
    ccall((:gtk_tree_selection_count_selected_rows, libgtk), Cint, (Ptr{GObject},), selection)

hasselection(selection::GtkTreeSelection) = length(selection) > 0

select!(selection::GtkTreeSelection, iter::TRI) =
    ccall((:gtk_tree_selection_select_iter, libgtk), Nothing,
        (Ptr{GObject}, Ref{GtkTreeIter}), selection, iter)

unselect!(selection::GtkTreeSelection, iter::TRI) =
    ccall((:gtk_tree_selection_unselect_iter, libgtk), Nothing,
        (Ptr{GObject}, Ref{GtkTreeIter}), selection, iter)

selectall!(selection::GtkTreeSelection) =
    ccall((:gtk_tree_selection_select_all, libgtk), Nothing, (Ptr{GObject},), selection)

unselectall!(selection::GtkTreeSelection) =
    ccall((:gtk_tree_selection_unselect_all, libgtk), Nothing, (Ptr{GObject},), selection)
#---end of  GtkTreeSelection
#-----GtkTreeViewColumn
function push!(treeView::GtkTreeView, treeColumns::GtkTreeViewColumn...)
    for col in treeColumns
        ccall((:gtk_tree_view_append_column, libgtk), Nothing, (Ptr{GObject}, Ptr{GObject}), treeView, col)
    end
    treeView
end
#--- GTKTreeView
function insert!(treeView::GtkTreeView, index::Integer, treeColumn::GtkTreeViewColumn)
    ccall((:gtk_tree_view_insert_column, libgtk), Nothing, (Ptr{GObject}, Ptr{GObject}, Cint), treeView, treeColumn, index - 1)
    treeView
end
#---end of GtkTreeViewColumn
#---GtkTreeView
function expand_to_path(tree_view::GtkTreeView, path::GtkTreePath)
    return ccall(
        (:gtk_tree_view_expand_to_path, libgtk), Cvoid,
        (Ptr{GObject}, Ptr{GtkTreePath}), tree_view, path
    )
end

function treepath(path::AbstractString) #compiles
    ptr = ccall(
        (:gtk_tree_path_new_from_string, libgtk), Ptr{GtkTreePath},
        (Ptr{UInt8},), bytestring(path)
    )
    return ptr == C_NULL ? GtkTreePath() : convert(GtkTreePath, ptr)
end

# There's a method wrapped in GAccessor but tries to convert to a GtkTreeModel, which
# is an interface in Gtk
function model(tree_view::GtkTreeView)
    return convert(GtkTreeStore, ccall(
        (:gtk_tree_view_get_model, Gtk.libgtk),
        Ptr{Gtk.GObject},
        (Ptr{Gtk.GObject},),
        tree_view)
    )
end

# TODO Use internal accessor with default values?
function path_at_pos(treeView::GtkTreeView, x::Integer, y::Integer)
    pathPtr = Ref{Ptr{GtkTreePath}}(0)

    ret = ccall((:gtk_tree_view_get_path_at_pos, libgtk), Cint,
        (Ptr{GObject}, Cint, Cint, Ref{Ptr{GtkTreePath}}, Ptr{Ptr{Nothing}}, Ptr{Cint}, Ptr{Cint}),
        treeView, x, y, pathPtr, C_NULL, C_NULL, C_NULL) != 0
    if ret
        path = GtkTreePath(pathPtr[], true)
    else
        path = GtkTreePath()
    end
    ret, path
end
#---end of GtkTreeView

###---- GtkCellLayout
function cells(cellLayout::GtkCellLayout)
    cells = Gtk.GLib.GList(ccall((:gtk_cell_layout_get_cells, Gtk.libgtk),
        Ptr{Gtk._GList{Gtk.GtkCellRenderer}}, (Ptr{GObject},), cellLayout))
    return cells
end

### To be done
#
#GtkCellArea
#GtkCellAreaBox
#GtkCellAreaContext
#GtkCellView
#GtkIconView

max_stars_repo_name: adamwillisMastery/MiniGtk

max_issues_repo_name: adamwillisMastery/MiniGtk

max_forks_repo_name: adamwillisMastery/MiniGtk


text:
alias(::SiteType"Boson") = SiteType"Qudit"()

"""
    space(::SiteType"Boson";
          dim = 2,
          conserve_qns = false,
          conserve_number = false,
          qnname_number = "Number")

Create the Hilbert space for a site of type "Boson".

Optionally specify the conserved symmetries and their quantum number labels.
"""
ITensors.space(st::SiteType"Boson"; kwargs...) = space(alias(st); kwargs...)

ITensors.val(vn::ValName, st::SiteType"Boson") = val(vn, alias(st))

ITensors.state(sn::StateName, st::SiteType"Boson", s::Index) = state(sn, alias(st), s)

ITensors.op(on::OpName, st::SiteType"Boson", s::Index) = op(on, alias(st), s)


text:
# extract_features.jl
# This script will take the extracted spectrograms and create a training set
# of data that can be used to train the random forest classifier.
# author: Timothy Evans
# date: 31/07/14

push!(LOAD_PATH, pwd())
importall dataprocessing, config
using Images, DataFrames, ProgressMeter

#load paths from config.jl
specpath,labelledpath,trainpath,modelpath = loadpaths()
p = Progress(length(readdir(labelledpath)),1) # initialise progress bar

println("Loading $(length(readdir(labelledpath))) images and extracting feature vectors ... ")

for spec in readdir(labelledpath)

  #load the images and construct the feature vector for this image pair.
  imgmask = Images.load(string(labelledpath,spec)); # labelled masks are png images to avoid loss
  img = Images.load(string(trainpath,spec[1:end-3],"jpg")); # the corresponding img will be jpg for space reasons
  recorderdata = readtable(string(modelpath,"recorderdata.csv"));
  if (colorspace(imgmask) == "BGRA")
#    print(spec)
    (pixels,freq,boxmu,boxvar,label) = imgfeature(img, imgmask,spec,recorderdata)
  else
    c = colorspace(img)
    # if this error is thrown consider adding elseif conditions for other
    # potential colorspaces
    error("Currently extract_features.jl only considers images with colorspace
    BRGA: received image of type $cs.")
  end

  #concatenate feature data together
  if isdefined(:featuredata)
    featuredata = vcat(featuredata,hcat(pixels,freq,boxmu,boxvar))
    labeldata = vcat(labeldata,label)
  else
    global featuredata = hcat(pixels,freq,boxmu,boxvar);
    global labeldata = label;
  end
  next!(p)
end

print("Subsampling data and writing to $(string(modelpath,datafile)) ... \n")

# subsample data as required
featuredata,labeldata = subsampledata(featuredata,labeldata,subsampleratio)
labeldata = convertclasses(labeldata) # make zeros and ones all zeros and twos into ones

#feature normalise the data
(X,mu,sigma) = featurenormalise(featuredata);

#write data to file and save mu and sigma for future use in prediction
writecsv(string(modelpath,datafile),hcat(X,labeldata))
writecsv(string(modelpath,"musigma.csv"),vcat(mu,sigma))

max_stars_repo_name: kokakodetect/kokako-detection

max_issues_repo_name: kokakodetect/kokako-detection

max_forks_repo_name: kokakodetect/kokako-detection


text:
module LiftProps

export fitliftslope,findclmax,findclmaxlinear,findclmin

"""
    findclmax(aoa,cl)
Determines clmax as greatest lift coefficient. Returns aoaclmax, clmax
"""
function findclmax(aoa,cl)
  indclmax = argmax(cl)
  clmax = cl[indclmax]
  aoaclmax = aoa[indclmax]
  return aoaclmax,clmax
end #findclmax

"""
    findclmax(aoa,cl,npnts::Integer)
Determines clmax as when all angles greater than the clmax angle for `npnts`
data points are less than clmax. Assumes points are ordered by angle of attack.
Returns aoaclmax, clmax
"""
function findclmax(aoa,cl,npnts::Integer)
  # default to basic method if conditions not satisfied
  aoaclmax,clmax = findclmax(aoa,cl)
  # start at zero
  idxzero = argmin(abs.(aoa))
  for i = idxzero:length(cl)-npnts
    # check if all points in range are less than current point
    if count(cl[(i+1):(i+npnts)] .> cl[i]) == 0
      clmax = cl[i]
      aoaclmax = aoa[i]
      break
    end
  end
  return aoaclmax,clmax
end #findclmax

"""
    findclmax(aoa,cl,range::AbstractFloat)
Determines clmax as when all angles greater than the clmax angles for `range`
radians are less than clmax. Assumes points are ordered by angle of attack.
Returns aoaclmax, clmax
"""
function findclmax(aoa,cl,range::AbstractFloat)
  # default to basic method if conditions not satisfied
  aoaclmax,clmax = findclmax(aoa,cl)
  # start at zero
  idxzero = argmin(abs.(aoa))
  for i = idxzero:length(cl)
    # find index of point approximately `range` greater
    idx = argmin(abs.(aoa[i].+range.-aoa))
    if idx == i
      break
    else
      # check if all points in range are less than current point
      if count(cl[(i+1):idx] .> cl[i]) == 0
        clmax = cl[i]
        aoaclmax = aoa[i]
        break
      end
    end
  end
  return aoaclmax,clmax
end #findclmax

"""
    findclmin(aoa,cl)
Determines clmin as smallest lift coefficient.  Returns aoaclmin, clmin
"""
function findclmin(aoa,cl)
  indclmin = argmin(cl)
  clmin = cl[indclmin]
  aoaclmin = aoa[indclmin]
  return aoaclmin,clmin
end #findclmax

"""
    findclmin(aoa,cl,npnts::Integer)
Determines clmin as when all angles less than the clmin angle for `npnts` data
points are greater than clmin. Assumes points are ordered by angle of attack.
Returns aoaclmin, clmin
"""
function findclmin(aoa,cl,npnts::Integer)
  # default to basic method if conditions not satisfied
  aoaclmin,clmin = findclmin(aoa,cl)
  # start at zero
  idxzero = argmin(abs.(aoa))
  for i = idxzero:-1:(npnts+1)
    # check if all points in range are less than current point
    if count(cl[(i-1):-1:(i-npnts)] .< cl[i]) == 0
      clmin = cl[i]
      aoaclmin = aoa[i]
      break
    end
  end
  return aoaclmin,clmin
end #findclmax

"""
    findclmin(aoa,cl,range::AbstractFloat)
Determines clmin as when all points less than the clmin angle for `range`
radians are greater than clmin. Returns aoaclmin, clmin
"""
function findclmin(aoa,cl,range::AbstractFloat)
  # default to basic method if conditions not satisfied
  aoaclmin,clmin = findclmin(aoa,cl)
  # start at zero
  idxzero = argmin(abs.(aoa))
  for i = idxzero:-1:1
    # find index of point approximately `range` less
    idx = argmin(abs.(aoa[i].-range.-aoa))
    if idx == i
      break
    else
      # check if all points in range are greater than current point
      if count(cl[(i-1):-1:idx] .< cl[i]) == 0
        clmin = cl[i]
        aoaclmin = aoa[i]
        break
      end
    end
  end
  return aoaclmin,clmin
end #findclmax

"""
    fitliftslope(aoa,cl,tol::Real=0.05,allnegfit::Bool=false)
Returns the lift slope and zero lift angle of attack as well as the data used
to compute these parameters.  The tolerance `tol` (in terms of cl) for the fit
and whether to include all data points below zero angle of attack `allnegfit`
may be specified. Returns liftslope,zeroliftangle,aoafit,clfit
"""
function fitliftslope(aoa,cl,tol::Real=0.05,allnegfit::Bool=false,center=0.0)

  if length(aoa) != length(cl)
    error("aoa and cl must have the same length")
  end

  # split into positive and negative angles of attack
  idxcenter = argmin(abs.(aoa .- center))
  idxneg = findall(aoa .< aoa[idxcenter])
  sort!(idxneg,rev = true)
  idxpos = findall(aoa .> aoa[idxcenter])
  sort!(idxpos)

  # initialize arrays of data to fit
  aoafit = [aoa[idxcenter]]
  clfit = [cl[idxcenter]]
  # create indexes for increasing and decreasing aoa
  ipos = 1
  ineg = 1
  # initialize flag to stop adding data > 0
  upperflag = false
  if ipos > length(idxpos)
    upperflag = true
  end
  # initialize flag to stop adding data < 0
  lowerflag = false
  if ineg > length(idxneg)
    lowerflag = true
  end
  # compute lift slope and zero lift angle of attack
  success = false
  liftslope = 2*pi
  zeroliftangle = 0.0
  for i = 1:(length(idxpos)+length(idxneg))
    # add positive angle of attack point to fit if closest to zero aoa
    if upperflag == false
      if lowerflag == true || abs(aoa[idxpos[ipos]]) <= abs(aoa[idxneg[ineg]])
        # add point
        push!(aoafit,aoa[idxpos[ipos]])
        push!(clfit,cl[idxpos[ipos]])
        # order points
        order = sortperm(aoafit)
        aoafit = aoafit[order]
        clfit = clfit[order]
        # create least squares fit
        lsqsol = hcat(aoafit, -ones(length(aoafit)))\clfit
        # if liftslope not defined from previous iteration, assign it here
        if ipos == 1
            liftslope = lsqsol[1]
        end
        # get slope and error of added point
        yerror = lsqsol[1]*(aoa[idxpos[ipos:end]].-lsqsol[2]/lsqsol[1]).-cl[idxpos[ipos:end]]
        # slope = (clfit[end] - clfit[end-1])/(aoafit[end] - aoafit[end-1])
        # check if on linear portion of lift curve
        if any(yerror .< tol) #slope > 0.5*liftslope ||
          liftslope = lsqsol[1]
          zeroliftangle = lsqsol[2]/lsqsol[1]
          success = true
        else # if not on linear portion remove from fit
          aoafit = aoafit[1:(end-1)]
          clfit = clfit[1:(end-1)]
          upperflag = true
        end
        #  increment counter and check for more points greater than aoa=0
        ipos = ipos+1
        if ipos > length(idxpos)
          upperflag = true
        end
      end
    end
    # add negative angle of attack point to fit if closest to zero
    if lowerflag == false
      if upperflag == true || abs(aoa[idxneg[ineg]]) <= abs(aoa[idxpos[ipos]])
        # add point
        pushfirst!(aoafit,aoa[idxneg[ineg]])
        pushfirst!(clfit,cl[idxneg[ineg]])
        # create least squares fit
        lsqsol = hcat(aoafit, -ones(length(aoafit)))\clfit
        # get error of added point
        yerror = lsqsol[1]*(aoa[idxneg[ineg:end]].-lsqsol[2]/lsqsol[1]).-cl[idxneg[ineg:end]]
        # check if on linear portion of lift curve
        if any(abs.(yerror) .< tol) || allnegfit
          liftslope = lsqsol[1]
          zeroliftangle = lsqsol[2]/lsqsol[1]
          success = true
        else # if not on linear portion remove from fit
          aoafit = aoafit[2:end]
          clfit = clfit[2:end]
          lowerflag = true
        end
        #  increment counter and check for more points less than aoa=0
        ineg = ineg+1
        if ineg > length(idxneg)
          lowerflag = true
        end
      end
    end
    # break if no more points to add
    if upperflag && lowerflag
      break
    end
  end
  if success == false
    liftslope,zeroliftangle,aoafit,clfit = fitliftslope(aoa,cl,tol,allnegfit,aoa[idxcenter]+1.0*pi/180)
  end

  return liftslope,zeroliftangle,aoafit,clfit
end

"""
    findclmaxlinear(aoa,cl,liftslope::Real,zeroliftangle::Real;tol::Real=0.1,
    interpolate::Bool=true)
Returns the angle of attack and cl of the maximum linear lift coefficient. `tol`
is used to determine the liftslope line tolerance. Returns aoaclmaxlinear,clmaxlinear
"""
function findclmaxlinear(aoa,cl,liftslope::Real,zeroliftangle::Real;
  tol::Real=0.1,interpolate::Bool=true)

  # find where difference in cl is greater than tol
  indclmaxlinear = 0
  idxzero = argmin(abs.(aoa))
  for i = idxzero:length(aoa)
    predictedcl = liftslope*(aoa[i]-zeroliftangle)
    indclmaxlinear = i
    if abs(cl[i]-predictedcl) > tol
      break
    end
  end
  if interpolate
    m = (cl[indclmaxlinear]-cl[indclmaxlinear-1])/(aoa[indclmaxlinear]-aoa[indclmaxlinear-1])
    aoaclmaxlinear = (m*aoa[indclmaxlinear-1]-liftslope*zeroliftangle-tol-cl[indclmaxlinear-1])/(m-liftslope)
    clmaxlinear = liftslope*(aoaclmaxlinear-zeroliftangle)-tol
  else
    aoaclmaxlinear = aoa[indclmaxlinear]
    clmaxlinear = cl[indclmaxlinear]
  end
  return aoaclmaxlinear,clmaxlinear
end #findclmaxlinear

end #module


text:
using ModelingToolkit, ModelingToolkitStandardLibrary, OrdinaryDiffEq
using ModelingToolkitStandardLibrary.Blocks: t, Saturation, DeadZone, Integrator

#=
Testing strategy:
The general strategy is to test systems using simple intputs where the solution is known on closed form. For algebraic systems (without differential variables), an integrator with a constant input is often used together with the system under test.
=#

## Saturation
@testset "Saturation" begin
    @info "Testing Saturation"
    y_max = 0.8
    y_min = -0.6
    @named sat = Saturation(; y_min, y_max)
    @test count(ModelingToolkit.isinput, states(sat)) == 1
    @test count(ModelingToolkit.isoutput, states(sat)) == 1
    @named iosys = ODESystem([sat.u~sin(t)], t, systems=[sat])

    sys = structural_simplify(iosys)
    stateind(sym) = findfirst(isequal(sym),states(sys))
    prob = ODEProblem(sys, Pair[sat.u=>0], (0.0, 2pi))
    sol = solve(prob, Rosenbrock23(), saveat=0:0.1:2pi)
    y = clamp.(sin.(sol.t), y_min, y_max)
    # plot([sol[sat.y] y])
    @test sol[sat.y] ≈ y rtol = 1e-6
end

@testset "DeadZone" begin
    @info "Testing DeadZone"

    ie = ifelse
    deadzone(u, u_min, u_max) = ie(u > u_max, u-u_max, ie( u < u_min, u-u_min, 0))

    u_max = 1
    u_min = -2
    @named dz = DeadZone(; u_min, u_max)
    @named int = Integrator()
    @test count(ModelingToolkit.isinput, states(dz)) == 1
    @test count(ModelingToolkit.isoutput, states(dz)) == 1
    @named iosys = ODESystem([
        int.u ~ 1
        int.y ~ dz.u
        ], t, systems=[dz, int]
    )

    sys = structural_simplify(iosys)
    prob = ODEProblem(sys, Pair[int.x => -3], (0.0, 5))
    sol = solve(prob, Rosenbrock23(), saveat=0:0.1:5)
    y = deadzone.(sol[int.y], u_min, u_max)
    @test y[1] == -3 - u_min
    @test y[end] ≈ 2 - u_max
    @test y[end÷2] == 0

    # plot([y sol[dz.y] sol[dz.u]])
    @test sol[dz.y] ≈ y rtol = 1e-6
end