text:
"""
    $SIGNATURES

Notes
- Parametric state machine function nr. 3
"""
function solveUp_ParametricStateMachine(csmc::CliqStateMachineContainer)

  infocsm(csmc, "Par-3, Solving Up")

  setCliqueDrawColor!(csmc.cliq, "red")
  # csmc.drawtree ? drawTree(csmc.tree, show=false, filepath=joinpath(getSolverParams(csmc.dfg).logpath,"bt.pdf")) : nothing

  #TODO maybe change to symbols
  msgfcts = DFGFactor[]
  # LITTLE WEIRD get previously set up msgs (stored in this clique)
    # FIXME, fetch message buffered in channels
  # see #855
  for (idx,upmsg) in getMessageBuffer(csmc.cliq).upRx #get cached messages taken from children saved in this clique
    #TODO remove temp msgfcts container
    append!(msgfcts, addMsgFactors!(csmc.cliqSubFg, upmsg, UpwardPass) ) # addMsgFactors_Parametric!
  end
  logCSM(csmc,  "length mgsfcts=$(length(msgfcts))")
  infocsm(csmc, "length mgsfcts=$(length(msgfcts))")

  # store the cliqSubFg for later debugging
  _dbgCSMSaveSubFG(csmc, "fg_beforeupsolve")

  vardict, result, varIds, Σ = solveFactorGraphParametric(csmc.cliqSubFg)

  logCSM(csmc, "$(csmc.cliq.id) vars $(keys(varIds))")
  # @info "$(csmc.cliq.id) Σ $(Σ)"
  # Pack all results in variables
  # FIXME test f_converged, ls_success, confirm convergence check
  if result.f_converged || result.g_converged
    logCSM(csmc, "$(csmc.cliq.id): subfg optim converged updating variables")
    for (v,val) in vardict
      vnd = getSolverData(getVariable(csmc.cliqSubFg, v), :parametric)
      # fill in the variable node data value
      logCSM(csmc, "$(csmc.cliq.id) up: updating $v : $val")
      vnd.val .= val.val
      #calculate and fill in covariance
      #TODO rather broadcast than make new memory
      vnd.bw = val.cov
    end
  # elseif length(lsfPriors(csmc.cliqSubFg)) == 0 #FIXME
  #   @error "Par-3, clique $(csmc.cliq.id) failed to converge in upsolve, but ignoring since no priors" result
  else
    @error "Par-3, clique $(csmc.cliq.id) failed to converge in upsolve" result
    # propagate error to cleanly exit all cliques
    putErrorUp(csmc)
    if length(getParent(csmc.tree, csmc.cliq)) == 0
      putErrorDown(csmc)
      return IncrementalInference.exitStateMachine
    end

    return waitForDown_StateMachine
  end

  # Done with solve delete factors
  #TODO confirm, maybe don't delete mesage factors on subgraph, maybe delete if its priors, but not conditionals
  deleteMsgFactors!(csmc.cliqSubFg)

  # store the cliqSubFg for later debugging
  _dbgCSMSaveSubFG(csmc, "fg_afterupsolve")

  #fill in belief
  #TODO createBeliefMessageParametric(csmc.cliqSubFg, csmc.cliq, solvekey=opts.solvekey)
  cliqSeparatorVarIds = getCliqSeparatorVarIds(csmc.cliq)
  #Fil in CliqueLikelihood
  cliqlikelihood = calculateMarginalCliqueLikelihood(vardict, Σ, varIds, cliqSeparatorVarIds)
  # @info "$(csmc.cliq.id) clique likelihood message $(cliqlikelihood)"
  beliefMsg = LikelihoodMessage(status=UPSOLVED, variableOrder=cliqSeparatorVarIds, cliqueLikelihood=cliqlikelihood, msgType=ParametricMessage())

  #FIXME bit of a hack, only fill in variable beliefs if there are priors or for now more than one seperator
  if length(lsfPriors(csmc.cliqSubFg)) > 0 || length(cliqSeparatorVarIds) > 1
    for si in cliqSeparatorVarIds
      vnd = getSolverData(getVariable(csmc.cliqSubFg, si), :parametric)
      beliefMsg.belief[si] = TreeBelief(deepcopy(vnd))
    end
  end

  for e in getEdgesParent(csmc.tree, csmc.cliq)
    logCSM(csmc, "$(csmc.cliq.id): put! on edge $(e)")
    getMessageBuffer(csmc.cliq).upTx = deepcopy(beliefMsg)
    putBeliefMessageUp!(csmc.tree, e, beliefMsg)
  end

  return waitForDown_StateMachine
end

"""
    $SIGNATURES

Notes
- Parametric state machine function nr. 5
"""
function solveDown_ParametricStateMachine(csmc::CliqStateMachineContainer)

  infocsm(csmc, "Par-5, Solving down")

  setCliqueDrawColor!(csmc.cliq, "red")
  # csmc.drawtree ? drawTree(csmc.tree, show=false, filepath=joinpath(getSolverParams(csmc.dfg).logpath,"bt.pdf")) : nothing

  # TODO create function:
  # updateMsgSeparators!(csmc.cliqSubFg, downmsg)
  downmsg = getMessageBuffer(csmc.cliq).downRx  #see #855
  svars = getCliqSeparatorVarIds(csmc.cliq)
  if !isnothing(downmsg)
    for (msym, belief) in downmsg.belief
      if msym in svars
        #TODO maybe combine variable and factor in new prior?
        vnd = getSolverData(getVariable(csmc.cliqSubFg, msym), :parametric)
        logCSM(csmc, "$(csmc.cliq.id): Updating separator $msym from message $(belief.val)")
        vnd.val .= belief.val
        vnd.bw .= belief.bw
      end
    end
  end

  # store the cliqSubFg for later debugging
  # NOTE ITS not changed for now but keep here for possible future use
  # _dbgCSMSaveSubFG(csmc, "fg_beforedownsolve")

  # DownSolve cliqSubFg
  #only down solve if its not a root
  if length(getParent(csmc.tree, csmc.cliq)) != 0
    frontals = getCliqFrontalVarIds(csmc.cliq)
    vardict, result, flatvars, Σ = solveConditionalsParametric(csmc.cliqSubFg, frontals)
    #TEMP testing difference
    # vardict, result = solveFactorGraphParametric(csmc.cliqSubFg)
    # Pack all results in variables
    if result.g_converged || result.f_converged
      logCSM(csmc, "$(csmc.cliq.id): subfg optim converged updating variables"; loglevel=Logging.Info)
      for (v,val) in vardict
        logCSM(csmc, "$(csmc.cliq.id) down: updating $v : $val"; loglevel=Logging.Info)
        vnd = getSolverData(getVariable(csmc.cliqSubFg, v), :parametric)
        #Update subfg variables
        vnd.val .= val.val
        vnd.bw .= val.cov
      end
    else
      @error "Par-5, clique $(csmc.cliq.id) failed to converge in down solve" result
      #propagate error to cleanly exit all cliques
      putErrorDown(csmc)
      return IncrementalInference.exitStateMachine
    end
  end

  #TODO fill in belief
  cliqFrontalVarIds = getCliqFrontalVarIds(csmc.cliq)
  #TODO createBeliefMessageParametric
  # beliefMsg = createBeliefMessageParametric(csmc.cliqSubFg, cliqFrontalVarIds, solvekey=opts.solvekey)
  beliefMsg = LikelihoodMessage(status=DOWNSOLVED, msgType=ParametricMessage())
  for fi in cliqFrontalVarIds
    vnd = getSolverData(getVariable(csmc.cliqSubFg, fi), :parametric)
    beliefMsg.belief[fi] = TreeBelief(vnd)
    # beliefMsg.belief[fi] = TreeBelief(vnd.val, vnd.bw, vnd.inferdim, vnd.variableType.manifolds)
    logCSM(csmc, "$(csmc.cliq.id): down message $fi : $beliefMsg"; loglevel=Logging.Info)
  end

  # pass through the frontal variables that were sent from above
  if !isnothing(downmsg)
    pass_through_separators = intersect(svars, keys(downmsg.belief))
    for si in pass_through_separators
      beliefMsg.belief[si] = downmsg.belief[si]
      logCSM(csmc, "adding parent message"; sym=si, msg=downmsg.belief[si])
    end
  end

  #TODO sendBeliefMessageParametric(csmc, beliefMsg)
  #TODO maybe send a specific message to only the child that needs it
  @sync for e in getEdgesChildren(csmc.tree, csmc.cliq)
    logCSM(csmc,  "$(csmc.cliq.id): put! on edge $(e)")
    @async putBeliefMessageDown!(csmc.tree, e, beliefMsg)#put!(csmc.tree.messageChannels[e.index].downMsg, beliefMsg)
  end

  logCSM(csmc, "$(csmc.cliq.id): Solve completed")

  return updateFromSubgraph_ParametricStateMachine

end

#TODO Consolidate with updateFromSubgraph_StateMachine
function updateFromSubgraph_ParametricStateMachine(csmc::CliqStateMachineContainer)

  # transfer results to main factor graph
  frontsyms = getFrontals(csmc.cliq)
  logCSM(csmc, "11, finishingCliq -- going for transferUpdateSubGraph! on $frontsyms")
  transferUpdateSubGraph!(csmc.dfg, csmc.cliqSubFg, frontsyms, updatePPE=false, solveKey=:parametric)

  #solve finished change color
  setCliqueDrawColor!(csmc.cliq, "lightblue")

  logCSM(csmc, "Clique $(csmc.cliq.id): Finished", loglevel=Logging.Info)
  return IncrementalInference.exitStateMachine

end


text:
using AndorSIF
using Test
import FileIO: load

testfile_2d = joinpath(@__DIR__, "testfiles/2d_testfile.sif")
testfile_1d = joinpath(@__DIR__, "testfiles/1d_testfile.sif")

img_2d = load(testfile_2d)
img_1d = load(testfile_1d)

@test size(img_2d) == (512, 512, 1)
@test size(img_1d) == (1, 512, 1)
@test img_1d[1:2] == [789.0, 783.0]
@test img_1d[end-1:end] == [765.0, 768.0]
@test img_1d.ixon["exposure_time"] == 5.0

ext: jl


text:
# FIX

function read_slist!(S::SeisData, f::String; lennartz::Bool=false)
  fname = realpath(f)
  nx = countlines(fname) - 1
  i = 1
  X = Array{Float32,1}(undef, nx)

  # file read
  io = open(fname, "r")
  h_line = readline(io)
  while i ≤ nx
    v = stream_float(io, 0x00)
    setindex!(X, v, i)
    i += 1
  end
  close(io)

  # header
  if lennartz
    id_sep = "."
    h = split(h_line)
    sta = replace(h[3], "\'" => "")
    cmp = last(split(fname, id_sep))
    ts = (Date(h[8]).instant.periods.value)*86400000000 +
          div(Time(h[9]).instant.value, 1000) -
          dtconst
    C = SeisChannel(*(id_sep, sta, id_sep, id_sep, cmp),
                    "",
                    GeoLoc(),
                    1000.0 / parse(Float64, h[5]),
                    1.0,
                    PZResp(),
                    "",
                    fname,
                    Dict{String, Any}(),
                    String[],
                    mk_t(nx, ts),
                    X)
  else
    h = split(h_line, ',')
    id = split_id(split(h[1])[2], c="_")
    C = SeisChannel(join(id, "."),
                    "",
                    GeoLoc(),
                    parse(Float64, split(h[3])[1]),
                    1.0,
                    PZResp(),
                    "",
                    fname,
                    Dict{String, Any}(),
                    String[],
                    mk_t(nx, 1000*(DateTime(lstrip(h[4])).instant.periods.value - div(dtconst, 1000))),
                    X)
  end
  push!(S, C)
  return nothing
end


text:
module PHonon

using REPL.Terminals: TTYTerminal
using REPL.TerminalMenus: RadioMenu, request

using Crayons.Box: GREEN_FG
using QuantumESPRESSOBase.Inputs.PHonon:
    PhNamelist, Q2rNamelist, MatdynNamelist, DynmatNamelist, Q2rInput, DynmatInput

using ..Inputs: namelist_builder, setfield_helper

import QuantumESPRESSOHelpers.Inputs

function Inputs.namelist_builder(terminal::TTYTerminal, ::Type{T}) where {T<:PhNamelist}
    print(
        terminal,
        GREEN_FG("Please input the atomic mass [amu] of each atomic type `amass` (separated by spaces): ") |>
        string,
    )
    amass = map(x -> parse(Float64, x), split(readline(terminal), " ", keepempty = false))
    epsil_pool = pairs((false, true))
    epsil = epsil_pool[request(
        terminal,
        GREEN_FG("Please select the `epsil`: ") |> string,
        RadioMenu([false, true]),
    )]
    q_in_band_form_pool = pairs((false, true))
    q_in_band_form = q_in_band_form_pool[request(
        terminal,
        GREEN_FG("Please select the `q_in_band_form`: ") |> string,
        RadioMenu([false, true]),
    )]
    print(
        terminal,
        GREEN_FG("Please input parameters of the Monkhorst-Pack grid `nq` 1-3 (separated by spaces): ") |>
        string,
    )
    nq1, nq2, nq3 =
        map(x -> parse(Float64, x), split(readline(terminal), " ", keepempty = false))
    print(
        terminal,
        GREEN_FG("Please input parameters of the Monkhorst-Pack grid `nk` 1-3 (separated by spaces): ") |>
        string,
    )
    nk1, nk2, nk3 =
        map(x -> parse(Float64, x), split(readline(terminal), " ", keepempty = false))
    print(
        terminal,
        GREEN_FG("Please input offset `k` 1-3 (separated by spaces): ") |> string,
    )
    k1, k2, k3 =
        map(x -> parse(Float64, x), split(readline(terminal), " ", keepempty = false))
    ph = T(
        amass = amass,
        epsil = epsil,
        q_in_band_form = q_in_band_form,
        nq1 = nq1,
        nq2 = nq2,
        nq3 = nq3,
        nk1 = nk1,
        nk2 = nk2,
        nk3 = nk3,
        k1 = k1,
        k2 = k2,
        k3 = k3,
    )
    return setfield_helper(terminal, ph)
end # function namelist_builder
function Inputs.namelist_builder(terminal::TTYTerminal, ::Type{T}) where {T<:Q2rNamelist}
    print(terminal, GREEN_FG("name of input dynamical matrices `fildyn`: ") |> string)
    fildyn = strip(readline(terminal))
    print(terminal, GREEN_FG("name of output force constants `flfrc`: ") |> string)
    flfrc = strip(readline(terminal))
    zasr_pool = pairs(("no", "simple", "crystal", "one-dim", "zero-dim"))
    zasr = zasr_pool[request(
        terminal,
        GREEN_FG("Please input the type of acoustic sum rules used for the Born effective charges `zasr`: ") |>
        string,
        RadioMenu(collect(values(zasr_pool))),
    )]
    q2r = T(fildyn = fildyn, flfrc = flfrc, zasr = zasr)
    return setfield_helper(terminal, q2r)
end # function namelist_builder
function Inputs.namelist_builder(
    terminal::TTYTerminal,
    ::Type{T},
) where {T<:MatdynNamelist}
    dos_pool = pairs((false, true))
    dos = dos_pool[request(
        terminal,
        GREEN_FG("Please select if calculate phonon density of states `dos`: ") |> string,
        RadioMenu([false, true]),
    )]
    print(
        terminal,
        GREEN_FG("Please input the energy step, in cm^(-1) `deltaE`: ") |> string,
    )
    deltaE = parse(Float64, readline(terminal))
    print(
        terminal,
        GREEN_FG("Please input uniform q-point grid for DOS calculation `nk` 1-3 (separated by spaces): ") |>
        string,
    )
    nk1, nk2, nk3 =
        map(x -> parse(Float64, x), split(readline(terminal), " ", keepempty = false))
    asr_pool = pairs(("no", "simple", "crystal", "one-dim", "zero-dim"))
    asr = asr_pool[request(
        terminal,
        GREEN_FG("Please input the type of acoustic sum rule `asr`: ") |> string,
        RadioMenu(collect(values(asr_pool))),
    )]
    print(terminal, GREEN_FG("name of output force constants `flfrc`: ") |> string)
    flfrc = strip(readline(terminal))
    print(terminal, GREEN_FG("name of input dynamical matrices `fildyn`: ") |> string)
    fildyn = strip(readline(terminal))
    print(
        terminal,
        GREEN_FG("Please input the masses of atoms in the supercell (a.m.u.) `amass` (separated by spaces): ") |>
        string,
    )
    amass = map(x -> parse(Float64, x), split(readline(terminal), " ", keepempty = false))
    print(
        terminal,
        GREEN_FG("Please input the number of atom types in the supercell `ntyp`: ") |>
        string,
    )
    ntyp = parse(Int, readline(terminal))
    q_in_band_form_pool = pairs((false, true))
    q_in_band_form = q_in_band_form_pool[request(
        terminal,
        GREEN_FG("Please select the `q_in_band_form`: ") |> string,
        RadioMenu([false, true]),
    )]
    q_in_cryst_coord_pool = pairs((false, true))
    q_in_cryst_coord = q_in_cryst_coord_pool[request(
        terminal,
        GREEN_FG("Please select the `q_in_cryst_coord`: ") |> string,
        RadioMenu([false, true]),
    )]
    nosym_pool = pairs((false, true))
    nosym = nosym_pool[request(
        terminal,
        GREEN_FG("Please select if impose symmetry and time reversal `nosym`: ") |> string,
        RadioMenu([false, true]),
    )]
    matdyn = T(
        dos = dos,
        deltaE = deltaE,
        nk1 = nk1,
        nk2 = nk2,
        nk3 = nk3,
        asr = asr,
        flfrc = flfrc,
        fildyn = fildyn,
        amass = amass,
        ntyp = ntyp,
        q_in_band_form = q_in_band_form,
        q_in_cryst_coord = q_in_cryst_coord,
        nosym = nosym,
    )
    return setfield_helper(terminal, matdyn)
end # function namelist_builder
function Inputs.namelist_builder(
    terminal::TTYTerminal,
    ::Type{T},
) where {T<:DynmatNamelist}
    asr_pool = pairs(("no", "simple", "crystal", "one-dim", "zero-dim"))
    asr = asr_pool[request(
        terminal,
        GREEN_FG("Please select the type of acoustic sum rule `asr`: ") |> string,
        RadioMenu(collect(values(asr_pool))),
    )]
    print(
        terminal,
        GREEN_FG("Please input mass for each atom type `amass` (separated by spaces): ") |>
        string,
    )
    amass = map(x -> parse(Float64, x), split(readline(terminal), " ", keepempty = false))
    dynmat = T(asr = asr, amass = amass)
    return setfield_helper(terminal, dynmat)
end # function namelist_builder

# function Inputs.input_builder(terminal::TTYTerminal, ::Type{T}) where {T<:PhInput}
#     ph = namelist_builder(terminal, PhNamelist)
# end
function Inputs.input_builder(terminal::TTYTerminal, ::Type{T}) where {T<:Q2rInput}
    return Q2rInput(namelist_builder(terminal, Q2rNamelist))
end
# function Inputs.input_builder(terminal::TTYTerminal, ::Type{T}) where {T<:MatdynInput}
#     ph = namelist_builder(terminal, MatdynNamelist)
# end
function Inputs.input_builder(terminal::TTYTerminal, ::Type{T}) where {T<:DynmatInput}
    return DynmatInput(namelist_builder(terminal, DynmatNamelist))
end

end # module PHonon


text:
using Test
using DynamicHMCExamples: rel_path
using Random
Random.seed!(UInt32[0x57a97f0d, 0x1a38664c, 0x0dddb228, 0x7dbba96f])

# includenbinclude(rel_path("Estimation of a covariance matrix.ipynb"))
# @test all(ESS .≥ 500)

@testset "independent bernoulli" begin
    include(rel_path("example_independent_bernoulli.jl"))
    @test ess_α ≥ 200
end

@testset "linear regression" begin
    include(rel_path("example_linear_regression.jl"))
    @test length(ess) == 4
end

include("../docs/make.jl")


text:
module QInterpolations

import Interpolations:interpolate,BSpline,Quadratic,Line,OnGrid,scale,gradient1,extrapolate
import Base.getindex

export construct_interpolations, COMPLEX_INTERPOLATION, COMPLEX_INTERPOLATION_ARRAY, REAL_INTERPOLATION_ARRAY, gradient, getindex

struct COMPLEX_INTERPOLATION
    real_part::AbstractArray{Float64,1}
    imag_part::AbstractArray{Float64,1}
end

struct COMPLEX_INTERPOLATION_ARRAY
    real_part::AbstractArray{AbstractArray{Float64, 1}, N} where N
    imag_part::AbstractArray{AbstractArray{Float64, 1}, N} where N
end

struct REAL_INTERPOLATION_ARRAY
    value::AbstractArray{AbstractArray{Float64, 1}, N} where N
end

function getindex(r_iter::REAL_INTERPOLATION_ARRAY, i...)
    getindex(r_iter.value, i...)
end

function getindex(c_iter::COMPLEX_INTERPOLATION_ARRAY, i...)
    r = getindex(c_iter.real_part, i...)
    i = getindex(c_iter.imag_part, i...)
    r,i
end

function (c_iter::COMPLEX_INTERPOLATION)(t)
    c_iter.real_part(t) + 1.0im*c_iter.imag_part(t)
end

function (c_iter::COMPLEX_INTERPOLATION_ARRAY)(t)
    res_size = size(c_iter.real_part)
    res = Array{ComplexF64}(undef, res_size)
    for i in eachindex(res)
        res[i] = c_iter.real_part[i](t) + 1.0im*c_iter.imag_part[i](t)
    end
    res
end

function (c_iter::REAL_INTERPOLATION_ARRAY)(t)
    res_size = size(c_iter.value)
    res = Array{Float64}(undef, res_size)
    for i in eachindex(res)
        res[i] = c_iter.value[i](t)
    end
    res
end

function construct_interpolations(x, y::Array{ComplexF64,1}; extrapolation="")
    yr = real(y)
    yi = imag(y)
    itpr = interpolate(yr, BSpline(Quadratic(Line(OnGrid()))))
    itpi = interpolate(yi, BSpline(Quadratic(Line(OnGrid()))))
    if lowercase(extrapolation) == "line"
        itpr = extrapolate(itpr, Line())
        itpi = extrapolate(itpi, Line())
    end
    sitpr = scale(itpr, x)
    sitpi = scale(itpi, x)
    COMPLEX_INTERPOLATION(sitpr, sitpi)
end

function construct_interpolations(x, y::Array{Float64,1}; extrapolation="")
    itp = interpolate(y,  BSpline(Quadratic(Line(OnGrid()))))
    if lowercase(extrapolation) == "line"
        itp = extrapolate(itp, Line())
    end
    sitp = scale(itp, x)
    return sitp
end

function construct_interpolations(x, y::Union{Array{Array{Float64,1},1},Array{Array{Float64,2},1}})
    res_size = size(y[1])
    interpolation_res = Array{AbstractArray}(undef,res_size)
    max_index = reduce(*,res_size)
    for j in range(1,length=max_index)
        interpolation_array = [y[i][j] for i in range(1,length=length(y))]
        itp = interpolate(interpolation_array,  BSpline(Quadratic(Line(OnGrid()))))
        interpolation_res[j] = scale(itp, x)
    end
    REAL_INTERPOLATION_ARRAY(interpolation_res)
end

function construct_interpolations(x, y::Union{Array{Array{ComplexF64,1},1},Array{Array{ComplexF64,2},1}})
    res_size = size(y[1])
    interpolation_res_real = Array{AbstractArray}(undef, res_size)
    interpolation_res_imag = Array{AbstractArray}(undef, res_size)
    max_index = reduce(*,res_size)
    for j in range(1, length=max_index)
        interpolation_array = [y[i][j] for i in range(1,length=length(y))]
        itpr = interpolate(real(interpolation_array), BSpline(Quadratic(Line(OnGrid()))))
        itpi = interpolate(imag(interpolation_array), BSpline(Quadratic(Line(OnGrid()))))
        interpolation_res_real[j] = scale(itpr, x)
        interpolation_res_imag[j] = scale(itpi, x)
    end
    COMPLEX_INTERPOLATION_ARRAY(interpolation_res_real, interpolation_res_imag)
end

function array_2_range(x)
    start = x[1]
    stop = x[end]
    range(start, stop=stop, length=length(x))
end

function gradient(c_iter::REAL_INTERPOLATION_ARRAY, t::Real)
    res = Array{Float64}(undef, size(c_iter.value))
    for i in eachindex(res)
        res[i] = gradient1(c_iter.value[i], t)
    end
    res
end

function gradient(x::COMPLEX_INTERPOLATION_ARRAY, t::Real)
    re = Array{ComplexF64}(undef, size(x.real_part))
    img = Array{ComplexF64}(undef, size(x.imag_part))
    for i in eachindex(re)
        re[i] = gradient1(x.real_part[i], t)
        img[i] = gradient1(x.imag_part[i], t)
    end
    re+1.0im*img
end

function gradient(x, t::Real)
    gradient1(x, t)
end

function gradient(x, t::AbstractArray{T, 1}) where T<:Real
    [gradient(x, i) for i in t]
end
end # module

max_stars_repo_name: neversakura/QInterpolate

max_issues_repo_name: neversakura/QInterpolate

max_forks_repo_name: neversakura/QInterpolate


text:
module DateRangeFilter
using Dash

const resources_path = realpath(joinpath( @__DIR__, "..", "deps"))
const version = "0.0.1-a"

include("date_range_filter.jl")

function __init__()
    DashBase.register_package(
        DashBase.ResourcePkg(
            "date_range_filter",
            resources_path,
            version = version,
            [
                DashBase.Resource(
    relative_package_path = "date_range_filter.min.js",
    external_url = nothing,
    dynamic = nothing,
    async = nothing,
    type = :js
),
DashBase.Resource(
    relative_package_path = "date_range_filter.min.js.map",
    external_url = nothing,
    dynamic = true,
    async = nothing,
    type = :js
)
            ]
        )

    )
end
end


text:
using Test

#include("dvcreso.jl")

@testset "isid" begin
  @test iscid(:C12)
  @test !iscid(:R12)
  @test isrid(:R11111)
  @test !isrid(:C222)
  @test !iscid("abc")
  @test !isrid("abc")
end
@testset "newvar" begin
  @test newvar(:C4, :x)   == :x_C4
  @test newvar(:C4, :x5)  == :x5_C4
  @test newvar(:C14, :x)  == :x_C14
  @test newvar(:C4, :xC4) == :xC4_C4
  @test newvar(:C4, :xyz) == :xyz_C4

  @test newvar(:R3, :x_C2)               == :x_C2R3
  @test newvar(:R3, :x_C122)             == :x_C122R3
  @test newvar(:R453, :x_C122)           == :x_C122R453
  @test newvar(:R15, :x_C1R9)           == :x_C1R9R15
  @test newvar(:R15, :x_C12R97)         == :x_C12R97R15
end

@testset "newvarlist" begin
  @test newvarlist(:R19, [:z1_C12,:w11_C123R10]) == [:z1_C12R19,:w11_C123R10R19]
  @test newvarlist(:R19, [:x,:y10]) == [:x_R19, :y10_R19]
end

@testset "input rename_term" begin
 @test rename_term(:C3, [], Meta.parse("+P(a,b)")) == Meta.parse("+P(a,b)")
 @test rename_term(:C3, [], Meta.parse("+P(f(a),g(b,a))")) == Meta.parse("+P(f(a),g(b,a))")

 @test rename_term(:C3, [:x], Meta.parse("+P(x)")) == Meta.parse("+P(x_C3)")
 @test rename_term(:C3, [:x], Meta.parse("+P(x,x)")) ==  Meta.parse("+P(x_C3,x_C3)")
 @test rename_term(:C3, [:x,:y], Meta.parse("+P(x,y)")) ==  Meta.parse("+P(x_C3, y_C3)")

 @test rename_term(:C3, [:x], Meta.parse("+P(fun(x))")) == Meta.parse("+P(fun(x_C3))")
 @test rename_term(:C3, [:x], Meta.parse("+P(f(x,x))")) == Meta.parse("+P(f(x_C3,x_C3))")
 @test rename_term(:C3, [:x,:y], Meta.parse("+P(f(x),h(x,y))")) == Meta.parse("+P(f(x_C3),h(x_C3,y_C3))")

 @test rename_term(:C3, [:x3,:y2], Meta.parse("+P(x3,f(y2))")) == Meta.parse("+P(x3_C3, f(y2_C3))")
 @test rename_term(:C3, [:x45,:yz], Meta.parse("+P(f(x45),g(yz,x45))")) == Meta.parse("+P(f(x45_C3), g(yz_C3, x45_C3))")

end

@testset "resolvent rename_term" begin
 @test rename_term(:R19, [], Meta.parse("+P(a,b)")) == Meta.parse("+P(a,b)")
 @test rename_term(:R19, [], Meta.parse("+P(f(a),g(b,a))")) == Meta.parse("+P(f(a),g(b,a))")

 @test rename_term(:R19, [:x_C22], Meta.parse("+P(x_C22)")) == Meta.parse("+P(x_C22R19)")
 @test rename_term(:R19, [:x_C22], Meta.parse("+P(x_C22,x_C22)")) ==  Meta.parse("+P(x_C22R19,x_C22R19)")
 @test rename_term(:R19, [:x_C22,:y_C22], Meta.parse("+P(x_C22,y_C22)")) ==  Meta.parse("+P(x_C22R19, y_C22R19)")

 @test rename_term(:R19, [:x_C22], Meta.parse("+P(fun(x_C22))")) == Meta.parse("+P(fun(x_C22R19))")
 @test rename_term(:R19, [:x_C22], Meta.parse("+P(f(x_C22,x_C22))")) == Meta.parse("+P(f(x_C22R19,x_C22R19))")
 @test rename_term(:R19, [:x_C22,:y_C22], Meta.parse("+P(f(x_C22),h(x_C22,y_C22))")) == Meta.parse("+P(f(x_C22R19),h(x_C22R19,y_C22R19))")

 @test rename_term(:R19, [:x3_C22,:y2_C22], Meta.parse("+P(x3_C22,f(y2_C22))")) == Meta.parse("+P(x3_C22R19, f(y2_C22R19))")
 @test rename_term(:R19, [:x45_C22,:yz_C22], Meta.parse("+P(f(x45_C22),g(yz_C22,x45_C22))")) == Meta.parse("+P(f(x45_C22R19), g(yz_C22R19, x45_C22R19))")

end

@testset "rename_clause" begin
 r19 = rename_clause(:R19, [:x3_C22,:y2_C22,:x3_C11R2], Meta.parse("[+P(x3_C22,f(y2_C22)),-Q(h(x3_C11R2,y2_C22),y2_C22)]").args)

 @test r19.cid == :R19
 @test r19.vars == [:x3_C22R19,:y2_C22R19,:x3_C11R2R19]
 @test r19.body == Meta.parse("[+P(x3_C22R19, f(y2_C22R19)),-Q(h(x3_C11R2R19,y2_C22R19),y2_C22R19)]").args

end

@testset "fitting" begin
 @test fitting_vars_term([:x,:y], Meta.parse("a")) == []
 @test fitting_vars_term([:x,:y], Meta.parse("x")) == [:x]
 @test fitting_vars_term([:x,:y], Meta.parse("f(x,y)")) == [:x,:y]
 @test fitting_vars_term([:x,:y], Meta.parse("f(x,a)")) == [:x]
 @test fitting_vars_term([:x,:y], Meta.parse("f(x,g(y))")) == [:x,:y]
 @test fitting_vars_lit([:x,:y], Meta.parse("(+P(x,g(y)))")) == [:x,:y]
 @test fitting_vars_lit([:x,:y], Meta.parse("(+P(x,g(x)))")) == [:x]
 @test fitting_vars_lit([:x,:y], Meta.parse("(+P(y,g(x)))")) == [:y,:x]

end

@testset "inverseof" begin
 @test inverseof(:+) == :-
 @test inverseof(:-) == :+
end

@testset "rotate" begin
 @test rotate([1,2,3]) == [1,2,3]
 @test rotate([1,2,3],0) == [1,2,3]
 @test rotate([1,2,3],1) == [2,3,1]
 @test rotate([1,2,3],2) == [3,1,2]
 @test_throws ErrorException rotate([1,2,3],3)

end

@testset "findrepeat in proof" begin
 @test !findrepeat([[:L1_C1,:L2_R1],[:L3_C3,:L4_R12],[:L1_C3,:L3_R4]])
 @test findrepeat([[:L1_C1,:L2_R1],[:L3_C3,:L4_R12],[:L1_C3,:L2_R4]])

end

max_stars_repo_name: sazare/cheapViews

max_issues_repo_name: sazare/cheapViews

max_forks_repo_name: sazare/cheapViews


text:
## occupying
import Statistics.quantile
function occupying(img::AbstractMatrix, bgvalue=img[1])
    return sum(img .!= bgvalue)
end
function occupying(imgs::AbstractVector, bgvalue=imgs[1][1])
    if isempty(imgs) return 0 end
    return sum(p->occupying(p, bgvalue), imgs)
end
function boxoccupying(img::AbstractMatrix, border=0)
    return (size(img, 1)-2border) * (size(img, 2)-2border)
end
function boxoccupying(imgs::AbstractVector, border=0)
    if isempty(imgs) return 0 end
    return sum(p->boxoccupying(p, border), imgs)
end
function feelingoccupying(imgs, border=0, bgvalue=imgs[1][1])
    bs = boxoccupying.(imgs, border)
    os = occupying.(imgs, bgvalue)
    s = (0.8 * sum(bs) + 0.2 * sum(os)) / 0.93 #兼顾饱满字体（华文琥珀）和清瘦字体（仿宋）
    # sum(os) ≈ 2/3 sum(bs), 故除以0.93还原到sum(bs)的大小
    th = 10quantile(bs, 0.1)
    bigind = findall(x->x>th, bs)
#     @show length(bigind)
    er = (sum(bs[bigind]) - sum(os[bigind])) * 0.2 #兼顾大字的内隙和小字的占据
    (s - er)
end

function textoccupying(words, fontsizes, fonts)
    border=1
    imgs = []
    for (c, sz, ft) in zip(words, fontsizes, fonts)
#         print(c)
        img = Render.rendertext(string(c), sz, backgroundcolor=(0,0,0,0), font=ft, border=border)
        push!(imgs, img)
    end
    feelingoccupying(imgs, border) #border>0 以获取背景色imgs[1]
end

## prepare
function preparemask(img, bgcolor)
    mask = imagemask(img, bgcolor)
    maskqt = maskqtree(mask)
    groundsize = size(maskqt[1], 1)
    maskoccupying = occupying(mask, false)
    @assert maskoccupying==occupying(QTree.kernel(maskqt[1]), QTree.FULL)
    return img, maskqt, groundsize, maskoccupying
end

function prepareword(word, fontsize, color, angle; backgroundcolor=(0,0,0,0), font="", border=0)
    mat, svg = rendertext(string(word), fontsize, color=color, backgroundcolor=backgroundcolor,
        angle=angle, border=border, font=font, type=:both)
    Render.recolor!(mat, color), svg #字体边缘有杂色
end

wordmask(img, bgcolor, border) = dilate(alpha.(img) .!= 0, border)
#use `alpha` instead of `convert(eltype(img), parsecolor(bgcolor))`
#https://github.com/JuliaGraphics/Luxor.jl/issues/107

## weight_scale
function scalestep(x₀, y₀, x₁, y₁, y)
    x₀ = x₀ ^ 2
    x₁ = x₁ ^ 2
    x = ((x₁-x₀)*y + x₀*y₁ - x₁*y₀) / (y₁-y₀) # 假设y=k*x^2+b
    x > 0 ? √x : (√min(x₀, x₁))/2
end

function find_weight_scale!(wc::WC; initialscale=0, density=0.3, maxiter=5, tolerance=0.05)
    ground_size = getparameter(wc, :maskoccupying)
    words = wc.words
    if initialscale <= 0
        initialscale = √(ground_size/length(words)/0.45*density) #初始值假设字符的字面框面积占正方格比率为0.45（低估了汉字）
    end
    @assert sum(wc.weights.^2 .* length.(words)) / length(wc.weights) ≈ 1.0
    target = density * ground_size
    target_lower = (density - tolerance) * ground_size
    target_upper = (density + tolerance) * ground_size
    target = density * ground_size
    best_tar_H = Inf
    best_tar_L = -Inf
    best_scale_H = Inf
    best_scale_L = -Inf
    step = 0
    sc1 = initialscale
    fonts = getfonts(wc)
    sc0 = 0.
    tg0 = 0.
    oneway_count = 1
    while true
        step = step + 1
        if step > maxiter
            @warn "find_weight_scale! reach the `maxiter`. The `density` may be inaccurate. This may be caused by too small background, too many words or too big `minfontsize`."
            break
        end
        # cal tg1
        setparameter!(wc, sc1, :scale)
        tg1 = textoccupying(words, getfontsizes(wc), fonts)
        dens = tg1 / ground_size
        println("scale=$(getparameter(wc, :scale)), density=$dens\t", dens>density ? "↑" : "↓")
        if tg1 > target
            if best_tar_H > tg1
                best_tar_H = tg1
                best_scale_H = sc1
            end
        else
            if best_tar_L <= tg1
                best_tar_L = tg1
                best_scale_L = sc1
            end
        end
        # cal sc2
        sc2 = scalestep(sc0, tg0, sc1, tg1, target)
#         @show sc0, tg0, sc1, tg1, sc2
        if !(best_scale_L < sc2 < best_scale_H)
            if isfinite(best_tar_H + best_tar_L)
                sc2_ = √((best_scale_H^2 + best_scale_L^2)/2.)
                println("bisection search takes effect: scale $sc2 -> $sc2_")
                sc2 = sc2_
#                 @show best_scale_L best_scale_H
            elseif isfinite(best_tar_H)
                sc2_ = sc1 * (0.95^oneway_count)
                oneway_count += 1
                println("one-way search takes effect: scale $sc2 -> $sc2_")
                sc2 = sc2_
            elseif isfinite(best_tar_L)
                sc2_ = sc1 / (0.95^oneway_count)
                oneway_count += 1
                println("one-way search takes effect: scale $sc2 -> $sc2_")
                sc2 = sc2_
            else
                error("find_weight_scale! failed")
            end
        end
        if sc2 >= 50initialscale #防止空白words的输入，计算出sc过大渲染字体耗尽内存
            @warn "Extra large font size detected. The density $density may be unreachable."
            break
        end
        # next iter init
        tg0 = tg1
        sc0 = sc1
        sc1 = sc2
        if target_lower <= tg1 <= target_upper
            break
        end
    end
    setparameter!(wc, sc1, :scale)
    return sc1
end


text:
function categorical_lpdf(
    sample::IndexObjects.IndexVector, probabilities::Vector{Float64}
)::Vector{Float64}
    isempty(sample.v) && return Float64[]

    if maximum(sample.v) > length(probabilities)
        throw(DimensionMismatch(string(
            "maximum sample value (", maximum(sample),
            ") larger than length of probabilities (", length(probabilities), "), but ",
            "will be used to index. Values in sample: ", unique(sample)
        )))
    end

    return [log(probabilities[x]) for x in sample.v]
end

function posterior(
    node::Delayed.CategoricalIndex, probabilities::Vector{Float64}, nid::Symbol,
    trials::Vector{Trials.Trial}, config::Config
)::IndexObjects.IndexInt
    obs_below, obs_above = ApFilterTrials.ap_filter_trials(nid, trials, config)

    b_post, b_pseudocounts = Samplers.categoricalindex(
        IndexObjects.IndexVector(obs_below), probabilities, config.draws, config
    )
    _, a_pseudocounts = Samplers.categoricalindex(
        IndexObjects.IndexVector(obs_above), probabilities, config.draws, config
    )

    if isempty(b_post.v)
        throw(ArgumentError("b_post is empty"))
    end

    below_llik = categorical_lpdf(b_post, b_pseudocounts)
    above_llik = categorical_lpdf(b_post, a_pseudocounts)

    return IndexObjects.IndexInt(b_post.v[argmax(below_llik .- above_llik)])
end
function posterior(
    node::Delayed.LogNormal, mu::Float64, sigma::Float64, nid::Symbol,
    trials::Vector{Trials.Trial}, config::Config
)::Real

    obs_below, obs_above = ApFilterTrials.ap_filter_trials(nid, trials, config)

    b_post, b_weights, b_mus, b_sigmas = Samplers.lognormal(
        obs_below, mu, sigma, config.draws, config
    )
    _, a_weights, a_mus, a_sigmas = Samplers.lognormal(
        obs_above, mu, sigma, config.draws, config
    )

    if isempty(b_post)
        throw(ArgumentError("b_post is empty"))
    end

    below_llik = LogGMM.LGMM1_lpdf(b_post, b_weights, b_mus, b_sigmas)
    above_llik = LogGMM.LGMM1_lpdf(b_post, a_weights, a_mus, a_sigmas)

    return b_post[argmax(below_llik .- above_llik)]
end
function posterior(
    node::Delayed.LogNormalQuantDist, mu::Float64, sigma::Float64, q::Float64, nid::Symbol,
    trials::Vector{Trials.Trial}, config::Config
)::Real

    obs_below, obs_above = ApFilterTrials.ap_filter_trials(nid, trials, config)

    b_post, b_weights, b_mus, b_sigmas = Samplers.logquantnormal(
        Float64.(obs_below), mu, sigma, q, config.draws, config
    )
    _, a_weights, a_mus, a_sigmas = Samplers.logquantnormal(
        Float64.(obs_above), mu, sigma, q, config.draws, config
    )

    if isempty(b_post)
        throw(ArgumentError("b_post is empty"))
    end

    below_llik = LogGMM.LGMM1_lpdf(b_post, b_weights, b_mus, b_sigmas, q)
    above_llik = LogGMM.LGMM1_lpdf(b_post, a_weights, a_mus, a_sigmas, q)

    return b_post[argmax(below_llik .- above_llik)]
end
function posterior(
    node::Delayed.Normal, mu::Float64, sigma::Float64, nid::Symbol,
    trials::Vector{Trials.Trial}, config::Config
)::Real

    obs_below, obs_above = ApFilterTrials.ap_filter_trials(nid, trials, config)

    b_post, b_weights, b_mus, b_sigmas = Samplers.normal(
        Float64.(obs_below), mu, sigma, config.draws, config
    )
    _, a_weights, a_mus, a_sigmas = Samplers.normal(
        Float64.(obs_above), mu, sigma, config.draws, config
    )

    if isempty(b_post)
        throw(ArgumentError("b_post is empty"))
    end

    below_llik = GMM.GMM1_lpdf(b_post, b_weights, b_mus, b_sigmas)
    above_llik = GMM.GMM1_lpdf(b_post, a_weights, a_mus, a_sigmas)

    return b_post[argmax(below_llik .- above_llik)]
end
function posterior(
    node::Delayed.QuantNormal, mu::Float64, sigma::Float64, q::Float64, nid::Symbol,
    trials::Vector{Trials.Trial}, config::Config
)::Real

    obs_below, obs_above = ApFilterTrials.ap_filter_trials(nid, trials, config)

    b_post, b_weights, b_mus, b_sigmas = Samplers.quantnormal(
        Float64.(obs_below), mu, sigma, q, config.draws, config
    )
    _, a_weights, a_mus, a_sigmas = Samplers.quantnormal(
        Float64.(obs_above), mu, sigma, q, config.draws, config
    )

    if isempty(b_post)
        throw(ArgumentError("b_post is empty"))
    end

    below_llik = GMM.GMM1_lpdf(b_post, b_weights, b_mus, b_sigmas, q)
    above_llik = GMM.GMM1_lpdf(b_post, a_weights, a_mus, a_sigmas, q)

    return b_post[argmax(below_llik .- above_llik)]
end
function posterior(
    node::Delayed.RandIndex, upper::Int, nid::Symbol, trials::Vector{Trials.Trial},
    config::Config
)::IndexObjects.IndexInt

    obs_below, obs_above = ApFilterTrials.ap_filter_trials(nid, trials, config)

    b_post, b_probabilities = Samplers.randindex(
        IndexObjects.IndexVector(obs_below), upper, config.draws, config
    )
    _, a_probabilities = Samplers.randindex(
        IndexObjects.IndexVector(obs_above), upper, config.draws, config
    )
    if isempty(b_post.v)
        throw(ArgumentError("b_post is empty"))
    end

    below_llik = categorical_lpdf(b_post, b_probabilities)
    above_llik = categorical_lpdf(b_post, a_probabilities)

    return IndexObjects.IndexInt(b_post.v[argmax(below_llik .- above_llik)])
end
function posterior(
    node::Delayed.Uniform, low::Float64, high::Float64, nid::Symbol,
    trials::Vector{Trials.Trial}, config::Config
)::Real

    obs_below, obs_above = ApFilterTrials.ap_filter_trials(nid, trials, config)

    b_post, b_weights, b_mus, b_sigmas = Samplers.uniform(
        obs_below, low, high, config.draws, config
    )
    _, a_weights, a_mus, a_sigmas = Samplers.uniform(
        obs_above, low, high, config.draws, config
    )

    if isempty(b_post)
        throw(ArgumentError("b_post is empty"))
    end

    below_llik = GMM.GMM1_lpdf(b_post, b_weights, b_mus, b_sigmas, low, high)
    above_llik = GMM.GMM1_lpdf(b_post, a_weights, a_mus, a_sigmas, low, high)

    return b_post[argmax(below_llik .- above_llik)]
end
function posterior(
    node::Delayed.QuantUniform, low::Float64, high::Float64, q::Float64, nid::Symbol,
    trials::Vector{Trials.Trial}, config::Config
)::Real

    obs_below, obs_above = ApFilterTrials.ap_filter_trials(nid, trials, config)

    b_post, b_weights, b_mus, b_sigmas = Samplers.quantuniform(
        Float64.(obs_below), low, high, q, config.draws, config
    )
    _, a_weights, a_mus, a_sigmas = Samplers.quantuniform(
        Float64.(obs_above), low, high, q, config.draws, config
    )

    if isempty(b_post)
        throw(ArgumentError("b_post is empty"))
    end

    below_llik = GMM.GMM1_lpdf(b_post, b_weights, b_mus, b_sigmas, low, high, q)
    above_llik = GMM.GMM1_lpdf(b_post, a_weights, a_mus, a_sigmas, low, high, q)

    return b_post[argmax(below_llik .- above_llik)]
end

function posterior(
    node::Delayed.LogUniform, low::Float64, high::Float64, nid::Symbol, trials::Vector{Trials.Trial},
    config::Config
)::Real

    obs_below, obs_above = ApFilterTrials.ap_filter_trials(nid, trials, config)

    b_post, b_weights, b_mus, b_sigmas = Samplers.loguniform(
        float.(obs_below), low, high, config.draws, config
    )
    _, a_weights, a_mus, a_sigmas = Samplers.loguniform(
        float.(obs_above), low, high, config.draws, config
    )

    if isempty(b_post)
        throw(ArgumentError("b_post is empty"))
    end

    below_llik = LogGMM.LGMM1_lpdf(
        b_post, b_weights, b_mus, b_sigmas, low, high
    )
    above_llik = LogGMM.LGMM1_lpdf(
        b_post, a_weights, a_mus, a_sigmas, low, high
    )

    return b_post[argmax(below_llik .- above_llik)]
end
function posterior(
    node::Delayed.LogUniformQuantDist, low::Float64, high::Float64, q::Float64, nid::Symbol,
    trials::Vector{Trials.Trial}, config::Config
)::Real

    obs_below, obs_above = ApFilterTrials.ap_filter_trials(nid, trials, config)

    b_post, b_weights, b_mus, b_sigmas = Samplers.logquantuniform(
        float.(obs_below), low, high, q, config.draws, config
    )
    _, a_weights, a_mus, a_sigmas = Samplers.logquantuniform(
        float.(obs_above), low, high, q, config.draws, config
    )

    if isempty(b_post)
        throw(ArgumentError("b_post is empty"))
    end

    below_llik = LogGMM.LGMM1_lpdf(b_post, b_weights, b_mus, b_sigmas,low, high, q)
    above_llik = LogGMM.LGMM1_lpdf(b_post, a_weights, a_mus, a_sigmas,low, high, q)

    return b_post[argmax(below_llik .- above_llik)]
end


text:
using ForwardDiff
using NLopt
using DataFrames
using FileIO
using Base.Filesystem: joinpath
using Dates: now
using Statistics

savesettings(::Nothing, args...; kwargs...) = nothing
function savesettings(dirname::AbstractString, nsolt::AbstractNsolt{T,D}, trainingset::AbstractArray; vlevel=0, epochs, sc_options=(), du_options=(), filename="settings", kwargs...) where {T,D}
    filepath = joinpath(dirname, filename)

    txt_general = """
        Settings of $(namestring(nsolt)) Dictionary Learning:
        Element type := $T
        Decimation factor := $(decimations(nsolt))
        Polyphase order := $(orders(nsolt))
        Number of channels := $(nchannels(nsolt))

        Number of training data := $(length(trainingset))
        Epochs := $epochs

        User-defined options for Sparse Coding Stage := $sc_options
        User-defined options for Dictionary Update Stage := $du_options

        """
    txt_others = [ "Keyword $(arg.first) := $(arg.second)\n" for arg in kwargs]

    open(filepath, write=true) do io
        println(io, txt_general, txt_others...)
    end
    vlevel >= 2 && println("Settings was written in $filename.")
    nothing
end

function savesettings(dirname::AbstractString, targets::Multiscale, trainingset::AbstractArray; vlevel=0, epochs, sc_options=(), du_options=(), filename="settings", kwargs...) where {T,D}
    for idx = 1:length(targets)
        savesettings(dirname, targets.filterbanks[idx], trainingset; vlevel=vlevel, epochs=epochs, sc_options=sc_options, du_options=du_options, filename=string(filename,"_",idx))
    end
end

initializelogs(::Nothing, args...; kwargs...) = ()

function initializelogs(dirname::AbstractString, x::AbstractArray; params...)
    csvheader = [ :epoch, :timestamp, [ Symbol("data_no$idx") for idx = 1:length(x) ]...]

    cfg_sp = (   filename = "loss_sparse_coding.csv",
                        csvheader = copy(csvheader),)
    cfg_du = (   filename = "loss_dictionary_update.csv",
                        csvheader = copy(csvheader),)

    empty_dataset = fill([], length(csvheader))
    save(joinpath(dirname, cfg_sp.filename), DataFrame(empty_dataset, cfg_sp.csvheader))
    save(joinpath(dirname, cfg_du.filename), DataFrame(empty_dataset, cfg_du.csvheader))

    (cfg_sp, cfg_du)
end

savelogs(::Nothing, args...; kwargs...) = nothing

function savelogs(  dirname::AbstractString, target, epoch::Integer,
                    cfg_sp::NamedTuple, cfg_du::NamedTuple;
                    timestamp=string(now()), loss_sparse_coding,
                    loss_dictionary_update, vlevel)
    savelogs_dictionary(dirname, target)
    # savefb(joinpath(dirname, filename_nsolt), nsolt)

    open(joinpath(dirname, cfg_sp.filename), append=true) do io
        dat = DataFrame([ epoch timestamp loss_sparse_coding...], cfg_sp.csvheader)
        save(Stream(format"CSV", io), dat, header = false)
    end

    open(joinpath(dirname, cfg_du.filename), append=true) do io
        dat = DataFrame([ epoch timestamp loss_dictionary_update...], cfg_du.csvheader)
        save(Stream(format"CSV", io), dat, header = false)
    end

    repname = "report.txt"
    open(joinpath(dirname, repname), write=true) do io
        txt = """
            time = $timestamp
            #epoch = $epoch
            sum of sparse coding loss = $(sum(loss_sparse_coding))
            var. of sparse coding loss = $(var(loss_sparse_coding))
            sum of dictionary update loss $(sum(loss_dictionary_update))
            var. of dictionary update loss = $(var(loss_dictionary_update))
        """
        print(io, txt)
    end
end

function savelogs_dictionary(dirname::AbstractString, nsolt::AbstractNsolt)
    filename_nsolt = "nsolt.json"
    savefb(joinpath(dirname, filename_nsolt), nsolt)
end

function savelogs_dictionary(dirname::AbstractString, targets::Multiscale) # where {N,CB<:AbstractNsolt}
    for idx = 1:length(targets)
        filename_nsolt = joinpath(dirname, string("nsolt_$idx.json"))
        savefb(filename_nsolt, targets.filterbanks[idx])
    end
end

# savelogs(::Nothing, args...; kwargs...) = nothing
#
# function savelogs(dirname::AbstractString, nsolt::AbstractNsolt, epoch::Integer; params...)
#     filename_logs = joinpath(dirname, "log")
#     filename_nsolt = joinpath(dirname, "nsolt.json")
#
#     strparams = [ " $(prm.first) = $(prm.second)," for prm in params ]
#     strlogs = string("epoch $epoch:", strparams...)
#     open(filename_logs, append=true) do io
#         println(io, strlogs)
#     end
#     savefb(filename_nsolt, nsolt)
#     nothing
# end
#
# function savelogs(dirname::AbstractString, targets::Multiscale, epoch::Integer; params...) # where {N,CB<:AbstractNsolt}
#     for idx = 1:length(targets)
#         filename_nsolt = joinpath(dirname, string("nsolt_", idx, ".json"))
#         savefb(filename_nsolt, targets.filterbanks[idx])
#     end
#     return nothing
#     # filename_logs = joinpath(dirname, "log")
#     # filename_nsolt = joinpath(dirname, "nsolt.json")
#     #
#     # strparams = [ " $(prm.first) = $(prm.second)," for prm in params ]
#     # strlogs = string("epoch $epoch:", strparams...)
#     # open(filename_logs, append=true) do io
#     #     println(io, strlogs)
#     # end
#     # save(nsolt, filename_nsolt)
# end

namestring(nsolt::Rnsolt) = namestring(nsolt, "Real NSOLT")
namestring(nsolt::Cnsolt) = namestring(nsolt, "Complex NSOLT")
namestring(nsolt::AbstractNsolt{T,D}, strnsolt::AbstractString) where {T,D} = "$D-dimensional $(ifelse(istype1(nsolt), "Type-I", "Type-II")) $strnsolt"

max_stars_repo_name: nixir/MDCDL

max_issues_repo_name: nixir/MDCDL

max_forks_repo_name: nixir/MDCDL


text:
export Model, SimulationData, getVariables, show

import Base.show

global t,y,p

function vectorise_model(odes::Dict, pars::Dict, alg::Dict, init::Dict, aux::Dict)
  v_odes = [v for (k,v) in odes]
  var_names = AbstractString[]
  y0 = Float64[]
  par_names = AbstractString[]
  par_values = Float64[]
  v_aux = [v for (k,v) in aux]
  a_names = [k for (k,v) in aux]

  #Get parameter list
  for (n,p) in enumerate(keys(pars))
    par_names = [par_names; p]
    par_values = [par_values; pars[p]]
  end

  #Vectorise odes
  for (i,k) in enumerate(keys(odes))
    var_names = [var_names; k]
    #Substitute algebraics
    for (n,p) in enumerate(keys(alg))
      v_odes[i] = replace(v_odes[i], Regex("\\b" * p * "\\b"), "($(alg[p]))")
    end
    #Substitute parameters
    for (n,p) in enumerate(keys(pars))
      v_odes[i] = replace(v_odes[i], Regex("\\b" * p * "\\b"), "p[$n]")
    end
    #Substitute variable names
    for (n,p) in enumerate(keys(odes))
      v_odes[i] = replace(v_odes[i], Regex("\\b" * p * "\\b"), "y[$n]")
    end
    # Add initial
    y0 = [y0; init[k]]
  end

  #Vectorise auxs
  for (i,k) in enumerate(a_names)
    #Substitute algebraics
    for (n,p) in enumerate(keys(alg))
      v_aux[i] = replace(v_aux[i], Regex("\\b" * p * "\\b"), "($(alg[p]))")
    end
    #Substitute parameters
    for (n,p) in enumerate(keys(pars))
      v_aux[i] = replace(v_aux[i], Regex("\\b" * p * "\\b"), "p[$n]")
    end
    #Substitute variable names
    for (n,p) in enumerate(keys(odes))
      v_aux[i] = replace(v_aux[i], Regex("\\b" * p * "\\b"), "y[$n]")
    end
  end

  # println("Vectorisation of model")
  # println(v_odes)
  # println(v_aux)

  v_aux = [eval(parse("a_$i" * "(t,y,p) = " * v )) for (i,v) in enumerate(v_aux)]
  A(t,y,p) = Float64[ai(t,y,p) for ai in v_aux]

  v_odes = [eval(parse("y_$i" * "(t,y,p) = " * v )) for (i,v) in enumerate(v_odes)]
  F(t,y,p) = Float64[yi(t,y,p) for yi in v_odes]
  return(F, var_names, A, a_names, y0, par_names, par_values)
end

"""
Custom type Model, used for specifying dynamical systems model to be simulated using XPP.
Minimal requirement: Dict of odes, dict of initial conditions, dict of parameters, model name.
Auxilliary equations or algebraic equations are both by default.
Provides interface for reading from an ode file, writing the model to an ode file.
Furthermore the model, along with simulations can be stored in, and loaded from a json file

Instantiation:

    ModelName = Model(odeDict, initialConditionsDict, parameterDict; modelName = "myName", ...)

"""
type Model
    odes::Dict #Dict that stores the odes
    init::Dict #Dict that stores the initial conditions
    pars::Dict #Dict that stores parameters
    name::AbstractString #Model name, used for writing ode, json
    aux::Dict #Auxilliary eqn
    alg::Dict #Algebraic eqn.
    spec::Dict #settings
    vars::Array{Any,1} #Variables
    sims::Dict #Dict that stores simulations
    F::Function
    y_names::Array{AbstractString,1}
    A::Function
    a_names::Array{AbstractString,1}
    y0::Array{Float64,1}
    p_names::Array{AbstractString,1}
    p::Array{Float64,1}
    originalState::Dict #Store original state of model
    auto_specs::Dict#Store Parameters required for running AUTO
end
vectorise_model(M::Model) = vectorise_model(M.odes, M.pars, M.alg, M.init)
#Instantiate model from minimal set of definitions (odes, initials, parameters, name)
function Model(odes::Dict, init::Dict, pars::Dict; name = "myModel", aux = Dict(),
               alg = Dict(), spec = Dict(), vars = [], sims = Dict(),
               originalState = Dict(), auto_specs = auto_default_specs)

  F, y_names, A, a_names, y0, p_names, p = vectorise_model(odes, pars, alg, init, aux)
  return Model(odes, init, pars, name, aux, alg, spec, vars, sims, F, y_names, A, a_names,y0, p_names, p, originalState, auto_specs)
end

"""
Simple function to  obtain a list of dynamical and auxilliary variables, which determines the handling of simulation data
"""
function getVariables(M::Model)
    v = ["t"]
    append!(v,[k for k in keys(M.odes)])
    append!(v,[k for k in keys(M.aux)])
    return(v)
end

function show(io::IO, M::Model)
    println(M.name)
    println("-"^60)
    println("ODES:")
    for var in keys(M.odes)
        println("\t$var = ", M.odes[var])
    end
    if length(M.alg) > 0
        println("-"^60)
        println("ALGEBRAIC EQUATIONS:")
        for alg in keys(M.alg)
            println("\t$alg = ", M.alg[alg])
        end
    end
    if length(M.aux) > 0
        println("-"^60)
        println("AUXILLIARY VARIABLES:")
        for aux in keys(M.aux)
            println("\t$aux = ", M.aux[aux])
        end
    end
    println("-"^60)
    println("INITIALS:")
    for var in keys(M.init)
        println("\t$var:\t", M.init[var])
    end
    println("-"^60)
    println("PARAMETERS:")
    for par in keys(M.pars)
        println("\t$par:", alignSpace(par, 15), M.pars[par])
    end
    println("-"^60)
    println("SETTINGS:")
    for spec in keys(M.spec)
        println("\t$spec:\t", M.spec[spec])
    end
    if length(M.sims) > 0
        println("-"^60)
        println("SIMULATIONS:")
        for sim in keys(M.sims)
            println("\t$sim")
        end
    end
    println("="^60)
end

"""
Custom type SimulationData serves as a datastructure to store data from timecourse simulations along with the initial conditions and the parameterset used in the simulation

Instantiation:

    D = SimulationData(initialConditionsDict, parameterDict, dataDict)
"""
type SimulationData
    N::AbstractString
    I::Dict
    P::Dict
    D::Dict
end
function SimulationData(M::Model, name)
    N = name
    I = deepcopy(M.init)
    P = deepcopy(M.pars)
    D = deepcopy(Dict([v => Float64[] for v in M.vars]))
    return(SimulationData(N, I, P, D))
end

function show(io::IO, S::SimulationData)
    println(S.N)
    println("-"^60)
    println("INITIALS:")
    for var in keys(S.I)
        println("\t$var:\t", S.I[var])
    end
    println("-"^60)
    println("PARAMETERS:")
    for par in keys(S.P)
        println("\t$par:", alignSpace(par, 15), S.P[par])
    end
    println("-"^60)
    println("DATA:")
    println("\tt_max:\t", S.D["t"][end])
    println("="^60)
end

function alignSpace(myString::AbstractString, maxSpace)
    n = 40 - length(myString)
    return(" "^n)
end

max_stars_repo_name: novakgroupoxford/XPPjl

max_issues_repo_name: novakgroupoxford/XPPjl

max_forks_repo_name: novakgroupoxford/XPPjl


text:
pages = [
        "DiffEqSensitivity.jl: Automatic Differentiation and Adjoints for (Differential) Equation Solvers" => "index.md",
        "Tutorials" => Any[
            "Differentiating Ordinary Differential Equations (ODE) Tutorials" => Any[
                "ad_examples/differentiating_ode.md",
                "ad_examples/direct_sensitivity.md",
                "ad_examples/adjoint_continuous_functional.md",
                "ad_examples/chaotic_ode.md",
            ],
            "Fitting Ordinary Differential Equation (ODE) Tutorials" => Any[
                "ode_fitting/optimization_ode.md",
                "ode_fitting/stiff_ode_fit.md",
                "ode_fitting/exogenous_input.md",
                "ode_fitting/data_parallel.md",
                "ode_fitting/prediction_error_method.md",
                "ode_fitting/second_order_adjoints.md",
                "ode_fitting/second_order_neural.md",
            ],
            "Training Techniques and Tips" => Any[
                "training_tips/local_minima.md",
                "training_tips/divergence.md",
                "training_tips/multiple_nn.md",
            ],
            "Neural Ordinary Differential Equation (Neural ODE) Tutorials" => Any[
                "neural_ode/neural_ode_galacticoptim.md",
                "neural_ode/neural_ode_flux.md",
                "neural_ode/mnist_neural_ode.md",
                "neural_ode/mnist_conv_neural_ode.md",
                "neural_ode/GPUs.md",
                "neural_ode/neural_gde.md",
                "neural_ode/minibatch.md",
            ],
            "Stochastic Differential Equation (SDE) Tutorials" => Any[
                "sde_fitting/optimization_sde.md",
                "sde_fitting/neural_sde.md",
            ],
            "Delay Differential Equation (DDE) Tutorials" => Any[
                "dde_fitting/delay_diffeq.md",
            ],
            "Differential-Algebraic Equation (DAE) Tutorials" => Any[
                "dae_fitting/physical_constraints.md",
            ],
            "Partial Differential Equation (PDE) Tutorials" => Any[
                "pde_fitting/pde_constrained.md",
            ],
            "Hybrid and Jump Equation Tutorials" => Any[
                "hybrid_jump_fitting/hybrid_diffeq.md",
                "hybrid_jump_fitting/bouncing_ball.md",
            ],
            "Bayesian Estimation Tutorials" => Any[
                "bayesian/turing_bayesian.md",
                "bayesian/BayesianNODE_NUTS.md",
                "bayesian/BayesianNODE_SGLD.md",
            ],
            "Optimal and Model Predictive Control Tutorials" => Any[
                "optimal_control/optimal_control.md",
                "optimal_control/feedback_control.md",
                "optimal_control/SDE_control.md",
            ],
        ],
        "Manual and APIs" => Any[
            "manual/differential_equation_sensitivities.md",
            "manual/nonlinear_solve_sensitivities.md",
            "manual/direct_forward_sensitivity.md",
            "manual/direct_adjoint_sensitivities.md",
        ],
        "Benchmarks" => "Benchmark.md",
        "Sensitivity Math Details" => "sensitivity_math.md",
    ]


text:
export run_pf, run_ac_pf, run_dc_pf

""
function run_ac_pf(file, solver; kwargs...)
    return run_pf(file, ACPPowerModel, solver; kwargs...)
end

""
function run_dc_pf(file, solver; kwargs...)
    return run_pf(file, DCPPowerModel, solver; kwargs...)
end

""
function run_pf(file, model_constructor, solver; kwargs...)
    return run_generic_model(file, model_constructor, solver, post_pf; kwargs...)
end

""
function post_pf(pm::GenericPowerModel)
    variable_voltage(pm, bounded = false)
    variable_generation(pm, bounded = false)
    variable_branch_flow(pm, bounded = false)
    variable_dcline_flow(pm, bounded = false)

    constraint_voltage(pm)

    for (i,bus) in ref(pm, :ref_buses)
        @assert bus["bus_type"] == 3
        constraint_theta_ref(pm, i)
        constraint_voltage_magnitude_setpoint(pm, i)
    end

    for (i,bus) in ref(pm, :bus)
        constraint_kcl_shunt(pm, i)

        # PV Bus Constraints
        if length(ref(pm, :bus_gens, i)) > 0 && !(i in ids(pm,:ref_buses))
            # this assumes inactive generators are filtered out of bus_gens
            @assert bus["bus_type"] == 2

            constraint_voltage_magnitude_setpoint(pm, i)
            for j in ref(pm, :bus_gens, i)
                constraint_active_gen_setpoint(pm, j)
            end
        end
    end

    for i in ids(pm, :branch)
        constraint_ohms_yt_from(pm, i)
        constraint_ohms_yt_to(pm, i)
    end

    for (i,dcline) in ref(pm, :dcline)
        #constraint_dcline(pm, i) not needed, active power flow fully defined by dc line setpoints
        constraint_active_dcline_setpoint(pm, i)

        f_bus = ref(pm, :bus)[dcline["f_bus"]]
        if f_bus["bus_type"] == 1
            constraint_voltage_magnitude_setpoint(pm, f_bus["index"])
        end

        t_bus = ref(pm, :bus)[dcline["t_bus"]]
        if t_bus["bus_type"] == 1
            constraint_voltage_magnitude_setpoint(pm, t_bus["index"])
        end
    end
end


text:
module ParticleSwarmOptimization

include("pso.jl"); export pso, single_iter, search!
include("Particle.jl"); export AbsParticle, Particle, NNParticle, fitness, init_particles, update!, Bcast!, copybest!, copygbest!
include("Problem.jl"); export Data, Single, MiniBatch, Problem, RegularProblem, NNProblem

end # module


text:
function readmesh(filename, mode)

#fileID = fopen(filename,'r');
if mode==0 # binary
    tmp = reinterpret(Float64,read(filename));
    nd = Int(tmp[1]);
    np = Int(tmp[2]);
    nve = Int(tmp[3]);
    ne = Int(tmp[4]);
    p = reshape(tmp[5:(4+nd*np)], nd, np);
    t = reshape(tmp[(5+nd*np):(4+nd*np+nve*ne)], nve, ne);
    t = Int.(t);
else # text
    tmp = readdlm(filename);
    nd = Int(tmp[1,1]);
    np = Int(tmp[1,2]);
    nve = Int(tmp[1,3]);
    ne = Int(tmp[1,4]);
    p = Float64.(reshape(tmp[2:np+1,1:nd], np, nd));
    p = p';
    t = Int.(reshape(tmp[np+2:end,1:nve], ne, nve));
    t = t';
end

return p,t

end

max_stars_repo_name: glwagner/Exasim

max_issues_repo_name: glwagner/Exasim

max_forks_repo_name: glwagner/Exasim


text:
import AbstractPlotting:plot!

"""
    errorbary(x, y, Δy)

Plots points defined by `x` and `y`,
and vertical error bars (along the `y`-axis)
on those points, as defined by `Δy`.
"""
@recipe(ErrorBarY, x, y, Δy) do scene
    Theme(; default_theme(scene, LineSegments)..., whiskerwidth = 0)
end

"""
    errorbarx(x, y, Δx)

Plots points defined by `x` and `y`,
and horizontal error bars (along the `x`-axis)
on those points, as defined by `Δx`.
"""
@recipe(ErrorBarX, x, y, Δx) do scene
    Theme(; default_theme(scene, LineSegments)..., whiskerwidth = 0)
end

"""
    errorbar(x, y, Δx, Δy)

Plots points defined by `x` and `y`,
and horizontal and vertical error bars
(along the `x` and `y`-axes)
on those points, as defined by `Δx` and `Δy`.
"""
@recipe(ErrorBar, x, y, Δx, Δy) do scene
    Theme(;
        default_theme(scene, LineSegments)...,
        whiskerwidth = 0,
        xcolor = automatic,
        xwhiskerwidth = automatic,
        ycolor = automatic,
        ywhiskerwidth = automatic,
    )
end

function plot!(plot::ErrorBarY)
    t = copy(Theme(plot))
    ww = pop!(t, :whiskerwidth)
    segments = lift(plot[1], plot[2], plot[3], ww) do x,y,Δy,ww
        bar = Pair.(Point2f0.(x, y .- Δy), Point2f0.(x, y .+ Δy))
        segments = [bar;]
        if ww != 0
            hww = ww ./ 2
            lw = Pair.(
                first.(bar) .- Point2f0.(hww, 0),
                first.(bar) .+ Point2f0.(hww, 0),
            )
            uw = Pair.(last.(bar) .- Point2f0.(hww, 0), last.(bar) .+ Point2f0.(hww, 0))
            append!(segments, [lw; uw])
        end
        return segments
    end
    linesegments!(plot, t, segments)
end

function plot!(plot::ErrorBarX)
    t = copy(Theme(plot))
    ww = pop!(t, :whiskerwidth)
    segments = lift(plot[1], plot[2], plot[3], ww) do x,y,Δx,ww
        bar = Pair.(Point2f0.(x .- Δx, y), Point2f0.(x .+ Δx, y))
        segments = [bar;]
        if ww != 0
            hww = ww ./ 2
            lw = Pair.(
                first.(bar) .- Point2f0.(0, hww),
                first.(bar) .+ Point2f0.(0, hww),
            )
            uw = Pair.(last.(bar) .- Point2f0.(0, hww), last.(bar) .+ Point2f0.(0, hww))
            append!(segments, [lw; uw])
        end
        return segments
    end
    linesegments!(plot, t, segments)
end

function plot!(plot::ErrorBar)
    x,y,Δx,Δy = (plot[1], plot[2], plot[3], plot[4])

    t = copy(Theme(plot))
    xcolor, ycolor = pop!.(Ref(t), (:xcolor, :ycolor))
    xww, yww = pop!.(Ref(t), (:xwhiskerwidth, :ywhiskerwidth))
    xcolor = lift((xc,c) -> xc === automatic ? c : xc, xcolor, plot[:color])
    ycolor = lift((yc,c) -> yc === automatic ? c : yc, ycolor, plot[:color])
    xww = lift((xww,ww) -> xww === automatic ? ww : xww, xww, plot[:whiskerwidth])
    yww = lift((yww,ww) -> yww === automatic ? ww : yww, yww, plot[:whiskerwidth])

    #x-error
    tx = merge(Theme(color = xcolor, whiskerwidth = xww), t)
    errorbarx!(plot, tx, x, y, Δx)
    #y-error
    ty = merge(Theme(color = ycolor, whiskerwidth = yww), t)
    errorbary!(plot, ty, x, y, Δy)
    plot
end

max_stars_repo_name: piever/StatMakie

max_issues_repo_name: piever/StatMakie

max_forks_repo_name: piever/StatMakie


text:
using JuMP, EAGO

                     m = Model()

                     EAGO.register_eago_operators!(m)

                     @variable(m, -1 <= x[i=1:2] <= 1)

                     @variable(m, -7.9284408379108005 <= q <= 14.377266175441108)

                     add_NL_constraint(m, :((0.4343485145630286 + -0.5735104656090533*(-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))*(1 + erf((-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))/sqrt(2)))/2 + -0.40833038450807946*(0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))*(1 + erf((0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))/sqrt(2)))/2 + 0.09714914815406805*(-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))*(1 + erf((-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))/sqrt(2)))/2 + -0.19623354791767778*(0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))*(1 + erf((0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))/sqrt(2)))/2 + -0.3237276355524821*(0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))*(1 + erf((0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))/sqrt(2)))/2)*(1 + erf((0.4343485145630286 + -0.5735104656090533*(-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))*(1 + erf((-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))/sqrt(2)))/2 + -0.40833038450807946*(0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))*(1 + erf((0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))/sqrt(2)))/2 + 0.09714914815406805*(-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))*(1 + erf((-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))/sqrt(2)))/2 + -0.19623354791767778*(0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))*(1 + erf((0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))/sqrt(2)))/2 + -0.3237276355524821*(0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))*(1 + erf((0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))/sqrt(2)))/2)/sqrt(2)))/2 + (-0.11905941659917563 + 0.17224590981590104*(-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))*(1 + erf((-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))/sqrt(2)))/2 + 0.8406566605626429*(0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))*(1 + erf((0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))/sqrt(2)))/2 + 0.24719777641241691*(-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))*(1 + erf((-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))/sqrt(2)))/2 + -0.24308200319021767*(0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))*(1 + erf((0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))/sqrt(2)))/2 + -0.39557038452022475*(0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))*(1 + erf((0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))/sqrt(2)))/2)*(1 + erf((-0.11905941659917563 + 0.17224590981590104*(-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))*(1 + erf((-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))/sqrt(2)))/2 + 0.8406566605626429*(0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))*(1 + erf((0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))/sqrt(2)))/2 + 0.24719777641241691*(-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))*(1 + erf((-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))/sqrt(2)))/2 + -0.24308200319021767*(0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))*(1 + erf((0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))/sqrt(2)))/2 + -0.39557038452022475*(0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))*(1 + erf((0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))/sqrt(2)))/2)/sqrt(2)))/2 + (0.967203829156619 + 0.3785230261408685*(-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))*(1 + erf((-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))/sqrt(2)))/2 + -0.23118999327456224*(0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))*(1 + erf((0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))/sqrt(2)))/2 + -0.5197073892915105*(-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))*(1 + erf((-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))/sqrt(2)))/2 + 0.6005003791404913*(0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))*(1 + erf((0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))/sqrt(2)))/2 + 0.15463985115916623*(0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))*(1 + erf((0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))/sqrt(2)))/2)*(1 + erf((0.967203829156619 + 0.3785230261408685*(-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))*(1 + erf((-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))/sqrt(2)))/2 + -0.23118999327456224*(0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))*(1 + erf((0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))/sqrt(2)))/2 + -0.5197073892915105*(-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))*(1 + erf((-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))/sqrt(2)))/2 + 0.6005003791404913*(0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))*(1 + erf((0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))/sqrt(2)))/2 + 0.15463985115916623*(0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))*(1 + erf((0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))/sqrt(2)))/2)/sqrt(2)))/2 + (-0.18340968019959902 + 0.01980109053282808*(-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))*(1 + erf((-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))/sqrt(2)))/2 + 0.8767310690037822*(0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))*(1 + erf((0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))/sqrt(2)))/2 + 0.42243485881005904*(-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))*(1 + erf((-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))/sqrt(2)))/2 + -0.1694649191201152*(0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))*(1 + erf((0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))/sqrt(2)))/2 + 0.5278959282338329*(0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))*(1 + erf((0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))/sqrt(2)))/2)*(1 + erf((-0.18340968019959902 + 0.01980109053282808*(-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))*(1 + erf((-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))/sqrt(2)))/2 + 0.8767310690037822*(0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))*(1 + erf((0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))/sqrt(2)))/2 + 0.42243485881005904*(-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))*(1 + erf((-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))/sqrt(2)))/2 + -0.1694649191201152*(0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))*(1 + erf((0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))/sqrt(2)))/2 + 0.5278959282338329*(0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))*(1 + erf((0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))/sqrt(2)))/2)/sqrt(2)))/2 + (0.7043455967116397 + -0.48930630508951234*(-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))*(1 + erf((-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))/sqrt(2)))/2 + 0.7375930151357304*(0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))*(1 + erf((0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))/sqrt(2)))/2 + -0.9188673755139103*(-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))*(1 + erf((-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))/sqrt(2)))/2 + 0.5801272291202126*(0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))*(1 + erf((0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))/sqrt(2)))/2 + 0.06743755305487698*(0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))*(1 + erf((0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))/sqrt(2)))/2)*(1 + erf((0.7043455967116397 + -0.48930630508951234*(-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))*(1 + erf((-0.47832195115882303 + 0.6358617391786257*$(x[1]) + -0.4037373919488174*$(x[2]))/sqrt(2)))/2 + 0.7375930151357304*(0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))*(1 + erf((0.4113265195541662 + -0.7994001067331897*$(x[1]) + -0.3401124060181533*$(x[2]))/sqrt(2)))/2 + -0.9188673755139103*(-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))*(1 + erf((-0.3249145933093094 + 0.9313960721440679*$(x[1]) + 0.2643917347767659*$(x[2]))/sqrt(2)))/2 + 0.5801272291202126*(0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))*(1 + erf((0.34085895078435247 + -0.33650259644885194*$(x[1]) + -0.9436140496760688*$(x[2]))/sqrt(2)))/2 + 0.06743755305487698*(0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))*(1 + erf((0.8342164127508305 + -0.6721074785776127*$(x[1]) + 0.009028597341863787*$(x[2]))/sqrt(2)))/2)/sqrt(2)))/2 - $q <= 0.0))

                     @objective(m, Min, q)

                     return m

max_stars_repo_name: PSORLab/RSActivationFunctions

max_issues_repo_name: PSORLab/RSActivationFunctions

max_forks_repo_name: PSORLab/RSActivationFunctions


text:
function test_backend(run::Function, name::String; check_object::Bool = true)
    function check(code::String, expected, expected_output::String = "")
        c = IOCapture.capture() do
            run(code)
        end

        if check_object
            test_object(c.value, expected)
        else
            @test c.value == expected
        end

        @test c.output == expected_output
    end

    @testset "Empty program" begin
        @test isnothing(run(""))
    end

    @testset "Integer expression" begin
        for (code, expected) in [
            ("5", 5),
            ("10", 10),
            ("-5", -5),
            ("-10", -10),
            ("5 + 5 + 5 + 5 - 10", 10),
            ("2 * 2 * 2 * 2 * 2", 32),
            ("-50 + 100 + -50", 0),
            ("5 * 2 + 10", 20),
            ("5 + 2 * 10", 25),
            ("20 + 2 * -10", 0),
            ("50 / 2 * 2 + 10", 60),
            ("2 * (5 + 10)", 30),
            ("3 * 3 * 3 + 10", 37),
            ("3 * (3 * 3) + 10", 37),
            ("(5 + 10 * 2 + 15 / 3) * 2 + -10", 50),
        ]
            check(code, expected)
        end
    end

    @testset "Boolean expression" begin
        for (code, expected) in [
            ("false", false),
            ("true", true),
            ("1 < 2", true),
            ("1 > 2", false),
            ("1 < 1", false),
            ("1 > 1", false),
            ("1 == 1", true),
            ("1 != 1", false),
            ("1 == 2", false),
            ("1 != 2", true),
            ("true == true", true),
            ("false == false", true),
            ("true == false", false),
            ("true != false", true),
            ("false != true", true),
            ("(1 < 2) == true", true),
            ("(1 < 2) == false", false),
            ("(1 > 2) == true", false),
            ("(1 > 2) == false", true),
            ("\"a\" == \"a\"", true),
            ("\"a\" != \"a\"", false),
            ("\"a\" == \"b\"", false),
            ("\"a\" != \"b\"", true),
        ]
            check(code, expected)
        end
    end

    @testset "String expression" begin
        for (code, expected) in [
            ("\"Hello World!\"", "Hello World!"),
            ("\"newline\n\n\t\"", "newline\n\n\t"),
            (""""Hello" + " " + "World!\"""", "Hello World!"),
        ]
            check(code, expected)
        end
    end

    @testset "Array" begin
        @testset "Literal" begin
            for (code, expected) in
                [("[]", []), ("[1, 2, 3]", [1, 2, 3]), ("[1, 2 * 2, 3 + 3]", [1, 4, 6])]
                check(code, expected)
            end
        end

        @testset "Index" begin
            for (code, expected) in [
                ("[1, 2, 3][0]", 1),
                ("[1, 2, 3][1]", 2),
                ("[1, 2, 3][2]", 3),
                ("let i = 0; [1][i]", 1),
                ("[1, 2, 3][1 + 1]", 3),
                ("let myArray = [1, 2, 3]; myArray[2];", 3),
                ("let myArray = [1, 2, 3]; myArray[0] + myArray[1] + myArray[2]", 6),
                ("let myArray = [1, 2, 3]; let i = myArray[0]; myArray[i]", 2),
                ("[1, 2, 3][3]", nothing),
                ("[1, 2, 3][-1]", nothing),
            ]
                check(code, expected)
            end
        end
    end

    @testset "Hash" begin
        @testset "Literal" begin
            for (input, expected) in [
                ("""{"foo": "bar", true: false}""", Dict("foo" => "bar", true => false)),
                ("{1: 2, 1: 3, 1: 4}", Dict(1 => 4)),
                (
                    "{null: [], [2]: null, {3: 5}: {\"1\": 2}}",
                    Dict(nothing => [], [2] => nothing, Dict(3 => 5) => Dict("1" => 2)),
                ),
            ]
                check(input, expected)
            end
        end

        @testset "Index" begin
            for (code, expected) in [
                ("{\"foo\": 5}[\"foo\"]", 5),
                ("{\"foo\": 5}[\"bar\"]", nothing),
                ("let key = \"foo\"; {\"foo\": 5}[key]", 5),
                ("{}[\"foo\"]", nothing),
                ("{5: 5}[5]", 5),
                ("{true: 5}[true]", 5),
                ("{false: 5}[false]", 5),
                ("let a = [1, 2]; {a: 2}[[1, 2]]", 2),
                ("let a = {1: 2, 3: 4}; {a: 2}[{3: 4, 1: 2}]", 2),
            ]
                check(code, expected)
            end

            @testset "Maybe broken" begin
                for (code, expected) in [
                    ("let a = {1: 2, true: 3}; a[1] + a[true]", 5), # Julia backend fails this test since in Julia `true == 1` holds
                ]
                    if name == "julia"
                        @test_broken run(code) == expected
                    else
                        check(code, expected)
                    end
                end
            end
        end
    end

    @testset "Bang operator" begin
        for (code, expected) in [
            ("!true", false),
            ("!false", true),
            ("!5", false),
            ("!!true", true),
            ("!!false", false),
            ("!!5", true),
            ("!\"hello\"", false),
            ("!null", true),
            ("![1, 2, 3]", false),
            ("!{1: 2}", false),
            ("!(fn(x) {x})", false),
        ]
            check(code, expected)
        end
    end

    @testset "If-else expression" begin
        for (code, expected) in [
            ("if (true) { 10 }", 10),
            ("if (false) { 10 }", nothing),
            ("if (null) { 2 } else { 3 }", 3),
            ("if (1) { 10 }", 10),
            ("if (1 < 2) { 10 }", 10),
            ("if (1 > 2) { 10 }", nothing),
            ("if (1 > 2) { 10 } else { 20 }", 20),
            ("if (1 < 2) { 10 } else { 20 }", 10),
        ]
            check(code, expected)
        end
    end

    @testset "While statement" begin
        @testset "Plain" begin
            for (code, expected) in [
                ("let x = 1; while (false) { x = x + 1; } x", 1),
                ("let x = 1; let y = 1; while (y > 0) { y = y - 1; x = x + 1; } x", 2),
            ]
                check(code, expected)
            end
        end

        @testset "Nested" begin
            for (code, expected) in [(
                """
                let a = 6;
                let b = a;
                let x = 1;
                while (x > 0) {
                    x = x - 1;
                    a = 5;
                    b = b + a;
                    let c = 8;
                    c = c / 2;
                    b = b + c;
                    let y = 1;
                    while (y > 0) {
                        y = y - 1;
                        a = a + 3;
                        b = b + a;
                    }
                }
                b = b + a;
                """,
                31,
            )]
                check(code, expected)
            end
        end

        @testset "Inside functions" begin
            for (code, expected) in [
                (
                    """
                    let f = fn(x) {
                        while (x > 0) {
                            if (x == 3) {
                                return 4;
                            }
                            x = x - 1;
                        }
                    }
                    f(4);
                    """,
                    4,
                ),
                (
                    """
                    let f = fn(x) {
                        while (x > 0) {
                            if (x == 3) {
                                return 4;
                            }
                            x = x - 1;
                        }
                    }
                    f(2);
                    """,
                    nothing,
                ),
                (
                    """
                    let x = 5;
                    let y = 0;
                    while (x > 0) {
                        x = x - 1;
                        let z = 5;
                        let f = fn() {
                            let w = 1;
                            while (z > 0) {
                                w = w * 2;
                                y = y + z * w;
                                z = z - 1;
                                f();
                            }
                        }
                        f();
                    }
                    y;
                    """,
                    150,
                ),
            ]
                check(code, expected)
            end
        end
    end

    @testset "Break statement" begin
        for (code, expected) in [(
            """
            let a = 2;
            let b = 0;
            while (a > 0) {
                b = b + a;
                if (a == 2) {
                    break;
                }
                a = a - 1;
            }
            b;
            """,
            2,
        )]
            check(code, expected)
        end
    end

    @testset "Continue statement" begin
        for (code, expected) in [(
            """
            let a = 4;
            let b = 0;
            while (a > 0) {
                a = a - 1;
                if (a == 2) {
                    continue;
                }
                b = b + a;
            }
            b;
            """,
            4,
        )]
            check(code, expected)
        end
    end

    @testset "Return statement" begin
        for (code, expected) in [
            ("return 10;", 10),
            ("return 10; 9;", 10),
            ("return 2 * 5; 9;", 10),
            ("9; return 2 * 5; 9;", 10),
            (
                """
                if (10 > 1) {
                    if (10 > 1) {
                        return 10;
                    }

                    return 1;
                }
                """,
                10,
            ),
            ("while (true) { return 10; }", 10),
        ]
            check(code, expected)
        end
    end

    @testset "Let statement" begin
        @testset "Plain" begin
            for (code, expected) in [
                ("let a = 5; a;", 5),
                ("let a = 5 * 5; a;", 25),
                ("let a = 5; let b = a; b;", 5),
                ("let a = 5; let b = a; let c = a + b + 5; c;", 15),
                ("let a = 5; a = a + 1; a;", 6),
            ]
                check(code, expected)
            end
        end

        @testset "Reassign" begin
            for (code, expected) in [("let a = 5; a = a + 1; a;", 6)]
                check(code, expected)
            end
        end

        @testset "Redefine" begin
            for (code, expected) in [(
                """
                let x = 5;
                let y = 1;
                let z = 0;
                while (y > 0) {
                    z = z + x;
                    let x = 9;
                    z = z + x;
                    y = y - 1;
                }
                z = z + x;
                z;
                """,
                19,
            )]
                if name == "julia"
                    @test_broken run(code) == expected
                else
                    check(code, expected)
                end
            end
        end
    end

    @testset "Function" begin
        if name == "evaluator"
            @testset "Definition" begin
                code = "fn(x) { x + 2; };"
                result = run(code)

                @test isa(result, m.FunctionObj)
                @test string(result.parameters[1]) == "x"
                @test string(result.body) == "(x + 2)"
            end
        end

        @testset "Application" begin
            for (code, expected) in [
                ("let identity = fn(x) { x; }; identity(5);", 5),
                ("let identity = fn(x) { return x; }; identity(5);", 5),
                ("let double = fn(x) { x * 2; }; double(5);", 10),
                ("let add = fn(x, y) { x + y; }; add(5, 5);", 10),
                ("let add = fn(x, y) { x + y; }; add(5 + 5, add(5, 5));", 20),
                ("fn(x) { x; }(5)", 5),
            ]
                check(code, expected)
            end
        end

        @testset "Closure" begin
            for (code, expected) in [(
                """
               let newAdder = fn(x) {
                 fn(y) { x + y };
               }

               let addTwo = newAdder(2);
               addTwo(2);
               """,
                4,
            ), (
                """
                let a = 2;
                let ans = [];

                let g = fn() {
                    let b = 2;
                    let f = fn() {
                        b = b - 1;
                        return b;
                    }
                    return f;
                }

                let f = g();

                ans = push(ans, f());
                ans = push(ans, f());

                let ff = g();

                ans = push(ans, ff());
                ans = push(ans, ff());

                ans;
                """,
                [1, 0, 1, 0],
            )]
                check(code, expected)
            end
        end

        @testset "Recursion" begin
            for (code, expected) in [(
                """
                let fibonacci = fn(x) {
                if (x == 0) {
                    0
                } else {
                    if (x == 1) {
                        return 1;
                    } else {
                        fibonacci(x - 1) + fibonacci(x - 2);
                    }
                    }
                };

                fibonacci(10);
                """,
                55,
            )]
                check(code, expected)
            end
        end
    end

    @testset "Built-in functions" begin
        @testset "len" begin
            for (code, expected) in [
                ("len(\"\")", 0),
                ("len(\"four\")", 4),
                ("len([1, 2, 3])", 3),
                ("len([])", 0),
                ("len([[1, 2, 3], [4, 5, 6]])", 2),
                ("len({\"a\": 1, \"b\": 2})", 2),
                ("len({})", 0),
            ]
                check(code, expected)
            end
        end

        @testset "first" begin
            for (code, expected) in [
                ("first([1, 2, 3])", 1),
                ("first([])", nothing),
                ("first(\"hello\")", "h"),
                ("first(\"\")", nothing),
            ]
                check(code, expected)
            end
        end

        @testset "last" begin
            for (code, expected) in [
                ("last([1, 2, 3])", 3),
                ("last([])", nothing),
                ("last(\"hello\")", "o"),
                ("last(\"\")", nothing),
            ]
                check(code, expected)
            end
        end

        @testset "rest" begin
            for (code, expected) in [
                ("rest([1, 2, 3])", [2, 3]),
                ("rest([1])", []),
                ("rest([])", nothing),
                ("rest(\"hello\")", "ello"),
                ("rest(\"h\")", ""),
                ("rest(\"\")", nothing),
            ]
                check(code, expected)
            end
        end

        @testset "push" begin
            for (code, expected) in [("push([], 2)[0]", 2), ("push({2: 3}, 4, 5)[4]", 5)]
                check(code, expected)
            end
        end

        @testset "type" begin
            for (code, expected) in [
                ("type(false)", m.BOOLEAN_OBJ),
                ("type(true)", m.BOOLEAN_OBJ),
                ("type(null)", m.NULL_OBJ),
                ("type(0)", m.INTEGER_OBJ),
                ("type(fn (x) { x })", name == "vm" ? m.CLOSURE_OBJ : m.FUNCTION_OBJ),
                ("type(\"hello\")", m.STRING_OBJ),
                ("type([1, 2])", m.ARRAY_OBJ),
                ("type({1:2})", m.HASH_OBJ),
            ]
                check(code, expected)
            end
        end

        @testset "puts" begin
            for (code, expected_output) in [
                ("puts()", ""),
                ("puts(1)", "1\n"),
                ("puts(\"hello\")", "hello\n"),
                ("puts([23, \"hello\"])", "[23, \"hello\"]\n"),
            ]
                check(code, nothing, expected_output)
            end
        end

        @testset "Complex combination" begin
            for (code, expected) in [
                (
                    """
                    let map = fn(arr, f) {
                        let iter = fn(arr, accumulated) {
                            if (len(arr) == 0) {
                                accumulated
                            } else {
                                iter(rest(arr), push(accumulated, f(first(arr))));
                            }
                        };

                        iter(arr, []);
                    };

                    let a = [1, 2, 3, 4];
                    let double = fn(x) { x * 2 };
                    map(a, double)[3]
                    """,
                    8,
                ),
                (
                    """
                    let reduce = fn(arr, initial, f) {
                        let iter = fn(arr, result) {
                            if (len(arr) == 0) {
                                result
                            } else {
                                iter(rest(arr), f(result, first(arr)))
                            }
                        }

                        iter(arr, initial)
                    }

                    let sum = fn(arr) {
                        reduce(arr, 0, fn(initial, el) { initial + el })
                    }

                    sum([1, 2, 3, 4, 5])
                    """,
                    15,
                ),
            ]
                check(code, expected)
            end
        end
    end

    @testset "Macro" begin
        for (code, expected) in [
            (
                """
                let double_len_macro = macro(x) { quote(len(unquote(x)) * 2); };
                let double_len = double_len_macro([1, 2, 3]);
                    double_len;
                """,
                6,
            ),
            (
                """
                let unless = macro(condition, consequence, alternative) {
                    quote(if (!(unquote(condition))) {
                        unquote(consequence);
                    } else {
                        unquote(alternative);
                    });
                };

                unless(10 > 5, "not greater", "greater");
                """,
                "greater",
            ),
        ]
            check(code, expected)
        end
    end

    @testset "Error handling" begin
        @testset "Invalid expression" begin
            for (code, expected) in [
                # `INTEGER + BOOLEAN` works well in Julia
                ("5 + null", "type mismatch: INTEGER + NULL"),
                ("5 + null; 5;", "type mismatch: INTEGER + NULL"),
                ("-null", "unknown operator: -NULL"),
                ("null + null;", "unknown operator: NULL + NULL"),
                ("5; null + null; 5", "unknown operator: NULL + NULL"),
                ("if (10 > 1) { null + null; }", "unknown operator: NULL + NULL"),
                (
                    """
                    if (10 > 1) {
                        if (10 > 1) {
                            return null + null;
                        }

                        return 1;
                    }
                   """,
                    "unknown operator: NULL + NULL",
                ),
                ("\"Hello\" - \"World\"", "unknown operator: STRING - STRING"),
                ("5 / 0", "divide error: division by zero"),
                ("[5 / 0]", "divide error: division by zero"),
                ("{5 / 0: 2}", "divide error: division by zero"),
                ("{2: 5 / 0}", "divide error: division by zero"),
                ("(5 / 0) + (5 / 0)", "divide error: division by zero"),
                ("if (5 / 0) { 2 }", "divide error: division by zero"),
                ("while (5 / 0) { 2 }", "divide error: division by zero"),
                ("(5 / 0)()", "divide error: division by zero"),
                ("let a = fn(x) { x }; a(5 / 0);", "divide error: division by zero"),
                ("{1:2}[5 / 0]", "divide error: division by zero"),
                ("(5 / 0)[2]", "divide error: division by zero"),
                ("let a = 5 / 0", "divide error: division by zero"),
                ("if (true) { 5 / 0; 2 + 3; 4; }", "divide error: division by zero"),
                ("\"str\"[1]", "index operator not supported: STRING"),
                ("[1, 2, 3][\"23\"]", "unsupported index type: STRING"),
                ("2(3)", "not a function: INTEGER"),
                ("fn() { 1; }(1);", "argument error: wrong number of arguments: got 1"),
                ("fn(a) { a; }();", "argument error: wrong number of arguments: got 0"),
                (
                    "fn(a, b) { a + b; }(1);",
                    "argument error: wrong number of arguments: got 1",
                ),
            ]
                if check_object
                    check(code, expected, "ERROR: $expected\n")
                else
                    check(code, nothing, "ERROR: $expected\n")
                end
            end

            @testset "Semantic analysis" begin
                for (code, expected) in [
                    ("foobar", "identifier not found: foobar"),
                    ("x = 2;", "identifier not found: x"),
                    ("let a = 2; let a = 4;", "a is already defined"),
                ]
                    if check_object
                        check(code, expected, "ERROR: $expected\n")
                    else
                        check(code, nothing, "ERROR: $expected\n")
                    end
                end
            end
        end

        @testset "Built-in function" begin
            for (code, expected) in [
                (
                    "len(1)",
                    "argument error: argument to `len` is not supported, got INTEGER",
                ),
                (
                    "len(\"one\", \"two\")",
                    "argument error: wrong number of arguments. Got 2 instead of 1",
                ),
                (
                    "first([1, 2], [2])",
                    "argument error: wrong number of arguments. Got 2 instead of 1",
                ),
                (
                    "first(1)",
                    "argument error: argument to `first` is not supported, got INTEGER",
                ),
                (
                    "last(1)",
                    "argument error: argument to `last` is not supported, got INTEGER",
                ),
                (
                    "last([1, 2], [2])",
                    "argument error: wrong number of arguments. Got 2 instead of 1",
                ),
                (
                    "rest(1)",
                    "argument error: argument to `rest` is not supported, got INTEGER",
                ),
                (
                    "rest([1, 2], [2])",
                    "argument error: wrong number of arguments. Got 2 instead of 1",
                ),
                (
                    "push()",
                    "argument error: wrong number of arguments. Got 0 instead of 2 or 3",
                ),
                (
                    "push({}, 2)",
                    "argument error: argument to `push` is not supported, got HASH",
                ),
                (
                    "push([], 2, 3)",
                    "argument error: argument to `push` is not supported, got ARRAY",
                ),
                (
                    "type(1, 2)",
                    "argument error: wrong number of arguments. Got 2 instead of 1",
                ),
            ]
                if check_object
                    check(code, expected, "ERROR: $expected\n")
                else
                    check(code, nothing, "ERROR: $expected\n")
                end
            end
        end
    end
end


text:
# using Ecosystem
using Scientific_Programming_in_Julia.Ecosystem

function create_world()
    n_grass       = 500
    regrowth_time = 17.0

    n_sheep         = 100
    Δenergy_sheep   = 5.0
    sheep_reproduce = 0.5
    sheep_foodprob  = 0.4

    n_wolves       = 8
    Δenergy_wolf   = 17.0
    wolf_reproduce = 0.03
    wolf_foodprob  = 0.02

    gs = [Grass(id, regrowth_time) for id in 1:n_grass];
    ss = [Sheep(id, 2*Δenergy_sheep, Δenergy_sheep, sheep_reproduce, sheep_foodprob) for id in n_grass+1:n_grass+n_sheep];
    ws = [Wolf(id, 2*Δenergy_wolf, Δenergy_wolf, wolf_reproduce, wolf_foodprob) for id in n_grass+n_sheep+1:n_grass+n_sheep+n_wolves];
    World(vcat(gs, ss, ws))
end
world = create_world();
simulate!(world, 10)


text:
module BuildingGeometry

include("presstaps.jl")
#include("polygons.jl")
include("surf_voronoi_project2d.jl")

end