text:
module Mimi

include("metainfo.jl")
include("clock.jl")

using DataStructures
using DataFrames
using Distributions
using Compat

export
    ComponentState, run_timestep, run, @defcomp, Model, setindex, addcomponent, setparameter,
    connectparameter, setleftoverparameters, getvariable, adder, MarginalModel, getindex,
    getdataframe, components, variables, setbestguess, setrandom, getvpd, unitcheck

import
    Base.getindex, Base.run, Base.show

function lint_helper(ex::Expr, ctx)
    if ex.head == :macrocall
        if ex.args[1] == Symbol("@defcomp")
            push!(ctx.callstack[end].types, ex.args[2])
            return true
        end
    end
    return false
end

abstract ComponentState

abstract Parameter

type CertainScalarParameter <: Parameter
    dependentCompsAndParams::Set{Tuple{ComponentState, Symbol}}
    value

    function CertainScalarParameter(value)
        p = new()
        p.dependentCompsAndParams = Set{Tuple{ComponentState,Symbol}}()
        p.value = value
        return p
    end
end

function setbestguess(p::CertainScalarParameter)
    for (c, name) in p.dependentCompsAndParams
        bg_value = p.value
        setfield!(c.Parameters,name,bg_value)
    end
end

function setrandom(p::CertainScalarParameter)
    for (c, name) in p.dependentCompsAndParams
        bg_value = p.value
        setfield!(c.Parameters,name,bg_value)
    end
end

type UncertainScalarParameter <: Parameter
    dependentCompsAndParams::Set{Tuple{ComponentState,Symbol}}
    value::Distribution

    function UncertainScalarParameter(value)
        p = new()
        p.dependentCompsAndParams = Set{Tuple{ComponentState,Symbol}}()
        p.value = value
        return p
    end
end

function setbestguess(p::UncertainScalarParameter)
    bg_value = mode(p.value)
    for (c, name) in p.dependentCompsAndParams
        setfield!(c.Parameters,name,bg_value)
    end
end

function setrandom(p::UncertainScalarParameter)
    sample = rand(p.value)
    for (c, name) in p.dependentCompsAndParams
        setfield!(c.Parameters,name,sample)
    end
end

type UncertainArrayParameter <: Parameter
    distributions::Array{Distribution, 1}
    values::Array{Float64,1}

    function UncertainArrayParameter(distributions)
        uap = new()
        uap.distributions = distributions
        uap.values = Array(Float64, size(distributions))
        return uap
    end
end

function setbestguess(p::UncertainArrayParameter)
    for i in 1:length(p.distributions)
        p.values[i] = mode(p.distributions[i])
    end
end

function setrandom(p::UncertainArrayParameter)
    for i in 1:length(p.distributions)
        p.values[i] = rand(p.distributions[i])
    end
end

type CertainArrayParameter <: Parameter
    values

    function CertainArrayParameter(values::Array)
        uap = new()
        uap.values = values
        return uap
    end
end

function setbestguess(p::CertainArrayParameter)
end

function setrandom(p::CertainArrayParameter)
end

type ComponentInstanceInfo
    name::Symbol
    component_type::DataType
end

type ParameterVariableConnection
    source_variable_name::Symbol
    source_component_name::Symbol
    target_parameter_name::Symbol
    target_component_name::Symbol
end

type Model
    indices_counts::Dict{Symbol,Int}
    indices_values::Dict{Symbol,Vector{Any}}
    components::OrderedDict{Symbol,ComponentState}
    parameters_that_are_set::Set{Compat.UTF8String}
    parameters::Dict{Symbol,Parameter}
    numberType::DataType
    connections::Array{ParameterVariableConnection, 1}
    components2::OrderedDict{Symbol, ComponentInstanceInfo}

    function Model(numberType::DataType=Float64)
        m = new()
        m.indices_counts = Dict{Symbol,Int}()
        m.indices_values = Dict{Symbol, Vector{Any}}()
        m.components = OrderedDict{Symbol,ComponentState}()
        m.parameters_that_are_set = Set{Compat.UTF8String}()
        m.parameters = Dict{Symbol, Parameter}()
        m.numberType = numberType
        m.connections = Array(ParameterVariableConnection, 0)
        m.components2 = OrderedDict{Symbol, ComponentInstanceInfo}()
        return m
    end
end

type MarginalModel
    base::Model
    marginal::Model
    delta::Float64
end

function setbestguess(m::Model)
    for p in values(m.parameters)
        setbestguess(p)
    end
end

function setrandom(m::Model)
    for p in values(m.parameters)
        setrandom(p)
    end
end

"""
    components(m::Model)

List all the components in model `m`.
"""
function components(m::Model)
    collect(keys(m.components))
end

# Return the MetaComponent for a given component
function getmetainfo(m::Model, componentname::Symbol)
    meta = metainfo.getallcomps()
    meta_module_name = Symbol(supertype(typeof(m.components[componentname])).name.module)
    meta_component_name = Symbol(supertype(typeof(m.components[componentname])).name.name)
    meta[(meta_module_name, meta_component_name)]
end

"""
    variables(m::Model, componentname::Symbol)

List all the variables of `componentname` in model `m`.
"""
function variables(m::Model, componentname::Symbol)
    c = getmetainfo(m, componentname)
    collect(keys(c.variables))
end

function getindex(m::MarginalModel, component::Symbol, name::Symbol)
    return (m.marginal[component,name].-m.base[component,name])./m.delta
end

function setindex(m::Model, name::Symbol, count::Int)
    m.indices_counts[name] = count
    m.indices_values[name] = collect(1:count)
    nothing
end

function setindex{T}(m::Model, name::Symbol, values::Vector{T})
    m.indices_counts[name] = length(values)
    m.indices_values[name] = copy(values)
    nothing
end

"""
Add a component to a model.
"""
function addcomponent(m::Model, t, name::Symbol=Symbol(string(t)); before=nothing,after=nothing)
    if before!=nothing && after!=nothing
        error("Can only specify before or after parameter")
    end

    comp = t(m.numberType, m.indices_counts)

    if before!=nothing
        newcomponents = OrderedDict{Symbol,ComponentState}()
        newcomponents2 = OrderedDict{Symbol, ComponentInstanceInfo}()
        for i in keys(m.components)
            if i==before
                newcomponents[name] = comp
                curr = ComponentInstanceInfo(name, t)
                newcomponents2[name] = curr
            end
            newcomponents[i] = m.components[i]
            newcomponents2[i] = m.components2[i]
        end
        m.components = newcomponents
        m.components2 = newcomponents2
    elseif after!=nothing
        error("Not yet implemented")
    else
        m.components[name] = comp
        this = ComponentInstanceInfo(name, t)
        m.components2[name] = this
    end

    ComponentReference(m, name)
end

"""
Set the parameter of a component in a model to a given value.
"""
function setparameter(m::Model, component::Symbol, name::Symbol, value)
    addparameter(m, name, value)
    connectparameter(m, component, name, name)

    setbestguess(m.parameters[Symbol(lowercase(string(name)))])
    nothing
end

function connectparameter(m::Model, component::Symbol, name::Symbol, parametername::Symbol)
    c = m.components[component]
    p = m.parameters[Symbol(lowercase(string(parametername)))]

    if isa(p, CertainScalarParameter) || isa(p, UncertainScalarParameter)
        push!(p.dependentCompsAndParams, (c, name))
    else
        setfield!(c.Parameters,name,p.values)
    end
    push!(m.parameters_that_are_set, string(component) * string(name))

    nothing
end

function updateparameter(m::Model, name::Symbol, value)
       p = m.parameters[Symbol(lowercase(string(name)))]

       p.value = value

       setbestguess(p)
end

function addparameter(m::Model, name::Symbol, value)
    if isa(value, Distribution)
        p = UncertainScalarParameter(value)
        m.parameters[Symbol(lowercase(string(name)))] = p
    elseif isa(value, AbstractArray)
        if any(x->isa(x, Distribution), value)
            p = UncertainArrayParameter(value)
            m.parameters[Symbol(lowercase(string(name)))] = p
        else
            if !(typeof(value) <: Array{m.numberType})
                # E.g., if model takes Number and given Float64, convert it
                value = convert(Array{m.numberType}, value)
            end

            p = CertainArrayParameter(value)
            m.parameters[Symbol(lowercase(string(name)))] = p
        end
    else
        p = CertainScalarParameter(value)
        m.parameters[Symbol(lowercase(string(name)))] = p
    end
end

function connectparameter(m::Model, target_component::Symbol, target_name::Symbol, source_component::Symbol, source_name::Symbol; ignoreunits::Bool=false)
    c_target = m.components[target_component]
    c_source = m.components[source_component]

    # Check the units, if provided
    if !ignoreunits &&
        !unitcheck(getmetainfo(m, target_component).parameters[target_name].unit,
                   getmetainfo(m, source_component).variables[source_name].unit)
        throw(ErrorException("Units of $source_component.$source_name do not match $target_component.$target_name."))
    end

    setfield!(c_target.Parameters, target_name, getfield(c_source.Variables, source_name))
    push!(m.parameters_that_are_set, string(target_component) * string(target_name))

    this = ParameterVariableConnection(source_name, source_component, target_name, target_component)
    push!(m.connections, this)

    nothing
end

# Default string, string unit check function
function unitcheck(one::AbstractString, two::AbstractString)
    # True if and only if they match
    return one == two
end

"""
Bind the parameter of one component to a variable in another component.

"""
connectparameter

"""
Set all the parameters in a model that don't have a value and are not connected
to some other component to a value from a dictionary.
"""
function setleftoverparameters(m::Model,parameters::Dict{Any,Any})
    for (name, value) in parameters
        addparameter(m, Symbol(name), value)
    end

    for c in m.components
        for name in fieldnames(c[2].Parameters)
            if !in(string(c[1])*string(name), m.parameters_that_are_set)
                connectparameter(m, c[1], name, name)
            end
        end
    end
    nothing
end

function getindex(m::Model, component::Symbol, name::Symbol)
    return getfield(m.components[component].Variables, name)
end

"""
    getdataframe(m::Model, componentname::Symbol, name::Symbol)

Return the values for variable `name` in `componentname` of model `m` as a DataFrame.
"""
function getdataframe(m::Model, componentname::Symbol, name::Symbol)
    comp_type = typeof(m.components[componentname])

    meta_module_name = Symbol(supertype(typeof(m.components[componentname])).name.module)
    meta_component_name = Symbol(supertype(typeof(m.components[componentname])).name.name)

    vardiminfo = getdiminfoforvar((meta_module_name,meta_component_name), name)
    if length(vardiminfo)==0
        return m[componentname, name]
    elseif length(vardiminfo)==1
        df = DataFrame()
        df[vardiminfo[1]] = m.indices_values[vardiminfo[1]]
        df[name] = m[componentname, name]
        return df
    elseif length(vardiminfo)==2
        df = DataFrame()
        dim1 = length(m.indices_values[vardiminfo[1]])
        dim2 = length(m.indices_values[vardiminfo[2]])
        df[vardiminfo[1]] = repeat(m.indices_values[vardiminfo[1]],inner=[dim2])
        df[vardiminfo[2]] = repeat(m.indices_values[vardiminfo[2]],outer=[dim1])
        data = m[componentname, name]
        df[name] = cat(1,[vec(data[i,:]) for i=1:dim1]...)
        return df
    else
        error("Not yet implemented")
    end
end

import Base.show
show(io::IO, a::ComponentState) = print(io, "ComponentState")

"""
    run(m::Model)

Run model `m` once.
"""
function run(m::Model;ntimesteps=typemax(Int))
    clock = Clock(1,min(m.indices_counts[:time],ntimesteps))

    for c in values(m.components)
        resetvariables(c)
        init(c)
    end

    while !finished(clock)
        for c in values(m.components)
            run_timestep(c,gettimestep(clock))
        end
        move_forward(clock)
    end
end

function run_timestep(s, t)
    typeofs = typeof(s)
    println("Generic run_timestep called for $typeofs.")
end

function init(s)
end

function resetvariables(s)
    typeofs = typeof(s)
    println("Generic resetvariables called for $typeofs.")
end

function getdiminfoforvar(s, name)
    meta = metainfo.getallcomps()
    meta[s].variables[name].dimensions
end

function getvpd(s)
    return s.Variables, s.Parameters, s.Dimensions
end

# Helper function for macro: collects all the keyword arguments in a function call to a dictionary.
function collectkw(args::Vector{Any})
    kws = Dict{Symbol, Any}()
    for arg in args
        if isa(arg, Expr) && arg.head == :kw
            kws[arg.args[1]] = arg.args[2]
        end
    end

    kws
end

"""
Define a new component.
"""
macro defcomp(name, ex)
    resetvarsdef = Expr(:block)

    metavardef = Expr(:block)
    metapardef = Expr(:block)
    metadimdef = Expr(:block)

    for line in ex.args
        if line.head==:(=) && line.args[2].head==:call && line.args[2].args[1]==:Index
            dimensionName = line.args[1]

            push!(metadimdef.args, :(metainfo.adddimension(module_name(current_module()), $(Expr(:quote,name)), $(QuoteNode(dimensionName)) )))
        elseif line.head==:(=) && line.args[2].head==:call && line.args[2].args[1]==:Parameter
            if isa(line.args[1], Symbol)
                parameterName = line.args[1]
                parameterType = :Number
            elseif line.args[1].head==:(::)
                parameterName = line.args[1].args[1]
                parameterType = line.args[1].args[2]
            else
                error()
            end

            kws = collectkw(line.args[2].args)

            # Get description and unit, if provided
            description = get(kws, :description, "")
            unit = get(kws, :unit, "")

            if haskey(kws, :index)
                parameterIndex = kws[:index].args

                pardims = Array(Any, 0)
                for l in parameterIndex
                    push!(pardims, l)
                end

                push!(metapardef.args, :(metainfo.addparameter(module_name(current_module()), $(Expr(:quote,name)), $(QuoteNode(parameterName)), $(esc(parameterType)), $(pardims), $(description), $(unit))))
            else
                push!(metapardef.args, :(metainfo.addparameter(module_name(current_module()), $(Expr(:quote,name)), $(QuoteNode(parameterName)), $(esc(parameterType)), [], $(description), $(unit))))
            end
        elseif line.head==:(=) && line.args[2].head==:call && line.args[2].args[1]==:Variable
            if isa(line.args[1], Symbol)
                variableName = line.args[1]
                variableType = :Number
            elseif line.args[1].head==:(::)
                variableName = line.args[1].args[1]
                variableType = line.args[1].args[2]
            else
                error()
            end

            kws = collectkw(line.args[2].args)

            # Get description and unit, if provided
            description = get(kws, :description, "")
            unit = get(kws, :unit, "")

            if haskey(kws, :index)
                variableIndex = kws[:index].args

                vardims = Array(Any, 0)
                for l in variableIndex
                    push!(vardims, l)
                end

                push!(metavardef.args, :(metainfo.addvariable(module_name(current_module()), $(Expr(:quote,name)), $(QuoteNode(variableName)), $(esc(variableType)), $(vardims), $(description), $(unit))))

                if variableType==:Number
                    push!(resetvarsdef.args,:($(esc(Symbol("fill!")))(s.Variables.$(variableName),$(esc(Symbol("NaN"))))))
                end
            else
                push!(metavardef.args, :(metainfo.addvariable(module_name(current_module()), $(Expr(:quote,name)), $(QuoteNode(variableName)), $(esc(variableType)), [], $(description), $(unit))))

                if variableType==:Number
                    push!(resetvarsdef.args,:(s.Variables.$(variableName) = $(esc(Symbol("NaN")))))
                end
            end
        elseif line.head==:line
        else
            error("Unknown expression.")
        end
    end

    module_def = :(eval(current_module(), :(module temporary_name end)))
    module_def.args[3].args[1].args[2] = Symbol(string("_mimi_implementation_", name))

    call_expr = Expr(:call,
        Expr(:curly,
            Expr(:., Expr(:., Expr(:., :Main, QuoteNode(Symbol(current_module()))), QuoteNode(Symbol(string("_mimi_implementation_", name)))), QuoteNode(Symbol(string(name,"Impl")))) ,
            :T),
        :T,
        :indices
        )

    x = quote

        abstract $(esc(Symbol(name))) <: Mimi.ComponentState

        import Mimi.run_timestep
        import Mimi.init
        import Mimi.resetvariables

        function $(esc(Symbol("resetvariables")))(s::$(esc(Symbol(name))))
            $(resetvarsdef)
        end

        metainfo.addcomponent(module_name(current_module()), $(Expr(:quote,name)))
        $(metavardef)
        $(metapardef)
        $(metadimdef)

        $(module_def)

        eval($(esc(Symbol(string("_mimi_implementation_", name)))), metainfo.generate_comp_expressions(module_name(current_module()), $(Expr(:quote,name))))

        function $(esc(Symbol(name))){T}(::Type{T}, indices)
            $(call_expr)
        end

    end

    x
end

@defcomp adder begin
    add = Parameter(index=[time])
    input = Parameter(index=[time])
    output = Variable(index=[time])
end

function run_timestep(s::adder, t::Int)
    v = s.Variables
    p = s.Parameters

    v.output[t] = p.input[t] + p.add[t]
end

#Begin Graph Functionality section

function show(io::IO, m::Model)
    println(io, "showing model component connections:")
    for item in enumerate(keys(m.components2))
        c = item[2]
        i_connections = get_connections(m,c,:incoming)
        o_connections = get_connections(m,c,:outgoing)
        println(io, item[1], ". ", c, " component")
        println(io, "    incoming parameters:")
        if length(i_connections)==0
            println(io, "      none")
        else
            [println(io, "      - ",e.target_parameter_name," from ",e.source_component_name," component") for e in i_connections]
        end
        println(io, "    outgoing variables:")
        if length(o_connections)==0
            println(io, "      none")
        else
            [println(io, "      - ",e.source_variable_name," in ",e.target_component_name, " component") for e in o_connections]
        end
    end
end

function get_connections(m::Model, c::ComponentInstanceInfo, which::Symbol)
    return get_connections(m, c.name, which)
end

function get_connections(m::Model, component_name::Symbol, which::Symbol)
    if which==:all
        f = e -> e.source_component_name==component_name || e.target_component_name==component_name
    elseif which==:incoming
        f = e -> e.target_component_name==component_name
    elseif which==:outgoing
        f = e -> e.source_component_name==component_name
    else
        error("Invalid parameter for the 'which' argument; must be 'all' or 'incoming' or 'outgoing'.")
    end
    return filter(f, m.connections)
end

#End of graph section

include("references.jl")

end # module


text:
# see examples.jl first

# Creator

P1 = Person(age=24, field="Mechanical Engineering", courses = ["Artificial Intelligence", "Robotics"], id = 1, comment = "He is a genius")

P2 = Person(age=18, field="Computer Engineering", GPA=4, courses=["Julia"], id = 2)

# Two examples that doesn't meet the critertia function for GPA because GPA is more than 4.5
#=
P3 = Person(age=99, field="Macro Wizard", GPA=10, courses=["Julia Magic"], id = 3)
# GPA doesn't meet criteria function

P1.GPA=5.0
# GPA doesn't meet criteria function
=#

U = University(name="Julia University", people=[P1, P2])

U.people[2].GPA=4.2 # mutability support after Doc creation

pprint(P1) # or print(P1.aml)
#=
<person id="1">
  <age>24</age>
  <study-field>Mechanical Engineering</study-field>
  <GPA>4.5</GPA>
  <taken-courses>Artificial Intelligence</taken-courses>
  <taken-courses>Robotics</taken-courses>
  He is a genius
</person>
=#

pprint(P2) # or print(P2.aml)
#=
<person id="2">
  <age>18</age>
  <study-field>Computer Engineering</study-field>
  <GPA>4.2</GPA>
  <taken-courses>Julia</taken-courses>
</person>
=#

pprint(U) # or print(U.aml)
#=
<?xml version="1.0" encoding="UTF-8"?>
<university university-name="Julia University">
  <person id="1"><age>24</age><study-field>Mechanical Engineering</study-field><GPA>4.5</GPA><taken-courses>Artificial Intelligence</taken-courses><taken-courses>Robotics</taken-courses>He is a genius</person>
  <person id="2">
    <age>18</age>
    <study-field>Computer Engineering</study-field>
    <GPA>4.2</GPA>
    <taken-courses>Julia</taken-courses>
  </person>
</university>
=#

ext: jl


text:
module WeightedArrays

include("../deps/GroupSlices.jl")

include("struct.jl")

include("create.jl")

include("manip.jl")

include("pca.jl")

include("save.jl")

include("plots.jl")

end


text:
using PrettyPrint
using StructArrays
using Test
struct Account
    username :: String
    password :: String
end

struct S1
  i :: Int
  f :: Float64
end

struct S2
  s  :: Vector{String}
  s1 :: S1
end

struct B
  a :: Int
  b :: Int
end

struct C
  a
  b
end
@testset "PrettyPrint.jl" begin

    data = S2(
        ["114514", "as we can"],
        S1(42, 9.96)
    )
    pprint(data)
    println()
    @test pformat(data) == """S2(
  s=["114514", "as we can"],
  s1=S1(i=42, f=9.96),
)"""

    @testset "extension" begin
    @test pformat([Account("van", "gd"), Account("thautwarm", "996icu")]) == """[
  Account(username="van", password="gd"),
  Account(username="thautwarm", password="996icu"),
]"""
    PrettyPrint.pp_impl(io, account::Account, indent::Int) = begin
      repr = "Account($(account.username))"
      print(io, repr)
      length(repr) + indent
    end

    @test pformat([Account("van", "gd"), Account("thautwarm", "996icu")]) == """[
  Account(van),
  Account(thautwarm),
]"""
    @test pformat(Set([Account("van", "gd")])) == """{
  Account(van),
}"""

  pprint(Dict(:a=>Account("van", "gd"), :b=>Account("thautwarm", "996icu")))

    @test pformat(Dict(:a=>Account("van", "gd"), :b=>Account("thautwarm", "996icu"))) == """{
  :a : Account(van),
  :b : Account(thautwarm),
}"""

  @test pformat(1 => 2) == "1 => 2"

  @test pformat(Any[1 + 2im, 3]) == "[1 + 2im, 3]"

  @test pformat(StructArray([B(1, 2), B(2, 3)])) =="""StructArray{B,1,NamedTuple{(:a, :b),Tuple{Array{Int64,1},Array{Int64,1}}},Int64}(
    a=[1, 2],
    b=[2, 3],
  )"""

  @test pformat([]) == "[]"

  PrettyPrint.is_static_t(::Type{B}) = true

  @test pformat(StructArray([B(1, 2), B(2, 3)])) =="""StructArray{B,1,NamedTuple{(:a, :b),Tuple{Array{Int64,1},Array{Int64,1}}},Int64}(
    a=[1, 2],
    b=[2, 3],
  )"""

  @test pformat(['a', 'b']) == "['a', 'b']"
  @test pformat(['a', nothing]) == "['a', nothing]"

  xs = collect(1:100)
  @test pformat(xs) ==
"""
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
 12, 13, 14, 15, 16, 17, 18, 19,
 20, 21, 22, 23, 24, 25, 26, 27,
 28, 29, 30, 31, 32, 33, 34, 35,
 36, 37, 38, 39, 40, 41, 42, 43,
 44, 45, 46, 47, 48, 49, 50, 51,
 52, 53, 54, 55, 56, 57, 58, 59,
 60, 61, 62, 63, 64, 65, 66, 67,
 68, 69, 70, 71, 72, 73, 74, 75,
 76, 77, 78, 79, 80, 81, 82, 83,
 84, 85, 86, 87, 88, 89, 90, 91,
 92, 93, 94, 95, 96, 97, 98, 99,
 100]"""

    @test pformat([1]) == "[1,]"
    @test pformat((1, )) == "(1,)"

    PrettyPrint.is_simple_t(::Type{C}) = true
    PrettyPrint.is_static_t(::Type{C}) = true
    @test is_static_t(typeof(C(1, 2))) == true
    @test pformat(C(1, 2)) == "C(a=1, b=2)"
    @test pformat(SubString("aa", 1)) == "\"aa\""

    @test is_simple_t(Int) == true
    @test is_simple_t(SubString) == true
    @test is_simple_t(Complex{Int}) == true
    @test is_simple_t(Char) == true
    @test is_simple_t(Nothing) == true
    @test is_simple(PrettyPrint.PPPair("1", "=", "3")) == true
    pprintln(true)

  end

end


text:
""" Implements an exponentially-weighted smoothing method for low-pass
filtering.

For a data set `ys` at times `ts` with observational uncertainties `dys`, the
output point ``\\tilde{y}_i`` is given by the weighted sum

``\\tilde{y}_i = \\frac{\\sum_{\\left. j \\mid t_j < t_i \\right.} w_{j,i} y_j + y_i + \\sum_{\\left. k \\mid t_k > t_i \\right.} w_{k,i} y_k}{1 + \\sum_{\\left. j \\mid t_j < t_i \\right.} w_{j,i} + \\sum_{\\left. k \\mid t_k > t_i \\right.} w_{k,i}}``

and the uncertainty on the output point is given by

``\\sigma_{\\tilde{y}_i} = \\sqrt{\\frac{\\sum_{\\left. j \\mid t_j < t_i \\right.} w_{j,i}^2 \\sigma_{y_j}^2 + \\sigma_{y_i}^2 + \\sum_{\\left. k \\mid t_k > t_i \\right.} w_{k,i}^2 \\sigma_{y_k}^2}{\\left(1 + \\sum_{\\left. j \\mid t_j < t_i \\right.} w_{j,i} + \\sum_{\\left. k \\mid t_k > t_i \\right.} w_{k,i}\\right)^2}}``

where the weights are given by the exponential

``w_{j,i} = \\exp\\left( -\\frac{\\left| t_j - t_i \\right|}{\\tau} \\right)``

and similarly for ``w_{k,i}``.  Because

``w_{j,i+1} = w_{j,i} \\exp\\left( -\\frac{\\left| t_{i+1} - t_i \\right|}{\\tau}\\right)``

for all ``j < i``, we have

``\\sum_{\\left. j \\mid t_j < t_{i+1} \\right.} w_{j,i+1} y_j = \\exp\\left( -\\frac{\\left| t_{i+1} - t_i \\right|}{\\tau}\\right) \\left[ \\sum_{\\left. j \\mid t_j < t_i \\right.} w_{j,i} y_j + y_i \\right]``

and similarly for all other sums appearing above.  These recursions enable the
computation of all the terms appearing in the outputs above during one forward
and one reverse pass over the data.

The filter has an (exact) autocorrelation time of ``2\\tau``, which permits
thinning of the output time series to obtain (approximately) independent
uncertainties on the low-passed data.

"""
module LowPass

"""
    exp_lowpass(ts, ys, dys, tau)

Low-pass filter the input data `ys` taken at times `ts` with uncertainties `dys`
with exponential weighting with timescale `tau`.

Returns `(ys_lowpass, dys_lowpass)`, sampled at the same rate as the original
series.  (But see `thin_exp_lowpass`.)
"""
function exp_lowpass(ts, ys, dys, tau)
    n = size(ts, 1)

    left_mus = zeros(n)
    left_sigmas = zeros(n)
    left_sums = zeros(n)

    right_mus = zeros(n)
    right_sigmas = zeros(n)
    right_sums = zeros(n)

    for i in 2:n
        dt = ts[i] - ts[i-1]
        wt = exp(-dt/tau)

        left_mus[i] = left_mus[i-1]*wt + wt*ys[i-1]
        left_sigmas[i] = wt*sqrt(left_sigmas[i-1]*left_sigmas[i-1] + dys[i-1]*dys[i-1])
        left_sums[i] = wt*left_sums[i-1] + wt
    end

    for i in n-1:-1:1
        dt = ts[i+1]-ts[i]
        wt = exp(-dt/tau)

        right_mus[i] = right_mus[i+1]*wt + wt*ys[i+1]
        right_sigmas[i] = wt*sqrt(right_sigmas[i+1]*right_sigmas[i+1] + dys[i+1]*dys[i+1])
        right_sums[i] = wt*right_sums[i+1] + wt
    end

    ys_filt = (left_mus .+ right_mus .+ ys)./(1.0 .+ left_sums .+ right_sums)
    dys_filt = sqrt.((left_sigmas.*left_sigmas .+ right_sigmas.*right_sigmas .+ dys.*dys)./((1.0 .+ left_sums .+ right_sums).*(1.0 .+ left_sums .+ right_sums)))

    ys_filt, dys_filt
end

"""
    thin_exp_lowpass(ts, ys, dys, tau)

Return `(ts_thin, ys_thin, dys_thin)` with data chosen from the input times
`ts`, samples `ys`, and uncertainties `dys` but spaced by at least `tau` in
time.

The combination of `exp_lowpass` and `thin_exp_lowpass` will give
(approximately) independent-uncertainty low-passed samples from a time series.
"""
function thin_exp_lowpass(ts, ys, dys, tau)
    ifill = 1
    ts_t = [ts[1]]
    ys_t = [ys[1]]
    dys_t = [dys[1]]

    for i in 2:size(ts, 1)
        if ts[i] > ts_t[ifill] + 2*tau
            push!(ts_t, ts[i])
            push!(ys_t, ys[i])
            push!(dys_t, dys[i])
            ifill += 1
        end
    end

    ts_t, ys_t, dys_t
end

end


text:
using NeuralVerification, LazySets, Test, LinearAlgebra
import NeuralVerification: ReLU, Id

using Cbc

function read_input(fname::String)
    f = open(fname)
    allvals = chop(readline(f))
    arrvals = split(allvals,",")
    input_img = map(x->parse(Float64,x),arrvals)/255.0
    return input_img
end

vnn_mnist_networks = "$(@__DIR__)/../networks/vnn-comp-mnist/networks";
vnn_mnist_inputs = "$(@__DIR__)/../networks/vnn-comp-mnist/inputs";
input_labels = [7,2,1,0,4,1,4,9,5,9,0,6,9,0,1,5,9,7,3,4,9,6,6,5,4];

# property definition

# 256x2
network2  = read_nnet(vnn_mnist_networks*"/mnist-net_256x2.nnet", last_layer_activation = Id());
# 256x4
network4  = read_nnet(vnn_mnist_networks*"/mnist-net_256x4.nnet", last_layer_activation = Id());
# 256x6
network6  = read_nnet(vnn_mnist_networks*"/mnist-net_256x6.nnet", last_layer_activation = Id());

nws = Dict(2 => network2,
           4 => network4,
           6 => network6);

function test_mnist_problem1(solver, network_no, image_no , problem,epsi)
    solvername = string(typeof(solver))
    timed_result = @timed solve(solver, problem)
    res = solvername*","*string(network_no)*","*string(image_no)*","*string(epsi)*","*string(timed_result[2])*","*string(timed_result[1].status)
    print("\n"*res)
    return solvername, timed_result[2], timed_result[1].status, res
end

function test_mnist_group1(solver)
    solvername = string(typeof(solver))
    open(solvername*".csv", "w") do f
        for network_no in [2,4,6]
            print("Network: "*string(network_no))
            for in_epsilon in [.02, .05]
                print("Epsilon: "*string(in_epsilon))
                for image_no in 1:25

                    input_center = read_input(vnn_mnist_inputs*"/image"*string(image_no));
                    inputSet = Hyperrectangle(low=input_center .- in_epsilon, high=input_center .+ in_epsilon)

                    aux = Matrix(1.0I, 10,10);
                    aux[:,input_labels[image_no]+1] .= -1.0;
                    A = aux[1:size(aux,1) .!= input_labels[image_no]+1,: ];
                    b=zeros(9);

                    outputSet = HPolytope(A, b);

                    mnistproblem = Problem(nws[network_no], inputSet, outputSet);
                    solvername, t, status, res = test_mnist_problem1(solver, network_no, image_no , mnistproblem,in_epsilon)
                    write(f, res)
                    write(f, "\n")
                end
            end
        end
    end
end

function test_mnist_group2(solver)
    solvername = string(typeof(solver))
    open(solvername*".csv", "w") do f
        for network_no in [2,4,6]
            print("\n Network: "*string(network_no)*"\n")
            for in_epsilon in [.02, .05]
                print("\n Epsilon: "*string(in_epsilon)*"\n")
                for image_no in 1:25

                    input_center = read_input(vnn_mnist_inputs*"/image"*string(image_no));

                    inputSet = Hyperrectangle(input_center, ones(length(input_center))*in_epsilon)
                    #inputSet = Hyperrectangle(low=input_center .- in_epsilon, high=input_center .+ in_epsilon)

                    compare_to = (input_labels[image_no]+1) % 10
                    aux = Matrix(1.0I, 10,10);
                    aux[:,input_labels[image_no]+1] .= -1.0;
                    A = aux[1:size(aux,1) .== compare_to+1,: ];
                    b=zeros(1);

                    outputSet = HPolytope(A, b);

                    mnistproblem = Problem(nws[network_no], inputSet, outputSet);
                    solvername, t, status, res = test_mnist_problem1(solver, network_no, image_no , mnistproblem,in_epsilon)
                    write(f, res)
                    write(f, "\n")
                end
            end
        end
    end
end

# select group and solver

#test_mnist_group1(MaxSens())
test_mnist_group2(ConvDual())


text:
left_associative_contraction_sequence(N::Integer) = reduce((x, y) -> Any[y, x], 1:N)
left_associative_contraction_sequence(A) = left_associative_contraction_sequence(length(A))

"""
    contraction_cost(A; sequence)

Return the cost of contracting the collection of ITensors according to the specified sequence,
where the cost is measured in the number of floating point operations that would need to
be performed to contract dense tensors of the dimensions specified by the indices of the tensors
(so for now, sparsity is ignored in computing the costs).
Pairwise costs are returned in a vector (contracting `N` tensors requires `N-1` pairwise
contractions). You can use `sum(contraction_cost(A; sequence))` to get the total cost of the
contraction.

If no sequence is specified, left associative contraction is used, in other words the sequence
is equivalent to `[[[[1, 2], 3], 4], …]`.
"""
function contraction_cost(A; sequence = left_associative_contraction_sequence(A))
  pairwise_costs = Number[]
  _contraction_cost!(pairwise_costs, A, sequence)
  return pairwise_costs
end

function _contraction_cost!(pairwise_costs, A, sequence)
  inds1 = _contraction_cost!(pairwise_costs, A, sequence[1])
  inds2 = _contraction_cost!(pairwise_costs, A, sequence[2])
  return _pairwise_contraction_cost!(pairwise_costs, inds1, inds2)
end

_contraction_cost!(pairwise_costs, As, sequence::Integer) = As[sequence]

function _pairwise_contraction_cost!(pairwise_costs, A1, A2)
  cost = dim(union(A1, A2))
  push!(pairwise_costs, cost)
  return symdiff(A1, A2)
end


text:
## show.jl
## (c) 2013--2014 David A. van Leeuwen

## various tests for show()

## This code is licensed under the MIT license
## See the file LICENSE.md in this distribution
println("show,")

include("init-namedarrays.jl")

function showlines(x, args::Pair...)
    buf = IOBuffer()
    show(IOContext(buf, args...), x)
    return split(String(take!(copy(buf))), "\n")
end

function showlines(mime, x, args::Pair...)
    buf = IOBuffer()
    show(IOContext(buf, args...), mime, x)
    return split(String(take!(copy(buf))), "\n")
end

lines = showlines(NamedArray(Array{Int}(undef)))
@test length(lines) == 2
if VERSION >= v"1.6.0"
    @test lines[1] == "0-dimensional Named Array{Int64, 0}"
else
    @test lines[1] == "0-dimensional Named Array{Int64,0}"
end

lines = showlines(NamedArray([]))
@test length(lines) == 3
if VERSION >= v"1.6.0"
    @test lines[1] == "0-element Named Vector{Any}"
else
    @test lines[1] == "0-element Named Array{Any,1}"
end
@test split(lines[2]) == ["A", "│"]

for k in 0:5, (m,n) in ((k,0), (0,k))
    local lines = showlines(NamedArray(Matrix{Int}(undef, m, n)))
    @test length(lines) == 3 + m
    if VERSION >= v"1.6.0"
        @test lines[1] == "$m×$n Named Matrix{Int64}"
    else
        @test lines[1] == "$m×$n Named Array{Int64,2}"
    end
    @test split(lines[2]) == [["A", "╲", "B", "│"]; string.(1:n)]
    for i in 1:m
        @test split(lines[3+i])[1] == string(i)
    end
end

for _lines in Any[showlines(n), showlines(MIME"text/plain"(), n)]
    @test length(_lines) == 5
    if VERSION >= v"1.6.0"
        @test _lines[1] == "2×4 Named Matrix{Float64}"
    else
        @test _lines[1] == "2×4 Named Array{Float64,2}"
    end
    @test split(_lines[2]) == vcat(["A", "╲", "B", "│"], letters[1:4])
end

## wide array abbreviated
lines = showlines(NamedArray(randn(2,1000)), :limit => true)
@test length(lines) == 5
if VERSION >= v"1.6.0"
    @test lines[1] == "2×1000 Named Matrix{Float64}"
else
    @test lines[1] == "2×1000 Named Array{Float64,2}"
end
header = split(lines[2])
@test header[vcat(1:5, end)] == ["A", "╲", "B", "│", "1", "1000"]
@test "…" in header
for (_i, _line) in enumerate(lines[end-1:end])
    @test split(_line)[1] == string(_i)
end

## tall array abbreviated
lines = showlines(NamedArray(randn(1000,2)), :limit => true)
@test length(lines) > 7
if VERSION >= v"1.6.0"
    @test lines[1] == "1000×2 Named Matrix{Float64}"
else
    @test lines[1] == "1000×2 Named Array{Float64,2}"
end
@test split(lines[2]) == ["A", "╲", "B", "│", "1", "2"]
@test split(lines[4])[1] == "1"
@test split(lines[end])[1] == "1000"

## tall vector abbreviated
lines = showlines(NamedArray(randn(1000)), :limit => true)
@test length(lines) > 7
if VERSION >= v"1.6.0"
    @test lines[1] == "1000-element Named Vector{Float64}"
else
    @test lines[1] == "1000-element Named Array{Float64,1}"
end
@test split(lines[2]) == ["A", "│"]
@test split(lines[4])[1] == "1"
@test split(lines[end])[1] == "1000"

## non-standard integer indexing
zo = [0,1]
lines = showlines(NamedArray(rand(2,2,2), (zo, zo, zo), ("base", "zero", "indexing")))
@test length(lines) == 13
if VERSION >= v"1.6.0"
    @test lines[1] == "2×2×2 Named Array{Float64, 3}"
else
    @test lines[1] == "2×2×2 Named Array{Float64,3}"
end

for (index, offset) in ([0, 3], [1, 9])
    @test lines[offset] == "[:, :, indexing=$index] ="
    @test split(lines[offset+1]) == ["base", "╲", "zero", "│", "0", "1"]
    @test split(lines[offset+3])[1] == "0"
    @test split(lines[offset+4])[1] == "1"
end

for ndim in 1:5
    global lines = showlines(NamedArray(rand(fill(2,ndim)...)))
    if VERSION >= v"1.6.0"
        if (ndim == 1)
            line1 = "2-element Named Vector{Float64}"
        elseif (ndim == 2)
            line1 = "2×2 Named Matrix{Float64}"
        else
            line1 = join(repeat(["2"], ndim), "×") * " Named Array{Float64, $ndim}"
        end
    else
        if (ndim == 1)
            line1 = "2-element Named Array{Float64,1}"
        else
            line1 = join(repeat(["2"], ndim), "×") * " Named Array{Float64,$ndim}"
        end
    end
    @test lines[1] == line1
    if ndim ≥ 3
        @test startswith(lines[3], "[:, :, C=1")
        @test split(lines[4]) == ["A", "╲", "B", "│", "1", "2"]
    end
end
## various singletons
println(NamedArray(rand(1,2,2)))
println(NamedArray(rand(2,1,2)))
println(NamedArray(rand(2,2,1)))

## sparse array
nms = [string(hash(i)) for i in 1:1000]
lines = showlines(NamedArray(sprand(1000,1000, 1e-4), (nms, nms)), :limit => true)
@test length(lines) > 7
@test startswith(lines[1], "1000×1000 Named sparse matrix with")
@test endswith(lines[1], "Float64 nonzero entries:")
@test sum([occursin("⋮", _line) for _line in lines]) == 1

# DEPRECATED: ## array with Nullable names
# DEPRECATED: lines = showlines(NamedArray(rand(2, 2), (Nullable["a", Nullable()], Nullable["c", "d"])))
# DEPRECATED: @test lines[1] == "2×2 Named Array{Float64,2}"
# DEPRECATED: @test split(lines[2]) == ["A", "╲", "B", "│", "\"c\"", "\"d\""]
# DEPRECATED: @test startswith(lines[4], "\"a\"")
# DEPRECATED: @test startswith(lines[5], "#NULL")

## no limits
for dims in [(1000,), (1000, 2)]
    global lines = showlines(NamedArray(rand(dims...)), :limit => false)
    @test length(lines) == 1003
    @test startswith(lines[end-500], "500 ")
end
lines = showlines(NamedArray(rand(10, 1000)), :limit => false)
@test length(split(lines[2])) == 1004 ##  "A"    "╲"    "B"    "│" ...
@test length(split(lines[end])) == 1002 # "10"   "│" ...


text:
"Square the sum of the first `n` positive integers"
function square_of_sum(n)
    (n * (n + 1) ÷ 2)^2
end

"Sum the squares of the first `n` positive integers"
function sum_of_squares(n)
    n * (n + 1) * (2 * n + 1) ÷ 6
end

"Subtract the sum of squares from square of the sum of the first `n` positive ints"
function difference(n)
    square_of_sum(n) - sum_of_squares(n)
end

max_stars_repo_name: vladflore/exercism

max_issues_repo_name: vladflore/exercism

max_forks_repo_name: vladflore/exercism


text:
config = MOI.Test.TestConfig()
optimize!_max(mock) = MOIU.mock_optimize!(mock, [ 6.0, 1.0, 9.0, -3.0*√2],
    (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[3, 1, 1/3]],
    (MOI.VectorOfVariables, MOI.RotatedSecondOrderCone) => [[3, 1/3, √2]]
)
optimize!_min(mock) = MOIU.mock_optimize!(mock, [-6.0, 1.0, 9.0, 3.0*√2],
    (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[3, -1, 1/3]],
    (MOI.VectorOfVariables, MOI.RotatedSecondOrderCone) => [[3, 1/3, -√2]]
)
for mock in mocks(optimize!_max, optimize!_min)
    Tests.BPT12e399_test(mock, config)
end


text:
# This file is auto-generated by AWSMetadata.jl
using AWS
using AWS.AWSServices: codeguru_reviewer
using AWS.Compat
using AWS.UUIDs

"""
    associate_repository(repository)
    associate_repository(repository, params::Dict{String,<:Any})

 Use to associate an Amazon Web Services CodeCommit repository or a repostory managed by
Amazon Web Services CodeStar Connections with Amazon CodeGuru Reviewer. When you associate
a repository, CodeGuru Reviewer reviews source code changes in the repository's pull
requests and provides automatic recommendations. You can view recommendations using the
CodeGuru Reviewer console. For more information, see Recommendations in Amazon CodeGuru
Reviewer in the Amazon CodeGuru Reviewer User Guide.  If you associate a CodeCommit or S3
repository, it must be in the same Amazon Web Services Region and Amazon Web Services
account where its CodeGuru Reviewer code reviews are configured. Bitbucket and GitHub
Enterprise Server repositories are managed by Amazon Web Services CodeStar Connections to
connect to CodeGuru Reviewer. For more information, see Associate a repository in the
Amazon CodeGuru Reviewer User Guide.    You cannot use the CodeGuru Reviewer SDK or the
Amazon Web Services CLI to associate a GitHub repository with Amazon CodeGuru Reviewer. To
associate a GitHub repository, use the console. For more information, see Getting started
with CodeGuru Reviewer in the CodeGuru Reviewer User Guide.

# Arguments
- `repository`: The repository to associate.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ClientRequestToken"`: Amazon CodeGuru Reviewer uses this value to prevent the
  accidental creation of duplicate repository associations if there are failures and retries.
- `"KMSKeyDetails"`: A KMSKeyDetails object that contains:   The encryption option for this
  repository association. It is either owned by Amazon Web Services Key Management Service
  (KMS) (AWS_OWNED_CMK) or customer managed (CUSTOMER_MANAGED_CMK).   The ID of the Amazon
  Web Services KMS key that is associated with this respository association.
- `"Tags"`:  An array of key-value pairs used to tag an associated repository. A tag is a
  custom attribute label with two parts:    A tag key (for example, CostCenter, Environment,
  Project, or Secret). Tag keys are case sensitive.   An optional field known as a tag value
  (for example, 111122223333, Production, or a team name). Omitting the tag value is the same
  as using an empty string. Like tag keys, tag values are case sensitive.
"""
function associate_repository(Repository; aws_config::AbstractAWSConfig=global_aws_config())
    return codeguru_reviewer(
        "POST",
        "/associations",
        Dict{String,Any}(
            "Repository" => Repository, "ClientRequestToken" => string(uuid4())
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function associate_repository(
    Repository,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return codeguru_reviewer(
        "POST",
        "/associations",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "Repository" => Repository, "ClientRequestToken" => string(uuid4())
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_code_review(name, repository_association_arn, type)
    create_code_review(name, repository_association_arn, type, params::Dict{String,<:Any})

 Use to create a code review with a  CodeReviewType  of RepositoryAnalysis. This type of
code review analyzes all code under a specified branch in an associated repository.
PullRequest code reviews are automatically triggered by a pull request.

# Arguments
- `name`:  The name of the code review. The name of each code review in your Amazon Web
  Services account must be unique.
- `repository_association_arn`:  The Amazon Resource Name (ARN) of the
  RepositoryAssociation  object. You can retrieve this ARN by calling
  ListRepositoryAssociations .   A code review can only be created on an associated
  repository. This is the ARN of the associated repository.
- `type`:  The type of code review to create. This is specified using a  CodeReviewType
  object. You can create a code review only of type RepositoryAnalysis.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ClientRequestToken"`:  Amazon CodeGuru Reviewer uses this value to prevent the
  accidental creation of duplicate code reviews if there are failures and retries.
"""
function create_code_review(
    Name, RepositoryAssociationArn, Type; aws_config::AbstractAWSConfig=global_aws_config()
)
    return codeguru_reviewer(
        "POST",
        "/codereviews",
        Dict{String,Any}(
            "Name" => Name,
            "RepositoryAssociationArn" => RepositoryAssociationArn,
            "Type" => Type,
            "ClientRequestToken" => string(uuid4()),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_code_review(
    Name,
    RepositoryAssociationArn,
    Type,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return codeguru_reviewer(
        "POST",
        "/codereviews",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "Name" => Name,
                    "RepositoryAssociationArn" => RepositoryAssociationArn,
                    "Type" => Type,
                    "ClientRequestToken" => string(uuid4()),
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    describe_code_review(code_review_arn)
    describe_code_review(code_review_arn, params::Dict{String,<:Any})

 Returns the metadata associated with the code review along with its status.

# Arguments
- `code_review_arn`: The Amazon Resource Name (ARN) of the  CodeReview  object.

"""
function describe_code_review(
    CodeReviewArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return codeguru_reviewer(
        "GET",
        "/codereviews/$(CodeReviewArn)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function describe_code_review(
    CodeReviewArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return codeguru_reviewer(
        "GET",
        "/codereviews/$(CodeReviewArn)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    describe_recommendation_feedback(code_review_arn, recommendation_id)
    describe_recommendation_feedback(code_review_arn, recommendation_id, params::Dict{String,<:Any})

 Describes the customer feedback for a CodeGuru Reviewer recommendation.

# Arguments
- `code_review_arn`: The Amazon Resource Name (ARN) of the  CodeReview  object.
- `recommendation_id`:  The recommendation ID that can be used to track the provided
  recommendations and then to collect the feedback.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"UserId"`:  Optional parameter to describe the feedback for a given user. If this is not
  supplied, it defaults to the user making the request.   The UserId is an IAM principal that
  can be specified as an Amazon Web Services account ID or an Amazon Resource Name (ARN). For
  more information, see  Specifying a Principal in the Amazon Web Services Identity and
  Access Management User Guide.
"""
function describe_recommendation_feedback(
    CodeReviewArn, RecommendationId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return codeguru_reviewer(
        "GET",
        "/feedback/$(CodeReviewArn)",
        Dict{String,Any}("RecommendationId" => RecommendationId);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function describe_recommendation_feedback(
    CodeReviewArn,
    RecommendationId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return codeguru_reviewer(
        "GET",
        "/feedback/$(CodeReviewArn)",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("RecommendationId" => RecommendationId), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    describe_repository_association(association_arn)
    describe_repository_association(association_arn, params::Dict{String,<:Any})

 Returns a  RepositoryAssociation  object that contains information about the requested
repository association.

# Arguments
- `association_arn`:  The Amazon Resource Name (ARN) of the  RepositoryAssociation  object.
  You can retrieve this ARN by calling  ListRepositoryAssociations .

"""
function describe_repository_association(
    AssociationArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return codeguru_reviewer(
        "GET",
        "/associations/$(AssociationArn)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function describe_repository_association(
    AssociationArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return codeguru_reviewer(
        "GET",
        "/associations/$(AssociationArn)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    disassociate_repository(association_arn)
    disassociate_repository(association_arn, params::Dict{String,<:Any})

Removes the association between Amazon CodeGuru Reviewer and a repository.

# Arguments
- `association_arn`:  The Amazon Resource Name (ARN) of the  RepositoryAssociation  object.
  You can retrieve this ARN by calling  ListRepositoryAssociations .

"""
function disassociate_repository(
    AssociationArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return codeguru_reviewer(
        "DELETE",
        "/associations/$(AssociationArn)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function disassociate_repository(
    AssociationArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return codeguru_reviewer(
        "DELETE",
        "/associations/$(AssociationArn)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    list_code_reviews(type)
    list_code_reviews(type, params::Dict{String,<:Any})

 Lists all the code reviews that the customer has created in the past 90 days.

# Arguments
- `type`:  The type of code reviews to list in the response.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`:  The maximum number of results that are returned per call. The default is
  100.
- `"NextToken"`:  If nextToken is returned, there are more results available. The value of
  nextToken is a unique pagination token for each page. Make the call again using the
  returned token to retrieve the next page. Keep all other arguments unchanged.
- `"ProviderTypes"`:  List of provider types for filtering that needs to be applied before
  displaying the result. For example, providerTypes=[GitHub] lists code reviews from GitHub.
- `"RepositoryNames"`:  List of repository names for filtering that needs to be applied
  before displaying the result.
- `"States"`:  List of states for filtering that needs to be applied before displaying the
  result. For example, states=[Pending] lists code reviews in the Pending state.  The valid
  code review states are:    Completed: The code review is complete.     Pending: The code
  review started and has not completed or failed.     Failed: The code review failed.
  Deleting: The code review is being deleted.
"""
function list_code_reviews(Type; aws_config::AbstractAWSConfig=global_aws_config())
    return codeguru_reviewer(
        "GET",
        "/codereviews",
        Dict{String,Any}("Type" => Type);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_code_reviews(
    Type, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return codeguru_reviewer(
        "GET",
        "/codereviews",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("Type" => Type), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    list_recommendation_feedback(code_review_arn)
    list_recommendation_feedback(code_review_arn, params::Dict{String,<:Any})

 Returns a list of  RecommendationFeedbackSummary  objects that contain customer
recommendation feedback for all CodeGuru Reviewer users.

# Arguments
- `code_review_arn`: The Amazon Resource Name (ARN) of the  CodeReview  object.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`:  The maximum number of results that are returned per call. The default is
  100.
- `"NextToken"`:  If nextToken is returned, there are more results available. The value of
  nextToken is a unique pagination token for each page. Make the call again using the
  returned token to retrieve the next page. Keep all other arguments unchanged.
- `"RecommendationIds"`:  Used to query the recommendation feedback for a given
  recommendation.
- `"UserIds"`:  An Amazon Web Services user's account ID or Amazon Resource Name (ARN). Use
  this ID to query the recommendation feedback for a code review from that user.   The UserId
  is an IAM principal that can be specified as an Amazon Web Services account ID or an Amazon
  Resource Name (ARN). For more information, see  Specifying a Principal in the Amazon Web
  Services Identity and Access Management User Guide.
"""
function list_recommendation_feedback(
    CodeReviewArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return codeguru_reviewer(
        "GET",
        "/feedback/$(CodeReviewArn)/RecommendationFeedback";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_recommendation_feedback(
    CodeReviewArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return codeguru_reviewer(
        "GET",
        "/feedback/$(CodeReviewArn)/RecommendationFeedback",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    list_recommendations(code_review_arn)
    list_recommendations(code_review_arn, params::Dict{String,<:Any})

 Returns the list of all recommendations for a completed code review.

# Arguments
- `code_review_arn`: The Amazon Resource Name (ARN) of the  CodeReview  object.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`:  The maximum number of results that are returned per call. The default is
  100.
- `"NextToken"`:  Pagination token.
"""
function list_recommendations(
    CodeReviewArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return codeguru_reviewer(
        "GET",
        "/codereviews/$(CodeReviewArn)/Recommendations";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_recommendations(
    CodeReviewArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return codeguru_reviewer(
        "GET",
        "/codereviews/$(CodeReviewArn)/Recommendations",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    list_repository_associations()
    list_repository_associations(params::Dict{String,<:Any})

 Returns a list of  RepositoryAssociationSummary  objects that contain summary information
about a repository association. You can filter the returned list by  ProviderType ,  Name ,
 State , and  Owner .

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of repository association results returned by
  ListRepositoryAssociations in paginated output. When this parameter is used,
  ListRepositoryAssociations only returns maxResults results in a single page with a
  nextToken response element. The remaining results of the initial request can be seen by
  sending another ListRepositoryAssociations request with the returned nextToken value. This
  value can be between 1 and 100. If this parameter is not used, ListRepositoryAssociations
  returns up to 100 results and a nextToken value if applicable.
- `"Name"`: List of repository names to use as a filter.
- `"NextToken"`: The nextToken value returned from a previous paginated
  ListRepositoryAssociations request where maxResults was used and the results exceeded the
  value of that parameter. Pagination continues from the end of the previous results that
  returned the nextToken value.   Treat this token as an opaque identifier that is only used
  to retrieve the next items in a list and not for other programmatic purposes.
- `"Owner"`: List of owners to use as a filter. For Amazon Web Services CodeCommit, it is
  the name of the CodeCommit account that was used to associate the repository. For other
  repository source providers, such as Bitbucket and GitHub Enterprise Server, this is name
  of the account that was used to associate the repository.
- `"ProviderType"`: List of provider types to use as a filter.
- `"State"`: List of repository association states to use as a filter. The valid repository
  association states are:    Associated: The repository association is complete.
  Associating: CodeGuru Reviewer is:     Setting up pull request notifications. This is
  required for pull requests to trigger a CodeGuru Reviewer review.    If your repository
  ProviderType is GitHub, GitHub Enterprise Server, or Bitbucket, CodeGuru Reviewer creates
  webhooks in your repository to trigger CodeGuru Reviewer reviews. If you delete these
  webhooks, reviews of code in your repository cannot be triggered.      Setting up source
  code access. This is required for CodeGuru Reviewer to securely clone code in your
  repository.       Failed: The repository failed to associate or disassociate.
  Disassociating: CodeGuru Reviewer is removing the repository's pull request notifications
  and source code access.     Disassociated: CodeGuru Reviewer successfully disassociated the
  repository. You can create a new association with this repository if you want to review
  source code in it later. You can control access to code reviews created in an associated
  repository with tags after it has been disassociated. For more information, see Using tags
  to control access to associated repositories in the Amazon CodeGuru Reviewer User Guide.
"""
function list_repository_associations(; aws_config::AbstractAWSConfig=global_aws_config())
    return codeguru_reviewer(
        "GET", "/associations"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_repository_associations(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return codeguru_reviewer(
        "GET",
        "/associations",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    list_tags_for_resource(resource_arn)
    list_tags_for_resource(resource_arn, params::Dict{String,<:Any})

Returns the list of tags associated with an associated repository resource.

# Arguments
- `resource_arn`:  The Amazon Resource Name (ARN) of the  RepositoryAssociation  object.
  You can retrieve this ARN by calling  ListRepositoryAssociations .

"""
function list_tags_for_resource(
    resourceArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return codeguru_reviewer(
        "GET",
        "/tags/$(resourceArn)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_tags_for_resource(
    resourceArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return codeguru_reviewer(
        "GET",
        "/tags/$(resourceArn)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    put_recommendation_feedback(code_review_arn, reactions, recommendation_id)
    put_recommendation_feedback(code_review_arn, reactions, recommendation_id, params::Dict{String,<:Any})

 Stores customer feedback for a CodeGuru Reviewer recommendation. When this API is called
again with different reactions the previous feedback is overwritten.

# Arguments
- `code_review_arn`: The Amazon Resource Name (ARN) of the  CodeReview  object.
- `reactions`:  List for storing reactions. Reactions are utf-8 text code for emojis. If
  you send an empty list it clears all your feedback.
- `recommendation_id`:  The recommendation ID that can be used to track the provided
  recommendations and then to collect the feedback.

"""
function put_recommendation_feedback(
    CodeReviewArn,
    Reactions,
    RecommendationId;
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return codeguru_reviewer(
        "PUT",
        "/feedback",
        Dict{String,Any}(
            "CodeReviewArn" => CodeReviewArn,
            "Reactions" => Reactions,
            "RecommendationId" => RecommendationId,
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function put_recommendation_feedback(
    CodeReviewArn,
    Reactions,
    RecommendationId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return codeguru_reviewer(
        "PUT",
        "/feedback",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "CodeReviewArn" => CodeReviewArn,
                    "Reactions" => Reactions,
                    "RecommendationId" => RecommendationId,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    tag_resource(tags, resource_arn)
    tag_resource(tags, resource_arn, params::Dict{String,<:Any})

Adds one or more tags to an associated repository.

# Arguments
- `tags`:  An array of key-value pairs used to tag an associated repository. A tag is a
  custom attribute label with two parts:    A tag key (for example, CostCenter, Environment,
  Project, or Secret). Tag keys are case sensitive.   An optional field known as a tag value
  (for example, 111122223333, Production, or a team name). Omitting the tag value is the same
  as using an empty string. Like tag keys, tag values are case sensitive.
- `resource_arn`:  The Amazon Resource Name (ARN) of the  RepositoryAssociation  object.
  You can retrieve this ARN by calling  ListRepositoryAssociations .

"""
function tag_resource(Tags, resourceArn; aws_config::AbstractAWSConfig=global_aws_config())
    return codeguru_reviewer(
        "POST",
        "/tags/$(resourceArn)",
        Dict{String,Any}("Tags" => Tags);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function tag_resource(
    Tags,
    resourceArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return codeguru_reviewer(
        "POST",
        "/tags/$(resourceArn)",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("Tags" => Tags), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    untag_resource(resource_arn, tag_keys)
    untag_resource(resource_arn, tag_keys, params::Dict{String,<:Any})

Removes a tag from an associated repository.

# Arguments
- `resource_arn`:  The Amazon Resource Name (ARN) of the  RepositoryAssociation  object.
  You can retrieve this ARN by calling  ListRepositoryAssociations .
- `tag_keys`: A list of the keys for each tag you want to remove from an associated
  repository.

"""
function untag_resource(
    resourceArn, tagKeys; aws_config::AbstractAWSConfig=global_aws_config()
)
    return codeguru_reviewer(
        "DELETE",
        "/tags/$(resourceArn)",
        Dict{String,Any}("tagKeys" => tagKeys);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function untag_resource(
    resourceArn,
    tagKeys,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return codeguru_reviewer(
        "DELETE",
        "/tags/$(resourceArn)",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("tagKeys" => tagKeys), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end


text:
#=
Driver code for this SPECIFIC commit of Synaptor

(The current commit contains a good deal of hacks to make things work
 quickly. Once I update that repo, I can tailor this module to fit the new
 code)
=#

module Synaptor

"""

    make_cfg( seg_fname, output_prefix, seg_start )

Creates a Synaptor configuration file for the segmentation file passed,
and returns the pathname to it from base_dir. The pathname is currently
stamped with the date.

"""
function make_cfg( seg_fname, output_prefix, seg_start )

  cfg_fname = "$(output_prefix).cfg"

  open(cfg_fname, "w+") do f

    write(f, "#!/usr/bin/env julia\n" )
    write_field_line(f, "network_output_filename", "nothing" )
    write_field_line(f, "segmentation_filename", "\"$(seg_fname)\"" )
    write_field_line(f, "seg_dset_name", "\"/main\"" )
    write_field_line(f, "output_prefix", "\"$(output_prefix)\"" )
    write_field_line(f, "sem_incore", "false" )
    write_field_line(f, "seg_incore", "true" )
    write_field_line(f, "seg_start", "$seg_start" )
    write_field_line(f, "output_seg_shape", "[2048,2048,256]" )
    write_field_line(f, "seg_chunk_size", "[128,128,16]" )
    write_field_line(f, "scan_start_coord", "[1,1,1]" )
    write_field_line(f, "scan_end_coord", "[2048,2048,256]" )

  end #open

  cfg_fname
end

"""

    make_gc_cfg( seg_fname, output_prefix )

Makes a 2k cube cfg specific to the golden cube coordinates
"""
function make_gc_cfg( seg_fname, output_prefix )
  make_cfg(seg_fname, output_prefix, [19585,22657,4003])
end

"""

    write_field_line( f, field, val )

Writes a line of the format "field = val" to f
"""
function write_field_line( f, field, val )
  write(f, "$field = $val;\n")
end

"""

    run_cfg_file( cfg_file )

Runs main_ooc.jl on a configuration file
"""
function run_cfg_file( cfg_file )
  this_dir = dirname(@__FILE__)
  main_ooc = joinpath(this_dir,"Synaptor/src/main_ooc.jl")
  run(`julia $main_ooc $cfg_file`)
end

"""
Removes the mapping output file
"""
rm_mapping_file(prefix) = rm("$(prefix)_mapping.csv")
"""
Removes the seg output_file
"""
rm_seg_file(prefix) = rm("$(prefix)_seg.h5")

"""

    rm_duplicates( input_fname , out_fname, dist_thresh, res )

Runs the rm_duplicates script on an edge file, and saves
the results under out_fname.
"""
function rm_duplicates( input_fname, out_fname, dist_thresh, res )
  this_dir = dirname(@__FILE__)
  rm_dups = joinpath(this_dir,"Synaptor/src/rm_duplicates.jl")
  println("julia $rm_dups $input_fname $out_fname $dist_thresh $res")
  run(`julia $rm_dups $input_fname $out_fname $dist_thresh $res`)
end

end #module end


text:
__precompile__()

"""
# NoiseJul

A Julia module for seismological processing and analysis.
This module calls all submodules to perform seismological processing and analysis (data download, cross-correlation, noise monitoring etc.)
Each document can be found in their github repository.

- "IO" => "SeisIO",
- "Noise" => "SeisNoise",
- "Download" => "https://github.com/kura-okubo/SeisDownload",
- "Convert" => "https://github.com/xtyangpsp/SeisConvert.jl.git",
- #currently NOT available "Xcorrelation" => "https://github.com/jaredbryan881/SeisXcorrelation.jl",
- "RemoveEQ" => "https://github.com/kura-okubo/SeisRemoveEQ.jl",
- "Beamforming" => "https://github.com/kura-okubo/SeisBeamforming.jl.git")

## example:
S = NoiseJul.IO.SeisData()

Copyright (c) 2019 Harvard University Earthquake Seismology Group. All Rights Reserved.
"""
module NoiseJul

module IO
using SeisIO
for n in names(SeisIO, all=true)
    if Base.isidentifier(n) && n ∉ (Symbol(SeisIO), :eval)
        eval(Expr(:export, n))
    end
end
end

module Noise
using SeisNoise
for n in names(SeisNoise, all=true)
    if Base.isidentifier(n) && n ∉ (Symbol(SeisNoise), :eval)
        eval(Expr(:export, n))
    end
end
end

module Download
using SeisDownload
for n in names(SeisDownload, all=true)
    if Base.isidentifier(n) && n ∉ (Symbol(SeisDownload), :eval)
        eval(Expr(:export, n))
    end
end
end

module Convert
using SeisConvert
for n in names(SeisConvert, all=true)
    if Base.isidentifier(n) && n ∉ (Symbol(SeisConvert), :eval)
        eval(Expr(:export, n))
    end
end
end

module RemoveEQ
using SeisRemoveEQ
for n in names(SeisRemoveEQ, all=true)
    if Base.isidentifier(n) && n ∉ (Symbol(SeisRemoveEQ), :eval)
        eval(Expr(:export, n))
    end
end
end

module Beamforming
using SeisBeamforming
for n in names(SeisBeamforming, all=true)
    if Base.isidentifier(n) && n ∉ (Symbol(SeisBeamforming), :eval)
        eval(Expr(:export, n))
    end
end
end

end # module


text:
module HW

using LightGraphs, MetaGraphs
using MacroTools

export AbstractHandler
export @circuit

include("netlist.jl")
include("handler.jl")
include("module.jl")
include("circuit.jl")

end


text:
# Copyright 2018 Erik Edin
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

module Behavior

include("Gherkin.jl")
include("Selection.jl")

"Abstraction for presenting results from scenario steps."
abstract type Presenter end

"Presenting results from scenario steps as they occur."
abstract type RealTimePresenter <: Presenter end

include("stepdefinitions.jl")
include("exec_env.jl")
include("executor.jl")
include("asserts.jl")
include("presenter.jl")
include("terse_presenter.jl")
include("result_accumulator.jl")
include("engine.jl")
include("runner.jl")

export @given, @when, @then, @expect, @fail, @beforescenario, @afterscenario, runspec
export @beforefeature, @afterfeature, @beforeall, @afterall
export suggestmissingsteps
export TerseRealTimePresenter, ColorConsolePresenter

end # module


text:
### Fetch required packages and reaction networks ###
using Catalyst, Latexify

############################
### CURRENTLY NOT ACITVE ###
### REQUIRES REWRITING   ###
############################

### Tips for generating latex tests:
### Latexify has an unexported macro:
###
### Latexify.@generate_test
###
### which generates a test using a given latexify function.
### For example:
###
### Latexify.@generate_test latexify([1, 2, 3], [4, 5, 6]; env=:mdtable)
###
### This puts a ready-made test in your clipboard which you can paste into the
### test file.
###
### Just be sure to remove all such macros before you commit a change since it
### will cause issues with Travis.

r = @reaction_network begin
    hillr(X2,v1,K1,n1)*hill(X4,v1,K1,n1), ∅ → X1
    hill(X5,v2,K2,n2), ∅ → X2
    hill(X3,v3,K3,n3), ∅ → X3
    hillr(X1,v4,K4,n4), ∅ → X4
    hill(X2,v5,K5,n5), ∅ → X5
    (k1,k2), X2 ⟷ X1 + 2X4
    (k3,k4), X4 ⟷ X3
    (k5,k6), 3X5 + X1 ⟷ X2
    (d1,d2,d3,d4,d5), (X1,X2,X3,X4,X5)  ⟶ ∅
end v1 K1 n1 v2 K2 n2 v3 K3 n3 v4 K4 n4 v5 K5 n5 k1 k2 k3 k4 k5 k6 d1 d2 d3 d4 d5

# Latexify.@generate_test latexify(r)
@test latexify(r) == replace(
raw"\begin{align}
\require{mhchem}
\ce{ \varnothing &->[\frac{v1 \left( \mathrm{X4}\left( t \right) \right)^{n1}}{K1^{n1} + \left( \mathrm{X4}\left( t \right) \right)^{n1}} \frac{v1 K1^{n1}}{K1^{n1} + \left( \mathrm{X2}\left( t \right) \right)^{n1}}] X1}\\
\ce{ \varnothing &->[\frac{v2 \left( \mathrm{X5}\left( t \right) \right)^{n2}}{K2^{n2} + \left( \mathrm{X5}\left( t \right) \right)^{n2}}] X2}\\
\ce{ \varnothing &->[\frac{v3 \left( \mathrm{X3}\left( t \right) \right)^{n3}}{K3^{n3} + \left( \mathrm{X3}\left( t \right) \right)^{n3}}] X3}\\
\ce{ \varnothing &->[\frac{v4 K4^{n4}}{K4^{n4} + \left( \mathrm{X1}\left( t \right) \right)^{n4}}] X4}\\
\ce{ \varnothing &->[\frac{v5 \left( \mathrm{X2}\left( t \right) \right)^{n5}}{K5^{n5} + \left( \mathrm{X2}\left( t \right) \right)^{n5}}] X5}\\
\ce{ X2 &<=>[k1][k2] X1 + 2 X4}\\
\ce{ X4 &<=>[k3][k4] X3}\\
\ce{ 3 X5 + X1 &<=>[k5][k6] X2}\\
\ce{ X1 &->[d1] \varnothing}\\
\ce{ X2 &->[d2] \varnothing}\\
\ce{ X3 &->[d3] \varnothing}\\
\ce{ X4 &->[d4] \varnothing}\\
\ce{ X5 &->[d5] \varnothing}
\end{align}
", "\r\n"=>"\n")

# Latexify.@generate_test latexify(r, mathjax=false)
@test latexify(r, mathjax = false) == replace(
raw"\begin{align}
\ce{ \varnothing &->[$\frac{v1 \left( \mathrm{X4}\left( t \right) \right)^{n1}}{K1^{n1} + \left( \mathrm{X4}\left( t \right) \right)^{n1}} \frac{v1 K1^{n1}}{K1^{n1} + \left( \mathrm{X2}\left( t \right) \right)^{n1}}$] X1}\\
\ce{ \varnothing &->[$\frac{v2 \left( \mathrm{X5}\left( t \right) \right)^{n2}}{K2^{n2} + \left( \mathrm{X5}\left( t \right) \right)^{n2}}$] X2}\\
\ce{ \varnothing &->[$\frac{v3 \left( \mathrm{X3}\left( t \right) \right)^{n3}}{K3^{n3} + \left( \mathrm{X3}\left( t \right) \right)^{n3}}$] X3}\\
\ce{ \varnothing &->[$\frac{v4 K4^{n4}}{K4^{n4} + \left( \mathrm{X1}\left( t \right) \right)^{n4}}$] X4}\\
\ce{ \varnothing &->[$\frac{v5 \left( \mathrm{X2}\left( t \right) \right)^{n5}}{K5^{n5} + \left( \mathrm{X2}\left( t \right) \right)^{n5}}$] X5}\\
\ce{ X2 &<=>[$k1$][$k2$] X1 + 2 X4}\\
\ce{ X4 &<=>[$k3$][$k4$] X3}\\
\ce{ 3 X5 + X1 &<=>[$k5$][$k6$] X2}\\
\ce{ X1 &->[$d1$] \varnothing}\\
\ce{ X2 &->[$d2$] \varnothing}\\
\ce{ X3 &->[$d3$] \varnothing}\\
\ce{ X4 &->[$d4$] \varnothing}\\
\ce{ X5 &->[$d5$] \varnothing}
\end{align}
", "\r\n"=>"\n")

r = @reaction_network begin
    (hill(B, p_a, k, n), d_a), 0 ↔ A
    (p_b, d_b), 0 ↔ B
    (r_a, r_b), 3B ↔ A
end p_a k n d_a p_b d_b r_a r_b

# Latexify.@generate_test latexify(r)
@test latexify(r) == replace(
raw"\begin{align}
\require{mhchem}
\ce{ \varnothing &<=>[\frac{p_{a} \left( B\left( t \right) \right)^{n}}{k^{n} + \left( B\left( t \right) \right)^{n}}][d_{a}] A}\\
\ce{ \varnothing &<=>[p_{b}][d_{b}] B}\\
\ce{ 3 B &<=>[r_{a}][r_{b}] A}
\end{align}
", "\r\n"=>"\n")

# Latexify.@generate_test latexify(r, mathjax=false)
@test latexify(r, mathjax = false) == replace(
raw"\begin{align}
\ce{ \varnothing &<=>[$\frac{p_{a} \left( B\left( t \right) \right)^{n}}{k^{n} + \left( B\left( t \right) \right)^{n}}$][$d_{a}$] A}\\
\ce{ \varnothing &<=>[$p_{b}$][$d_{b}$] B}\\
\ce{ 3 B &<=>[$r_{a}$][$r_{b}$] A}
\end{align}
", "\r\n"=>"\n")


text:
using Documenter, PotentialFlow

makedocs(
    sitename = "PotentialFlow.jl",
    pages = [
        "Home" => "index.md",
        "Manual" => ["manual/quickstart.md",
                     "manual/elements.md",
                     "manual/velocities.md",
                     "manual/timemarching.md",
                     "manual/noflowthrough.md",
                     "manual/motions.md"
                     ],
        "Internals" => [ "internals/properties.md"]
    ],
    format = Documenter.HTML(assets = ["assets/custom.css"]),
#   strict = true
)

if "DOCUMENTER_KEY" in keys(ENV)
    deploydocs(;
     repo = "github.com/darwindarak/PotentialFlow.jl.git",
    )
end


text:
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).
# Since these FMAs can increase the performance of many numerical algorithms,
# we need to opt-in explicitly.
# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.
@muladd begin

# Initialize node_indices of MPI interface container
@inline function init_mpi_interface_node_indices!(mpi_interfaces::P4estMPIInterfaceContainer{3},
                                                  faces, local_side, orientation,
                                                  mpi_interface_id)
  # Align interface at the primary element (primary element has surface indices (:i_forward, :j_forward)).
  # The secondary element needs to be indexed differently.
  if local_side == 1
    surface_index1 = :i_forward
    surface_index2 = :j_forward
  else # local_side == 2
    surface_index1, surface_index2 = orientation_to_indices_p4est(faces[2], faces[1], orientation)
  end

  if faces[local_side] == 0
    # Index face in negative x-direction
    mpi_interfaces.node_indices[mpi_interface_id] = (:begin, surface_index1, surface_index2)
  elseif faces[local_side] == 1
    # Index face in positive x-direction
    mpi_interfaces.node_indices[mpi_interface_id] = (:end, surface_index1, surface_index2)
  elseif faces[local_side] == 2
    # Index face in negative y-direction
    mpi_interfaces.node_indices[mpi_interface_id] = (surface_index1, :begin, surface_index2)
  elseif faces[local_side] == 3
    # Index face in positive y-direction
    mpi_interfaces.node_indices[mpi_interface_id] = (surface_index1, :end, surface_index2)
  elseif faces[local_side] == 4
    # Index face in negative z-direction
    mpi_interfaces.node_indices[mpi_interface_id] = (surface_index1, surface_index2, :begin)
  else # faces[local_side] == 5
    # Index face in positive z-direction
    mpi_interfaces.node_indices[mpi_interface_id] = (surface_index1, surface_index2, :end)
  end

  return mpi_interfaces
end

end # muladd


text:
using StochasticDelayDiffEq, DiffEqDevTools
using Test

#Hayes Equation
begin
    function hayes_modelf(du,u,h,p,t)
        τ,a,b,c,α,β,γ = p
        du .= a.*u .+ b .* h(p,t-τ) .+ c
    end
    function hayes_modelg(du,u,h,p,t)
        τ,a,b,c,α,β,γ = p
        du .= α.*u .+ γ
    end
    h(p,t) = (ones(1) .+ t);
    tspan = (0.,10.)
end

pmul = [1.0,-4.,-2.,10.,-1.3,-1.2, 1.1]
padd = [1.0,-4.,-2.,10.,-0.0,-0.0, 0.1]

prob = @test_nowarn SDDEProblem(hayes_modelf, hayes_modelg, [1.], h, tspan, pmul; constant_lags = (pmul[1],));
@test_nowarn SDDEProblem(hayes_modelf, hayes_modelg, h, tspan, padd; constant_lags = (padd[1],));

dts = (1/2).^(8:-1:4)
test_dt = 1/2^9
sim2 = analyticless_test_convergence(dts,prob,EM(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-0.5) < 0.3
sim2 = analyticless_test_convergence(dts,prob,LambaEM(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-0.5) < 0.3
sim2 = analyticless_test_convergence(dts,prob,EulerHeun(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,LambaEulerHeun(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,RKMil(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,RKMil(interpretation=:Stratonovich),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,WangLi3SMil_A(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,WangLi3SMil_B(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,WangLi3SMil_C(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,WangLi3SMil_D(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,WangLi3SMil_E(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,WangLi3SMil_F(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3

# Test SROCK methods
println("SROCK methods")
prob.p .= pmul;
sim2 = analyticless_test_convergence(dts,prob,SROCK1(),test_dt,trajectories=100, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,SROCK1(interpretation=:Stratonovich),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,SROCKEM(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,SROCKEM(strong_order_1=false),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-0.5) < 0.3
sim2 = analyticless_test_convergence(dts,prob,SKSROCK(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-0.5) < 0.3
sim2 = analyticless_test_convergence(dts,prob,SKSROCK(;post_processing=true),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-0.5) < 0.3

# Test Implicit methods
println("implicit methods")
sim2 = analyticless_test_convergence(dts,prob,ImplicitEM(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-0.5) < 0.3
sim2 = analyticless_test_convergence(dts,prob,ImplicitEM(symplectic=true, theta = 1/2),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-0.5) < 0.3
sim2 = analyticless_test_convergence(dts,prob,ImplicitEulerHeun(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,ImplicitEulerHeun(symplectic=true, theta = 1/2),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,ISSEM(),test_dt,trajectories=1000, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-0.5) < 0.3
sim2 = analyticless_test_convergence(dts,prob,ISSEM(symplectic=true, theta = 1/2),test_dt,trajectories=500, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-0.5) < 0.3
sim2 = analyticless_test_convergence(dts,prob,ImplicitRKMil(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,ImplicitRKMil(symplectic=true, theta = 1/2),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,ImplicitRKMil(interpretation=:Stratonovich, symplectic = true, theta = 1/2),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,ISSEulerHeun(),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3
sim2 = analyticless_test_convergence(dts,prob,ISSEulerHeun(symplectic=true, theta = 1/2),test_dt,trajectories=300, use_noise_grid=false)
@test abs(sim2.𝒪est[:final]-1.0) < 0.3


text:
module Zilindroa

#Julia Libs
using LinearAlgebra
using LinearAlgebra.BLAS
using DifferentialEquations
using SparseArrays
using Dates
using Parameters
using HDF5
using DelimitedFiles
using ProgressMeter

#Import structures
include("./structs/Operators.jl")
include("./structs/Parameters.jl")

#Operators
include("./operators/differential_operator.jl")
include("./operators/BC_operators.jl")

#Simulation helpers
include("./sim_utils/get_gaussian_pulse.jl")

include("./sim_utils/setup_operators.jl")
include("./sim_utils/setup_folders.jl")

include("./sim_utils/save_parameters_to_file.jl")

include("./sim_utils/print_parameters_to_screen.jl")

include("./sim_utils/time_to_seconds.jl")
include("./sim_utils/exit_message.jl")
include("./sim_utils/welcome_message.jl")

#Solvers
include("./solvers/Zilindroa_solver.jl")

#Data analysis aids
include("./data_read_utils/get_field_energy.jl")
#include("./data_read_utils/get_field_point.jl")
#include("./data_read_utils/get_field_slice.jl")
include("./data_read_utils/get_fields.jl")
include("./data_read_utils/get_time_variables.jl")
#include("./data_read_utils/get_space_variables.jl")

#template runs
include("./template_runs/simple_run.jl")

export run_Zilindroa
export get_time_variables , get_field_energy , get_fields
#get_field_point, get_field_slice, get_fields

end


text:
# `partial(F, Ts...)`: called by the top-level tracer and allowed to directly
# evaluate side effects.

# `mutate(MutCtx, F, Ts...)`: called by the abstract interpreter, and allowed
# to abstractly interpret side effects.

# `abstract(F, Ts...)`: Side-effect-agnostic fallback, called by both stages of
# compilation.

# P is the set of primitives in use.

instead(P, args, Ts...) = nothing
abstract(P, Ts...) = nothing
partial(P, Ts...) = abstract(P, Ts...)
mutate(P, context, Ts...) = abstract(P, Ts...)

function something(f, xs)
  for x in xs
    y = f(x)
    y === nothing || return y
  end
  return
end

struct Multi{Ps<:Tuple}
  ps::Ps
  Multi(ps...) = new{typeof(ps)}(ps)
end

instead(m::Multi, args, Ts...) = something(p -> instead(p, args, Ts...), m.ps)
abstract(m::Multi, Ts...) = something(p -> abstract(p, Ts...), m.ps)
partial(m::Multi, Ts...)  = something(p ->  partial(p, Ts...), m.ps)
mutate(m::Multi, cx, Ts...)  = something(p ->  mutate(p, cx, Ts...), m.ps)

Defaults() = Multi(Basic(), Numeric())


text:
# Automatically generated
struct VirtualForce{F1<:Function,F2<:Function,F3<:Function,F4<:Function}
    vrx1::F1
    vry1::F2
    vrx2::F3
    vry2::F4
end

struct Params{T,F1<:Function,F2<:Function,F3<:Function,F4<:Function,F5<:Function,F6<:Function,F7<:Function,F8<:Function,F9<:Function,F10<:Function,F11<:Function,F12<:Function,F13<:Function,F14<:Function,F15<:Function}
    z::Vector{Float64}
    ea::F1
    fa::F2
    gs::F3
    ha::F4
    ia::F5
    eap::F6
    fap::F7
    gsp::F8
    hap::F9
    iap::F10
    eapp::F11
    fapp::F12
    gspp::F13
    happ::F14
    iapp::F15
    ae::TorqueGenerator
    af::TorqueGenerator
    footang::T
    g::T
    he::TorqueGenerator
    hf::TorqueGenerator
    ina::T
    inb::T
    inc::T
    ind::T
    ine::T
    inf::T
    ing::T
    inh::T
    ini::T
    k1::T
    k2::T
    k3::T
    k4::T
    k5::T
    k6::T
    k7::T
    k8::T
    ke::TorqueGenerator
    kf::TorqueGenerator
    l1::T
    l10::T
    l11::T
    l2::T
    l3::T
    l4::T
    l5::T
    l6::T
    l7::T
    l8::T
    l9::T
    ma::T
    mb::T
    mc::T
    md::T
    me::T
    mf::T
    mg::T
    mh::T
    mi::T
    mtpb::T
    mtpk::T
    pop1xi::T
    pop2xi::T
    mt::T
    u8::T
    u9::T
    u10::T
    u11::T
    virtual_force::VirtualForce
end

# initialise with constant values
function Params(ea, fa, gs, ha, ia, eap, fap, gsp, hap, iap, eapp, fapp, gspp, happ, iapp, ae, af, footang, g, he, hf, ina, inb, inc, ind, ine, inf, ing, inh, ini, k1, k2, k3, k4, k5, k6, k7, k8, ke, kf, l1, l10, l11, l2, l3, l4, l5, l6, l7, l8, l9, ma, mb, mc, md, me, mf, mg, mh, mi, mtpb, mtpk, pop1xi, pop2xi)
    z = Vector{Float64}(undef, 884)
    mt = ma + mb + mc + md + me + mf + mg
    u8 = 0.0
    u9 = 0.0
    u10 = 0.0
    u11 = 0.0

    virtual_force = VirtualForce(t -> 0.0, t -> 0.0, t -> 0.0, t -> 0.0)

    z[21] = l10 - l9
    z[394] = g * me
    z[749] = z[21] * z[394]
    z[846] = inf + inh + ini
    z[22] = l8 - l7
    z[677] = mf * z[22]
    z[857] = inh + ini
    z[26] = l2 - l1
    z[727] = mi * z[26]
    z[7] = cos(footang)
    z[8] = sin(footang)
    z[23] = l6 - l4
    z[24] = 0.5l6 + 0.5 * z[23]
    z[25] = 0.5l3 - 0.5l5
    z[75] = ma + mb + mc + md + me + mf + mg + mh + mi
    z[76] = (l1 * ma + l2 * mb + l2 * mc + l2 * md + l2 * me + l2 * mf + l2 * mg + l2 * mh + l2 * mi) / z[75]
    z[77] = (l4 * mb + 2 * l6 * mc + 2 * l6 * md + 2 * l6 * me + 2 * l6 * mf + 2 * l6 * mg + 2 * l6 * mh + 2 * l6 * mi) / z[75]
    z[78] = (l7 * mc + l8 * md + l8 * me + l8 * mf + l8 * mg + l8 * mh + l8 * mi) / z[75]
    z[79] = (l10 * me + l10 * mf + l10 * mg + l10 * mh + l10 * mi + l9 * md) / z[75]
    z[80] = (l10 * mf + l10 * mh + l10 * mi + me * z[21]) / z[75]
    z[81] = (l8 * mh + l8 * mi + mf * z[22]) / z[75]
    z[83] = (l6 * mi + mh * z[24]) / z[75]
    z[84] = (mi * z[26]) / z[75]
    z[85] = (mh * z[25]) / z[75]
    z[86] = (l3 * mb) / z[75]
    z[87] = ma + mb + mc + md
    z[88] = (l1 * ma + l2 * mb + l2 * mc + l2 * md) / z[87]
    z[89] = (l4 * mb + 2 * l6 * mc + 2 * l6 * md) / z[87]
    z[90] = (l7 * mc + l8 * md) / z[87]
    z[91] = (l9 * md) / z[87]
    z[92] = (l3 * mb) / z[87]
    z[93] = me + mf + mh + mi
    z[94] = (l2 * (me + mf + mh + mi)) / z[93]
    z[95] = (l6 * (me + mf + mh + mi)) / z[93]
    z[96] = (l8 * (me + mf + mh + mi)) / z[93]
    z[97] = (l10 * (me + mf + mh + mi)) / z[93]
    z[98] = (l10 * mf + l10 * mh + l10 * mi + me * z[21]) / z[93]
    z[99] = (l8 * mh + l8 * mi + mf * z[22]) / z[93]
    z[100] = (l6 * mi + mh * z[24]) / z[93]
    z[101] = (mi * z[26]) / z[93]
    z[102] = (mh * z[25]) / z[93]
    z[390] = g * ma
    z[391] = g * mb
    z[392] = g * mc
    z[393] = g * md
    z[395] = g * mf
    z[396] = g * mg
    z[397] = g * mh
    z[398] = g * mi
    z[438] = z[76] - l1
    z[443] = z[76] - l2
    z[444] = 0.5l4 - 0.5 * z[77]
    z[445] = 0.5l3 - 0.5 * z[86]
    z[516] = 2l6 - z[77]
    z[517] = l2 - z[76]
    z[538] = l8 - z[78]
    z[554] = l10 - z[79]
    z[562] = l10 - z[80]
    z[567] = l6 - 0.5 * z[77]
    z[569] = l8 - z[81]
    z[570] = z[24] - z[83]
    z[571] = z[25] - z[85]
    z[578] = l6 - z[83]
    z[587] = z[444] + z[7] * z[445]
    z[589] = z[445] + z[7] * z[444]
    z[600] = z[7] * z[86]
    z[610] = 2 * z[570] + 2 * z[7] * z[571]
    z[612] = 2 * z[571] + 2 * z[7] * z[570]
    z[618] = l1 * ma
    z[623] = l2 * mb
    z[626] = l4 * mb
    z[627] = l3 * mb
    z[659] = me * z[21]
    z[687] = l2 * mg
    z[688] = l6 * mg
    z[689] = l8 * mg
    z[690] = l10 * mg
    z[702] = l8 * mh
    z[712] = mh * z[24]
    z[714] = mh * z[25]
    z[741] = l1 * z[390]
    z[743] = l2 * z[391]
    z[744] = l2 * z[396]
    z[751] = z[22] * z[395]
    z[754] = z[26] * z[398]
    z[787] = ina + inb + inc + ind + ine + inf + ing + inh + ini + ma * l1^2
    z[788] = l3^2 + l4^2 + 4 * l2^2 + 2 * l3 * l4 * z[7]
    z[789] = l2 * l3
    z[790] = l2 * l4
    z[791] = z[24]^2
    z[792] = z[25]^2
    z[793] = z[7] * z[24] * z[25]
    z[794] = l10 * l2
    z[795] = l2 * l6
    z[796] = l2 * l8
    z[797] = l10^2
    z[798] = l2^2
    z[799] = l6^2
    z[800] = l8^2
    z[801] = l10 * l6
    z[802] = l10 * l8
    z[803] = l6 * l8
    z[805] = ma * l1^2
    z[810] = l3 * z[8]
    z[811] = l4 * z[8]
    z[812] = z[7] * z[24]
    z[813] = z[7] * z[25]
    z[814] = z[8] * z[25]
    z[815] = z[8] * z[24]
    z[817] = ina + ma * l1^2 + mb * l2^2 + mg * l2^2
    z[819] = ina + ma * l1^2
    z[824] = ina + inb + ma * l1^2
    z[825] = l2^2 + l6^2
    z[830] = ina + inb + inc + ma * l1^2
    z[834] = ina + inb + inc + ind + ma * l1^2
    z[837] = ine + inf + inh + ini
    z[847] = l8 * z[24]
    z[848] = l8 * z[25]

    return Params(z, ea, fa, gs, ha, ia, eap, fap, gsp, hap, iap, eapp, fapp, gspp, happ, iapp, ae, af, footang, g, he, hf, ina, inb, inc, ind, ine, inf, ing, inh, ini, k1, k2, k3, k4, k5, k6, k7, k8, ke, kf, l1, l10, l11, l2, l3, l4, l5, l6, l7, l8, l9, ma, mb, mc, md, me, mf, mg, mh, mi, mtpb, mtpk, pop1xi, pop2xi, mt, u8, u9, u10, u11, virtual_force)
end


text:
@testset "Read GFA" begin
    g_test = SimpleDiGraph(7)
    add_edge!(g_test, 1, 2)
    add_edge!(g_test, 2, 3)
    add_edge!(g_test, 3, 4)
    add_edge!(g_test, 4, 5)
    add_edge!(g_test, 5, 6)
    add_edge!(g_test, 7, 2)
    w_test = [Weight(7, 10),
    Weight(4, 10),
    Weight(2, 44),
    Weight(3, 2),
    Weight(5, 1),
    Weight(6, 11),
    Weight(1, 2)
    ]
    l_test = [NodeLabel(7, "4\t-", "TACAGGGTGA", ""),
    NodeLabel(4, "4\t+", "TACAGGGTGA", ""),
    NodeLabel(2, "2\t+", "TTAACTCCATCTTTGAGAAACATTTAATAATGTAATGTGTTTGT", ""),
    NodeLabel(3, "3\t+", "CA", ""),
    NodeLabel(5, "5\t+", "A", ""),
    NodeLabel(6, "6\t+", "TACAGATGCAC", ""),
    NodeLabel(1, "1\t+", "AT", "")
    ]
    e_test = [EdgeLabel("2\t+", "3\t+", "0M", ""),
    EdgeLabel("4\t-", "2\t+", "0M", ""),
    EdgeLabel("1\t+", "2\t+", "0M", ""),
    EdgeLabel("5\t+", "6\t+", "0M", ""),
    EdgeLabel("4\t+", "5\t+", "0M", ""),
    EdgeLabel("3\t+", "4\t+", "0M", "")
    ]
    gfa_result = read_from_gfa("data/gfa_sample_1.gfa");
    g = gfa_result.g
    w = gfa_result.w
    l = gfa_result.l
    e = gfa_result.e
    @test g == g_test
    @test w == w_test
    @test e == e_test
    @test l == l_test
end

@testset "Read GFA with weight" begin
    w_test = [Weight(7, 4),
    Weight(4, 4),
    Weight(2, 7),
    Weight(3, 6),
    Weight(5, 11),
    Weight(6, 52),
    Weight(1, 2)
    ]
    gfa_result = read_from_gfa("data/gfa_sample_1.gfa"; weight_file = "data/weight.csv")
    w = gfa_result.w
    @test w == w_test
end


text:
module MethodLists

using InteractiveUtils
using SparseArrays, LinearAlgebra

export collect_ml, basetype, supertypes, functions
export shortname, format

"""
    collect_ml(T::type; fun=nothing, up=T)

Return list of method with type `T` for function `fun`, `T` is restricted by `T <: up`.
Similar to methodswith, restricting types by upper bound.
"""
function collect_ml(T::Type; fun=nothing, up=Any)
    ml = Set{Method}()
    Y = up
    meli(T, ::Nothing) = methodswith(T; supertypes=true)
    meli(T, f) = methodswith(T, f; supertypes=true)

    res = Method[]
    for m in meli(T, fun)
        for P in basetype(m.sig).parameters
            if T <: P <: Y
                push!(res, m)
                break
            end
        end
    end
    res
end

function supertypes(T::Type)
    X = supertype(T)
    if X === T
        [T,]
    else
        [T, supertypes(X)...]
    end
end

basetype(u::UnionAll) = basetype(u.body)
basetype(a::Type) = a

function collect_ml(;fun=nothing)
    mlma = collect_ml(AbstractMatrix; fun=fun)
    mlms = collect_ml(SparseMatrixCSC; fun=fun, up=AbstractSparseArray)
    mlva = collect_ml(AbstractVector; fun=fun)
    mlvs = collect_ml(SparseVector; fun=fun,up=AbstractSparseArray)
    mlma, mlms, mlva, mlvs
end

function functions(mla)
    unique!([m.name for m in mla])
end

shortfile(s::Symbol) = shortfile(string(s))
function shortfile(f::String)
    r = findlast("/src/", f)
    if r !== nothing && !isempty(r)
        s = findlast("/", SubString(f, 1:first(r)-1))
        f[first(s)+1:first(r)] * f[last(r):end]
    else
        f
    end
end
function format(m::Method)
    argt = shortname.(basetype(m.sig).parameters[2:end])
    string(m.name, "(", join(argt, ", "), ") -> ", shortfile(m.file), ":", m.line)
end

shortname(d) = string(d)
shortname(::Type{Any}) = "_"
shortname(t::Core.TypeVar) = shortname(t.ub)
function shortname(d::DataType)
    name = string(d.name.name)
    par = shortname.(d.parameters)
    if all(isequal("_"), par)
        par = String[]
    end
    if length(par) > 3
        resize!(par, 4)
        par[4] = ".."
    end
    return isempty(par) ? name : string(name, "{", join(par, ","), "}")
end

shortname(d::UnionAll) = shortname(d.body)
function shortname(u::Union)
    un = unames(u)
    if length(un) > 2
        resize!(un, 3)
        un[3] = "..."
    end
    string("Union{", join(un, ","), "}")
end
unames(d) = shortname(d)
unames(u::Union) = unique(vcat(unames(u.a), unames(u.b)))

end # module