text:
using PubChemCrawler
using CSV
using JSON3
using DataFrames
using BrokenRecord: BrokenRecord, playback
using HTTP    # needed to make BSON happy upon playback
using Test

## NOTE: the interactions with PubChem are recorded using BrokenRecord and stored in the test/http_record
## directory. If you want to check that this still works with the "real" PubChem server, just delete
## that directory and re-run the tests.

const allrecordings = [joinpath("http_record", file) for file in [
    "estriol_cid.bson",
    "aspirin_cid_from_smiles.bson",
    "estriol_substructure.bson",
    "smarts.bson",
    "smarts_pug.bson",
    "aspirin_smiles_from_cid.bson",
    "estriol_substructure_formulas.bson",
    "asprin_sdf_3d.bson",
    "cGMP_cid.bson",
    "aspirin_cid_from_name.bson",
    "CAS_as_json.bson",
    "CAS_as_txt.bson"
]]
const get_recordings = !all(isfile, allrecordings)

if !isdir("http_record")
    mkdir("http_record")
end
BrokenRecord.configure!(; path="http_record")

@testset "PubChemCrawler.jl" begin
    # Note that PubChem limits requests to no more than 5 per second, so we need to introduce delays in the tests.
    # Moreover, multiple tests being run simultaneously by GitHubActions may count as originating from the same place,
    # so let's be quite conservative about the delays.
    cid_estriol = playback(() -> get_cid(;name="estriol"), "estriol_cid.bson")
    @test cid_estriol == 5756
    sleep(2.0 * get_recordings)
    @test playback(() -> get_cid(smiles="CC(=O)OC1=CC=CC=C1C(=O)O"), "aspirin_cid_from_smiles.bson") == 2244

    # substructure search
    sleep(2.0 * get_recordings)
    df = CSV.File(playback(() -> query_substructure(;cid=cid_estriol, output="CSV"), "estriol_substructure.bson")) |> DataFrame
    @test 27125 ∈ df.CID   # check that estetrol has estriol as a substructure
    sleep(2.0 * get_recordings)
    df13 = CSV.File(playback(() -> query_substructure(;smarts="[r13]Br", output="CSV"), "smarts.bson")) |> DataFrame  # brominated 13-atom ring structures
    @test 153064026 ∈ df13.CID
    # The recommended approach for substructure searches is `query_substructure_pug`
    sleep(5.0 * get_recordings)
    cids13 = playback(() -> query_substructure_pug(;smarts="[r13]Br", poll_interval=10*get_recordings), "smarts_pug.bson")  # brominated 13-atom ring structures, via PUG interface
    @test 153064026 ∈ cids13

    # properties
    sleep(5.0 * get_recordings)
    smiles = String(playback(() -> get_for_cids(2244, properties="CanonicalSMILES", output="TXT"), "aspirin_smiles_from_cid.bson"))
    @test chomp(smiles) == "CC(=O)OC1=CC=CC=C1C(=O)O"
    sleep(5.0 * get_recordings)
    df2 = CSV.File(playback(() -> get_for_cids(df.CID[1:2]; properties="MolecularFormula"), "estriol_substructure_formulas.bson")) |> DataFrame
    @test df2.CID == df.CID[1:2]
    @test parse_formula(df[1,"MolecularFormula"]) == ["C"=>18, "H"=>24, "O"=>3]
    @test parse(Int, match(atomregex("C"), df[1,"MolecularFormula"]).captures[1]) == 18

    # structure files (SDF)
    sleep(5.0 * get_recordings)
    sdf = String(playback(() -> get_for_cids(2244, output="SDF", record_type="3d"), "asprin_sdf_3d.bson"))
    @test occursin("PUBCHEM_MMFF94_PARTIAL_CHARGES", sdf)
    line = split(sdf, '\n')[5]
    flds = split(line)
    @test parse(Float32, flds[1]) != 0 && parse(Float32, flds[2]) != 0 && parse(Float32, flds[3]) != 0

    # parent compounds (sodium acetate is 517045, acetic acid is 176)
    sleep(5.0 * get_recordings)
    str = String(playback(() -> get_for_cids(517045; cids_type="parent", output="TXT"), "sodium_acetate_parent.bson"))
    @test parse(Int, chomp(str)) == 176

    # xrefs
    sleep(4.0 * get_recordings)  # next one is two requests
    cids = [playback(() -> get_cid(name="cyclic guanosine monophosphate"), "cGMP_cid.bson")
            playback(() -> get_cid(name="aspirin"), "aspirin_cid_from_name.bson")]
    sleep(5.0 * get_recordings)
    dct = JSON3.read(playback(() -> get_for_cids(cids; xrefs="RN,", output="JSON"), "CAS_as_json.bson"))
    @test dct[:InformationList][:Information][1][:RN] == ["40732-48-7", "7665-99-8"]
    sleep(5.0 * get_recordings)
    @test chomp(String(playback(() -> get_for_cids(cids[1]; xrefs="RN,", output="TXT"), "CAS_as_txt.bson"))) == "40732-48-7\n7665-99-8"
end


text:
using GtkReactive, Gtk.ShortNames, Colors

# Create some controls
n = slider(1:10)
dd = dropdown(["one"=>()->println("you picked \"one\""),
               "two"=>()->println("two for tea"),
               "three"=>()->println("three is a magic number")],
              label="dropdown")
cb = checkbox(true, label="make window visible")

# To illustrate some of Reactive's propagation, we create a textbox
# that shares the signal with the slider. You could alternatively
# `bind` the two signals together.
tb = textbox(Int; signal=n.signal)

# Set up the mapping for the dropdown callbacks
cbsig = map(g->g(), dd.mappedsignal)  # assign to variable to prevent garbage collection

# Lay out the GUI. You can alternatively use `glade` and pass the
# widgets to the constructors above (see the implementation of
# `player` in `extrawidgets.jl` for an example).
mainwin = Window("GtkReactive")
vbox = Box(:v)
hbox = Box(:h)
push!(vbox, hbox)
push!(hbox, n)
push!(hbox, tb)
push!(vbox, dd)
push!(vbox, cb)
push!(mainwin, vbox)

# Create the auxillary window and link its visibility to the checkbox
cnvs = canvas()
auxwin = Window(cnvs)
showwin = map(cb) do val
    set_gtk_property!(auxwin, :visible, val)
end
# Also make sure it gets destroyed when we destroy the main window
signal_connect(mainwin, :destroy) do w
    destroy(auxwin)
end
# Draw something in the auxillary window
draw(cnvs) do c
    fill!(c, colorant"orange")
end
Gtk.showall(auxwin)

Gtk.showall(mainwin)

ext: jl


text:
"""
$(TYPEDEF)
"""
mutable struct Point2Point2Range{D <: IIF.SamplableBelief} <: IncrementalInference.AbstractRelativeMinimize
  Z::D
end

function getSample(cfo::CalcFactor{<:Point2Point2Range}, N::Int=1)
  return (reshape(rand(cfo.factor.Z,N),1,N),)
end

function (cfo::CalcFactor{<:Point2Point2Range})(rho, xi, lm)
  # Basically `EuclidDistance`
  # must return all dimensions
  return rho .- norm(lm[1:2] .- xi[1:2])
end

passTypeThrough(d::FunctionNodeData{Point2Point2Range}) = d

"""
$(TYPEDEF)
"""
mutable struct PackedPoint2Point2Range  <: IncrementalInference.PackedInferenceType
  str::String
end
function convert(::Type{PackedPoint2Point2Range}, d::Point2Point2Range)
  return PackedPoint2Point2Range(convert(PackedSamplableBelief, d.Z))
end
function convert(::Type{Point2Point2Range}, d::PackedPoint2Point2Range)
  return Point2Point2Range(convert(SamplableBelief, d.str))
end

"""
    $TYPEDEF

Range only measurement from Pose2 to Point2 variable.
"""
mutable struct Pose2Point2Range{T <: IIF.SamplableBelief} <: IIF.AbstractRelativeMinimize
  Z::T
  partial::Tuple{Int,Int}
end
Pose2Point2Range(Z::T) where {T <: IIF.SamplableBelief} = Pose2Point2Range{T}(Z, (1,2))

function getSample(cfo::CalcFactor{<:Pose2Point2Range}, N::Int=1)
  return (reshape(rand(cfo.factor.Z,N),1,N), )
end

function (cfo::CalcFactor{<:Pose2Point2Range})(rho, xi, lm)
  # Basically `EuclidDistance`
  return rho .- norm(lm[1:2] .- xi[1:2])
end

mutable struct PackedPose2Point2Range  <: IncrementalInference.PackedInferenceType
  str::String
end
function convert(::Type{PackedPose2Point2Range}, d::Pose2Point2Range)
  return PackedPose2Point2Range(convert(PackedSamplableBelief, d.Z))
end
function convert(::Type{Pose2Point2Range}, d::PackedPose2Point2Range)
  return Pose2Point2Range(convert(SamplableBelief, d.str))
end


text:
# include("MyGraph.jl")

module DagFlowInstanceModule

using ..MyGraphModule

export OutFlowLimit, DagFlowInstance, DagFlowInstanceArcs

mutable struct OutFlowLimit
    node::Int32
    limit::Int64
end

mutable struct DagFlowInstance
    g::MyGraph
    nodePartition::Vector{Vector{Int32}}
    #node2Partition[i] gives the partition of node i
    node2Partion::Vector{Int32}
    sourceNode::Int32
    sinkNode::Int32
    nodeOrder::Vector{Int32}
    outFlowLimits::Vector{OutFlowLimit}
    setOutFlowNodes::Set{Int32}
    nodeInfoDict::Dict{Int32,String}
end

mutable struct DagFlowInstanceArcs
    g::MyGraph
    arcPartition::Vector{Vector{Int64}}
    #arc2Partition[i] gives the partition of arc i
    arc2Partion::Vector{Int32}
    sourceNode::Int32
    sinkNode::Int32
    nodeOrder::Vector{Int32}
    outFlowLimits::Vector{OutFlowLimit}
    setOutFlowNodes::Set{Int32}
    nodeInfoDict::Dict{Int32,String}
    highArcs::Vector{Int64}
    lowArcs::Vector{Int64}
end

function readDAGFlowArcsInstance(fileName::String)
    open(fileName) do f
      allFile = read(f, String)
      allNumbers = map(x -> parse(Int64,x), split(allFile))
      #println(allNumbers)
      nNodes = allNumbers[1]
      nArcs = allNumbers[2]
      nPartitions = allNumbers[3]
      nMaxPaths = allNumbers[4]
      graph=MyGraph(nNodes)
      index=5
      for i=1:nArcs
          src = allNumbers[index]   +1
          dst = allNumbers[index+1] +1
          cost = allNumbers[index+2]
          #println("src: $src, dst: $dst, cost: $cost")
          addArcNoDup!(graph, Int32(src), Int32(dst), Float64(cost))
          index += 3
      end
      arc2Partition = zeros(Int64,nArcs)
      arcPartition = Vector{Vector{Int64}}()
      highArcsSet = BitSet()
      for i=1:nPartitions
          nArcsInPartition = allNumbers[index]
          #println("nArcsInPartition: $nArcsInPartition")
          index += 1
          arcs = Vector{Int64}()
          for j=1:nArcsInPartition
              arcId = allNumbers[index]+1
              push!(arcs,arcId)
              arc2Partition[arcId] = i
              push!(highArcsSet, arcId)
              index+=1
          end
          #println("arcs $i: ", arcs)
          push!(arcPartition,arcs)
      end
      nodeInfoDict = Dict{Int32,String}()
      for i=1:nNodes
          node = allNumbers[index]
          time = allNumbers[index+1]
          #println("$i: $node $time")
          index += 2
          push!(nodeInfoDict, i => "$node $time")
      end

      lowArcs = Vector{Int64}()
      for arcId=1:nArcs
          if !(arcId in highArcsSet)
              push!(lowArcs, arcId)
          end
      end

      ofl = OutFlowLimit(1,nMaxPaths)
      setOutFlowNodes = Set{Int32}(Int32(1))
      return DagFlowInstanceArcs(graph, arcPartition, arc2Partition, 1, nNodes, [], [ofl], setOutFlowNodes, nodeInfoDict, collect(highArcsSet), lowArcs )
    end
end

#println(readDAGFlowArcsInstance("data/graphs/wt008_028_2.txt"))

end


text:
@testset "docs" begin
  @testset "searchdocs" begin
    using Atom: searchdocs′

    # don't error on fallback case
    @test !searchdocs′("sin")[:error]

    # don't erase module input when it's used
    @test !searchdocs′("getfield′", true, "Atom")[:shoulderase]
    # erase module input when it's replaced by module prefix in search text
    @test searchdocs′("Atom.getfield′", true, "Main")[:shoulderase]
  end

  @testset "moduleinfo" begin
    using Atom: moduleinfo

    @test_nowarn moduleinfo("Main")
    @test all(moduleinfo("Atom")[:items]) do item
      item[:mod] == "Atom"
    end
  end
end


text:
# Themelis, Stella, Patrinos, "Douglas-Rachford splitting and ADMM
# for nonconvex optimization: Accelerated and Newton-type linesearch algorithms",
# arXiv:2005.10230, 2020.
#
# https://arxiv.org/abs/2005.10230

using Base.Iterators
using ProximalAlgorithms.IterationTools
using ProximalCore: Zero
using LinearAlgebra
using Printf

function drls_default_gamma(f::Tf, mf, Lf, alpha, lambda) where Tf
    if mf !== nothing && mf > 0
        return 1 / (alpha * mf)
    end
    return ProximalCore.is_convex(Tf) ? alpha / Lf : alpha * (2 - lambda) / (2 * Lf)
end

function drls_C(f::Tf, mf, Lf, gamma, lambda) where Tf
    a = mf === nothing || mf <= 0 ? gamma * Lf : 1 / (gamma * mf)
    m = ProximalCore.is_convex(Tf) ? max(a - lambda / 2, 0) : 1
    return (lambda / ((1 + a)^2) * ((2 - lambda) / 2 - a * m))
end

"""
    DRLSIteration(; <keyword-arguments>)

Iterator implementing the Douglas-Rachford line-search algorithm [1].

This iterator solves optimization problems of the form

    minimize f(x) + g(x),

where `f` is smooth.

See also: [`DRLS`](@ref).

# Arguments
- `x0`: initial point.
- `f=Zero()`: smooth objective term.
- `g=Zero()`: proximable objective term.
- `mf=nothing`: convexity modulus of f.
- `Lf=nothing`: Lipschitz constant of the gradient of f.
- `gamma`: stepsize to use, chosen appropriately based on Lf and mf by defaults.
- `max_backtracks=20`: maximum number of line-search backtracks.
- `directions=LBFGS(5)`: strategy to use to compute line-search directions.

# References
1. Themelis, Stella, Patrinos, "Douglas-Rachford splitting and ADMM for nonconvex optimization: Accelerated and Newton-type linesearch algorithms", arXiv:2005.10230, 2020.
"""
Base.@kwdef struct DRLSIteration{R,Tx,Tf,Tg,Tmf,TLf,D}
    f::Tf = Zero()
    g::Tg = Zero()
    x0::Tx
    alpha::R = real(eltype(x0))(0.95)
    beta::R = real(eltype(x0))(0.5)
    lambda::R = real(eltype(x0))(1)
    mf::Tmf = nothing
    Lf::TLf = nothing
    gamma::R = drls_default_gamma(f, mf, Lf, alpha, lambda)
    c::R = beta * drls_C(f, mf, Lf, gamma, lambda)
    dre_sign::Int = mf === nothing || mf <= 0 ? 1 : -1
    max_backtracks::Int = 20
    directions::D = LBFGS(5)
end

Base.IteratorSize(::Type{<:DRLSIteration}) = Base.IsInfinite()

Base.@kwdef mutable struct DRLSState{R,Tx,TH}
    x::Tx
    u::Tx
    v::Tx
    w::Tx
    res::Tx
    res_prev::Tx = similar(x)
    xbar::Tx
    xbar_prev::Tx = copy(xbar)
    d::Tx = similar(x)
    x_d::Tx = similar(x)
    gamma::R
    f_u::R
    g_v::R
    H::TH
    tau::R = zero(gamma)
    u0::Tx = similar(x)
    u1::Tx = similar(x)
    temp_x1::Tx = similar(x)
    temp_x2::Tx = similar(x)
end

DRE(f_u::Number, g_v::Number, x, u, res, gamma) = f_u + g_v - real(dot(x - u, res)) / gamma + 1 / (2 * gamma) * norm(res)^2

DRE(state::DRLSState) = DRE(state.f_u, state.g_v, state.x, state.u, state.res, state.gamma)

function Base.iterate(iter::DRLSIteration)
    x = copy(iter.x0)
    u, f_u = prox(iter.f, x, iter.gamma)
    w = 2 * u - x
    v, g_v = prox(iter.g, w, iter.gamma)
    res = u - v
    xbar = x - iter.lambda * res
    state = DRLSState(
        x=x, u=u, v=v, w=w, res=res, xbar=xbar, gamma=iter.gamma, f_u=f_u,
        g_v=g_v, H=initialize(iter.directions, x),
    )
    return state, state
end

set_next_direction!(::QuasiNewtonStyle, ::DRLSIteration, state::DRLSState) = mul!(state.d, state.H, -state.res)
set_next_direction!(::NesterovStyle, ::DRLSIteration, state::DRLSState) = state.d .= iterate(state.H)[1] .* (state.xbar .- state.xbar_prev) .+ (state.xbar .- state.x)
set_next_direction!(::NoAccelerationStyle, ::DRLSIteration, state::DRLSState) = state.d .= state.xbar .- state.x
set_next_direction!(iter::DRLSIteration, state::DRLSState) = set_next_direction!(acceleration_style(typeof(iter.directions)), iter, state)

update_direction_state!(::QuasiNewtonStyle, ::DRLSIteration, state::DRLSState) = update!(state.H, state.d, state.res - state.res_prev)
update_direction_state!(::NesterovStyle, ::DRLSIteration, state::DRLSState) = return
update_direction_state!(::NoAccelerationStyle, ::DRLSIteration, state::DRLSState) = return
update_direction_state!(iter::DRLSIteration, state::DRLSState) = update_direction_state!(acceleration_style(typeof(iter.directions)), iter, state)

function Base.iterate(iter::DRLSIteration{R, Tx, Tf}, state::DRLSState) where {R, Tx, Tf}
    DRE_curr = DRE(state)

    set_next_direction!(iter, state)

    state.x_d .= state.x .+ state.d
    state.xbar_prev, state.xbar = state.xbar, state.xbar_prev
    state.res_prev, state.res = state.res, state.res_prev
    state.tau = R(1)

    state.x .= state.x_d
    state.f_u = prox!(state.u, iter.f, state.x, iter.gamma)
    state.w .= 2 .* state.u .- state.x
    state.g_v = prox!(state.v, iter.g, state.w, iter.gamma)
    state.res .= state.u .- state.v
    state.xbar .= state.x .- iter.lambda * state.res

    update_direction_state!(iter, state)

    a, b, c = R(0), R(0), R(0)

    for k in 1:iter.max_backtracks
        if iter.dre_sign * DRE(state) <= iter.dre_sign * DRE_curr - iter.c / iter.gamma * norm(state.res_prev)^2
            break
        end

        state.tau = k == iter.max_backtracks ? R(0) : state.tau / 2
        state.x .= state.tau .* state.x_d .+ (1 - state.tau) .* state.xbar_prev

        if ProximalCore.is_generalized_quadratic(Tf)
            if k == 1
                copyto!(state.u1, state.u)
                c = prox!(state.u0, iter.f, state.xbar_prev, iter.gamma)
                state.temp_x1 .= state.xbar_prev .- state.x_d
                state.temp_x2 .= state.xbar_prev .- state.u0
                b = real(dot(state.temp_x1, state.temp_x2)) / iter.gamma
                a = state.f_u - b - c
            end
            state.u .= state.tau .* state.u1 .+ (1 - state.tau) .* state.u0
            state.f_u = a * state.tau ^ 2 + b * state.tau + c
        else
            state.f_u = prox!(state.u, iter.f, state.x, iter.gamma)
        end

        state.w .= 2 .* state.u .- state.x
        state.g_v = prox!(state.v, iter.g, state.w, iter.gamma)
        state.res .= state.u .- state.v
        state.xbar .= state.x .- iter.lambda * state.res
    end

    return state, state
end

default_stopping_criterion(tol, ::DRLSIteration, state::DRLSState) = norm(state.res, Inf) / state.gamma <= tol
default_solution(::DRLSIteration, state::DRLSState) = state.v
default_display(it, ::DRLSIteration, state::DRLSState) = @printf(
    "%5d | %.3e | %.3e | %.3e\n", it, state.gamma / state.gamma, norm(state.res, Inf), state.tau,
)

"""
    DRLS(; <keyword-arguments>)

Constructs the Douglas-Rachford line-search algorithm [1].

This algorithm solves convex optimization problems of the form

    minimize f(x) + g(x),

where `f` is smooth.

The returned object has type `IterativeAlgorithm{DRLSIteration}`,
and can be called with the problem's arguments to trigger its solution.

See also: [`DRLSIteration`](@ref), [`IterativeAlgorithm`](@ref).

# Arguments
- `maxit::Int=1_000`: maximum number of iteration
- `tol::1e-8`: tolerance for the default stopping criterion
- `stop::Function`: termination condition, `stop(::T, state)` should return `true` when to stop the iteration
- `solution::Function`: solution mapping, `solution(::T, state)` should return the identified solution
- `verbose::Bool=false`: whether the algorithm state should be displayed
- `freq::Int=10`: every how many iterations to display the algorithm state
- `display::Function`: display function, `display(::Int, ::T, state)` should display a summary of the iteration state
- `kwargs...`: additional keyword arguments to pass on to the `DRLSIteration` constructor upon call

# References
1. Themelis, Stella, Patrinos, "Douglas-Rachford splitting and ADMM for nonconvex optimization: Accelerated and Newton-type linesearch algorithms", arXiv:2005.10230, 2020.
"""
DRLS(;
    maxit=1_000,
    tol=1e-8,
    stop=(iter, state) -> default_stopping_criterion(tol, iter, state),
    solution=default_solution,
    verbose=false,
    freq=10,
    display=default_display,
    kwargs...
) = IterativeAlgorithm(DRLSIteration; maxit, stop, solution, verbose, freq, display, kwargs...)


text:
using HypertextTools
using Test

@testset "HypertextTools.jl" begin
    # Write your tests here.
end

max_stars_repo_name: CGRG-lab/HypertextTools

max_issues_repo_name: CGRG-lab/HypertextTools

max_forks_repo_name: CGRG-lab/HypertextTools


text:
"""
    describe_class(object)

Return the type of the object.
"""
function describe_class(object)
    return typeof(object)
end


text:
# Reexport GridTools as they are useful outside too
@reexport module CirculationGeneration

using LinearAlgebra, SparseArrays
using Unitful, UnitfulAstro # for units

#=============================================
Tools for making simple circulations
=============================================#

function flux_divergence_operator_from_advection(c::Vector, i, v3D, nb)
    unit(c[1] / v3D[1]) ≠ unit(u"1/s") && error("Unit problem")
    j = circshift(i,-1) # i = origin -> j = destination
    return sparse(i, i, ustrip(c ./ v3D[i]), nb, nb) - sparse(j, i, ustrip(c ./ v3D[j]), nb, nb)
end

function flux_divergence_operator_from_advection(c, i, v3D, nb)
    c = fill(c, length(i))
    flux_divergence_operator_from_advection(c, i, v3D, nb)
end

end


text:
using FastTransforms, Compat
using Compat.Test

if VERSION < v"0.7"
    srand(0)
else
    Random.seed!(0)
end

println()
println("Spherical harmonic transform")
println()

include("slowplantests.jl")

include("fastplantests.jl")

include("thinplantests.jl")

include("pointwisetests.jl")

include("synthesisanalysistests.jl")

include("vectorfieldtests.jl")

include("apitests.jl")


text:
module Utils

include("elementfeature_utils.jl")
export ElementFeatureUtils

include("orbitalfeature_utils.jl")
export OrbitalFeatureUtils

include("graph_building.jl")
export GraphBuilding

end


text:
module PredicatedSets
export PredicatedSet,PredicatedHom

import FunctionWrappers
import FunctionWrappers: FunctionWrapper
using ...GAT
using ...Theories
import ...Theories: id, compose

struct PredicatedSet{T}
  predicate::FunctionWrapper{Bool,Tuple{T}}
  PredicatedSet(T::DataType,f::Function) = new{T}(FunctionWrapper{Bool,Tuple{T}}(f))
end

function (t::PredicatedSet{T})(x::T)::Bool where {T}
  t.predicate(x)
end

basetype(t::PredicatedSet{T}) where {T} = T

struct PredicatedHom{T,S}
  dom::PredicatedSet{T}
  codom::PredicatedSet{S}
  f::FunctionWrapper{S,Tuple{T}}
  PredicatedHom(dom::PredicatedSet{T},codom::PredicatedSet{S},f) where {T,S} =
    new{T,S}(dom,codom,FunctionWrapper{S,Tuple{T}}(f))
end

function (f::PredicatedHom{T,S})(x::T)::S where {T,S}
  @assert f.dom(x)
  y = f.f(x)
  @assert f.codom(y)
  y
end

function compose(f::PredicatedHom{T,S},g::PredicatedHom{S,U}) where {T,S,U}
  function h(x)
    y = f.f(x)
    @assert f.codom(y)
    @assert g.dom(y)
    g.f(y)
  end
  PredicatedHom(f.dom,g.codom,h)
end

# This is really the category of decidable sets and partial functions...
@instance Category{PredicatedSet, PredicatedHom} begin
  dom(f::PredicatedHom) = f.dom
  codom(f::PredicatedHom) = f.codom

  id(t::PredicatedSet) = PredicatedHom(t,t,x->x)
  compose(f::PredicatedHom,g::PredicatedHom) = begin
    @assert basetype(f.codom) == basetype(g.dom)
    compose(f,g)
  end
end

end


text:
__precompile__(true)

module StandardMarketData

using Printf, Dates, Distributed, Mmap, Statistics, Random
using ProgressMeter, Parameters, Glob, MacroTools
using PyCall, HDF5, BSON, BSONMmap
using PandasLite, PyCallUtils, HDF5Utils
using BlockArrays: _BlockArray
using PandasLite: StringRange
import StatsBase

export Data, loaddata, savedata, reloaddata
export nfeats, ncodes, nticks, ndays, nticksperday
export discretize!, discretize, undiscretize, period, downsample, featnames
export getfeat, getfeats, @uncol, dropfeats, keepfeats, getcats, keepcats
export datespan, firstdate, lastdate, setcomm, setpool
export epochsof, datetimesof, datesof, codesof, parsefreq
export concat, pivot, rolldata, to_df, to_data, sourceof, findsnap, splitday
export unix2date, unix2time, unix2hour, unix2str8, unix2str6, unix2int
export str2date, str2datetime, str2unix, int2unix
export to_dict, to_struct, idxmap, pct_change
export to_category, from_category
export sortedunique, sortednunique, nunique
export fillnan, fillnan!
export extract_talib_feats, extract_tsfresh_feats
export SMD, ⧶, @staticvar, @staticdef

export creshape, rreshape, csize, rsize, ccount, rcount
export cview, rview, cget, rget, cset!, rset!
export concatenate, cconcatenate, rconcatenate
export unsqueeze, stack, unstack, cstack, rstack
export colvec, rowvec, indbatch, minibatch, splat

const SMD = StandardMarketData

include("data.jl")
include("util.jl")
include("feature.jl")
include("discretize.jl")
include("array.jl")

end


text:
function svRelativity(dt::DateTime)
    return 0.0
end

function svClockBias(dt::DateTime)
    return 0.0
end

function svClockDrift(dt::DateTime)
    return 0.0
end

function calculate_Orbit_pos_BDGEO( dt::DateTime,
    ctToe::DateTime,
    af0::Float64, af1::Float64, af2::Float64,
    Ahalf::Float64, ecc::Float64, idot::Float64, dn::Float64,
    M0::Float64, ω::Float64, i0::Float64,
    Ω0::Float64, Ωdot::Float64,
    Cuc::Float64,  Cus::Float64,
    Crc::Float64,  Crs::Float64,
    Cic::Float64,  Cis::Float64,
    health::Float64=-1.0,
    Adot::Float64=0.0,
    dndot::Float64=0.0,
    gm::Float64=WGS84Ellipsoid.gm,
    angVelocity::Float64=WGS84Ellipsoid.angVelocity,
    )

    sqrtgm = sqrt(gm)
    twoPI = 2.0 * PI
    # lecc;            # eccentricity
    # tdrinc;          # dt inclination
    A = Ahalf^2
    # Ahalf = sqrt(A)  # A is semi-major axis of orbit

    _, ToeSOW = datetime2gpsws(ctToe)    # SOW is time-system-independent

    lecc = ecc
    tdrinc = idot

    # Compute time since ephemeris & clock epochs
    elapte = (dt - ctToe).value / 1000.0 # TODO  second?
    # Compute A at time of interest (LNAV: Adot==0)
    Ak = A + Adot * elapte

    # Compute mean motion (LNAV: dndot==0)
    dnA = dn + 0.5 * dndot * elapte
    amm  = (sqrtgm / (A * Ahalf)) + dnA     # Eqn specifies A0, not Ak

    # In-plane angles
    #     meana - Mean anomaly
    #     ea    - Eccentric anomaly
    #     truea - True anomaly
    meana = M0 + elapte * amm
    meana = meana % twoPI
    ea = meana + lecc * sin(meana)

    for loop_cnt in 1:20
        F = meana - (ea - lecc * sin(ea))
        G = 1.0 - lecc * cos(ea)
        delea = F / G
        ea = ea + delea
        abs(delea) < 1.0e-11 && break
    end

    # Compute clock corrections
    relcorr = svRelativity(dt)
    clkbias = svClockBias(dt)
    clkdrift = svClockDrift(dt)
    frame = fmWGS84;

    # Compute true anomaly
    q     = sqrt(1.0e0 - lecc * lecc)
    sinea = sin(ea)
    cosea = cos(ea)
    G     = 1.0e0 - lecc * cosea

    #  G*SIN(TA) AND G*COS(TA)
    GSTA  = q * sinea
    GCTA  = cosea - lecc

    #  True anomaly
    truea = atan(GSTA, GCTA)

    # Argument of lat and correction terms (2nd harmonic)
    alat  = truea + ω
    talat = 2.0e0 * alat
    c2al  = cos(talat)
    s2al  = sin(talat)

    du  = c2al * Cuc +  s2al * Cus
    dr  = c2al * Crc +  s2al * Crs
    di  = c2al * Cic +  s2al * Cis

    # U = updated argument of lat, R = radius, AINC = inclination
    U    = alat + du
    R    = Ak * G  + dr
    AINC = i0 + tdrinc * elapte  +  di

    #  Longitude of ascending node (ANLON)
    # ANLON = Ω0 + (Ωdot - WGS84Ellipsoid.angVelocity) *
    #         elapte - WGS84Ellipsoid.angVelocity * ToeSOW
    ANLON = Ω0 + Ωdot * elapte -
            angVelocity * ToeSOW
    # In plane location
    cosu = cos(U)
    sinu = sin(U)
    xip  = R * cosu
    yip  = R * sinu

    #  Angles for rotation to earth fixed
    can  = cos(ANLON)
    san  = sin(ANLON)
    cinc = cos(AINC)
    sinc = sin(AINC)

    # Earth fixed coordinates in meters
    # xef  =  xip * can  -  yip * cinc * san
    # yef  =  xip * san  +  yip * cinc * can
    # zef  =              yip * sinc
    # GEO satellite coordinates in user-defined inertial system
    xGK  =  xip * can  -  yip * cinc * san
    yGK  =  xip * san  +  yip * cinc * can
    zGK  =              yip * sinc

    # Rz matrix
    angleZ = angVelocity * elapte
    cosZ   = cos(angleZ)
    sinZ   = sin(angleZ)

    matZ = [ cosZ sinZ 0.0;
            -sinZ cosZ 0.0;
            0.0    0.0 1.0;]

    angleX = deg2rad(-5.0)
    cosX   = cos(angleX)
    sinX   = sin(angleX)
    matX = [1.0   0.0  0.0;
            0.0  cosX sinX;
            0.0 -sinX cosX;]

    inertialPos = [xGK; yGK; zGK]
    # @warn "matrix multiply check!"
    # @show matZ
    # @show matX
    # @show inertialPos

    result = matZ * matX * inertialPos

    x = ECEF(result[1], result[2], result[3])
    # sv.x[0] = xef
    # sv.x[1] = yef
    # sv.x[2] = zef
    # derivatives of true anamoly and arg of latitude
    dek = amm / G;
    dlk =  Ahalf * q * sqrtgm / (R * R);

    # in-plane, cross-plane, and radial derivatives
    div = tdrinc - 2.0e0 * dlk * (Cis  * c2al - Cic * s2al)
    duv = dlk * (1.e0 + 2.e0 * (Cus * c2al - Cuc * s2al))
    drv = A * lecc * dek * sinea + 2.e0 * dlk * (Crs * c2al - Crc * s2al)

    #
    dxp = drv * cosu - R * sinu * duv
    dyp = drv * sinu + R * cosu * duv

    # time-derivative of Rz matrix
    dmatZ = [sinZ * -angVelocity -cosZ * -angVelocity 0.0;
             cosZ * angVelocity   sinZ * -angVelocity 0.0;
                            0.0                   0.0 0.0;]

    dIntPos = [- xip * san * Ωdot +
                    dxp * can -
                    yip * (cinc * can * Ωdot -
                            sinc * san * div ) -
                    dyp * cinc * san,
                xip * can * Ωdot +
                    dxp * san -
                    yip * (cinc * san * Ωdot +
                            sinc * can * div ) +
                    dyp * cinc * can,
                yip * cinc * div + dyp * sinc
            ]
    # @warn "matrix multiply check!"
    # @show matZ
    # @show matX
    # @show inertialPos

    vresult = matZ * matX * dIntPos +
                dmatZ * matX * inertialPos

    v = (vresult[1], vresult[2], vresult[3],)
    # @bp
    # sv.v[0] = vxef;
    # sv.v[1] = vyef;
    # sv.v[2] = vzef;

    # return sv;

    Xvt(x, v, relcorr, clkbias, clkdrift, frame,
            health == 1.0 ? hsHealthy : hsUnhealthy)
end

function calculate_Orbit_pos( dt::DateTime,
    ctToe::DateTime,
    af0::Float64, af1::Float64, af2::Float64,
    Ahalf::Float64, ecc::Float64, idot::Float64, dn::Float64,
    M0::Float64, ω::Float64, i0::Float64,
    Ω0::Float64, Ωdot::Float64,
    Cuc::Float64,  Cus::Float64,
    Crc::Float64,  Crs::Float64,
    Cic::Float64,  Cis::Float64,
    health::Float64=-1.0,
    Adot::Float64=0.0,
    dndot::Float64=0.0,
    GPSEllipsoid::GNSSEllipsoid=GPSEllipsoid,
    )

    sqrtgm = sqrt(GPSEllipsoid.gm)
    twoPI = 2.0 * PI
    # lecc;            # eccentricity
    # tdrinc;          # dt inclination
    A = Ahalf^2
    # Ahalf = sqrt(A)  # A is semi-major axis of orbit

    # TODO
    _, ToeSOW = datetime2gpsws(ctToe)    # SOW is time-system-independent

    lecc = ecc
    tdrinc = idot

    # Compute time since ephemeris & clock epochs
    elapte = (dt - ctToe).value / 1000.0 # TODO  second?
    # Compute A at time of interest (LNAV: Adot==0)
    Ak = A + Adot * elapte

    # Compute mean motion (LNAV: dndot==0)
    dnA = dn + 0.5 * dndot * elapte
    amm  = (sqrtgm / (A * Ahalf)) + dnA     # Eqn specifies A0, not Ak

    # In-plane angles
    #     meana - Mean anomaly
    #     ea    - Eccentric anomaly
    #     truea - True anomaly
    meana = M0 + elapte * amm
    meana = meana % twoPI # TODO fmod
    ea = meana + lecc * sin(meana)

    for loop_cnt in 1:20
        F = meana - (ea - lecc * sin(ea))
        G = 1.0 - lecc * cos(ea)
        delea = F / G
        ea = ea + delea
        abs(delea) < 1.0e-11 && break
    end

    # Compute clock corrections
    relcorr = svRelativity(dt)
    clkbias = svClockBias(dt)
    clkdrift = svClockDrift(dt)
    frame = fmWGS84;

    # Compute true anomaly
    q     = sqrt(1.0e0 - lecc * lecc)
    sinea = sin(ea)
    cosea = cos(ea)
    G     = 1.0e0 - lecc * cosea

    #  G*SIN(TA) AND G*COS(TA)
    GSTA  = q * sinea
    GCTA  = cosea - lecc

    #  True anomaly
    truea = atan(GSTA, GCTA)

    # Argument of lat and correction terms (2nd harmonic)
    alat  = truea + ω
    talat = 2.0e0 * alat
    c2al  = cos(talat)
    s2al  = sin(talat)

    du  = c2al * Cuc +  s2al * Cus
    dr  = c2al * Crc +  s2al * Crs
    di  = c2al * Cic +  s2al * Cis

    # U = updated argument of lat, R = radius, AINC = inclination
    U    = alat + du
    R    = Ak * G  + dr
    AINC = i0 + tdrinc * elapte  +  di

    #  Longitude of ascending node (ANLON)
    ANLON = Ω0 + (Ωdot - GPSEllipsoid.angVelocity) *
            elapte - GPSEllipsoid.angVelocity * ToeSOW

    # In plane location
    cosu = cos(U)
    sinu = sin(U)
    xip  = R * cosu
    yip  = R * sinu

    #  Angles for rotation to earth fixed
    can  = cos(ANLON)
    san  = sin(ANLON)
    cinc = cos(AINC)
    sinc = sin(AINC)

    # Earth fixed coordinates in meters
    xef  =  xip * can  -  yip * cinc * san
    yef  =  xip * san  +  yip * cinc * can
    zef  =              yip * sinc

    x = ECEF(xef, yef, zef)
    # sv.x[0] = xef
    # sv.x[1] = yef
    # sv.x[2] = zef

    # Compute velocity of rotation coordinates
    dek = amm * Ak / R
    dlk = Ahalf * q * sqrtgm / (R * R)
    div = tdrinc - 2.0e0 * dlk * (Cic  * s2al - Cis * c2al)
    domk = Ωdot - GPSEllipsoid.angVelocity
    duv = dlk * (1.e0 + 2.e0 * (Cus * c2al - Cuc * s2al))
    drv = Ak * lecc * dek * sinea - 2.e0 * dlk * (Crc * s2al - Crs * c2al)
    dxp = drv * cosu - R * sinu * duv
    dyp = drv * sinu + R * cosu * duv

    # Calculate velocities
    vxef = dxp * can - xip * san * domk - dyp * cinc * san +
            yip * (sinc * san * div - cinc * can * domk)
    vyef = dxp * san + xip * can * domk + dyp * cinc * can -
            yip * (sinc * can * div + cinc * san * domk)
    vzef = dyp * sinc + yip * cinc * div

    # Move results into output variables
    v = (vxef, vyef, vzef)
    # @bp
    # sv.v[0] = vxef;
    # sv.v[1] = vyef;
    # sv.v[2] = vzef;

    # return sv;

    Xvt(x, v, relcorr, clkbias, clkdrift, frame,
            health == 1.0 ? hsHealthy : hsUnhealthy)
end

function calculate_Orbit_pos(ees::EphEpochStore, dt::DateTime,
    vaild_d::Hour=Hour(2), )
    k = ees.keys
    if length(k) == 0
        return ECEF{Float64}(NaN, NaN, NaN)
    end
    d = k .- dt
    i = argmin(abs.(d))

    md = d[i]
    if md > vaild_d || md < -vaild_d
        return ECEF{Float64}(NaN, NaN, NaN)
    end

    mk = k[i]
    me = ees.eph[mk].d
    fun = calculate_Orbit_pos
    if ees.si.ss == sstBeiDou
        prn = ees.si.id
        # http://mgex.igs.org/IGS_MGEX_Status_BDS.php
        if prn < 6 ||
            (prn == 17 && dt < DateTime(2018, 9, 29)) ||
            (prn == 18 && dt > DateTime(2019, 5, 17)) ||
            prn == 59
            fun = calculate_Orbit_pos_BDGEO
        end
    end

    xvt = fun(dt, mk,
                me[1], me[2], me[3],

                me[11], me[9], me[20], me[6],

                me[7], me[18], me[16],
                me[14], me[19],

                me[8], me[10],
                me[17], me[5],
                me[13], me[15],

                me[25],)
    return xvt.x
end


text:
module Acoustic
using FEniCS

c = 5000
#problem variables, have been scaled down for faster test solution
dt = 0.00004;
global t = 0;
T = 0.0004;

mesh = RectangleMesh(Point([-2., -2.]),Point([2., 2.]),40,40)
V = FunctionSpace(mesh,"Lagrange",1)

# Previous and current solution
u1= interpolate(Constant(0.0), V)
u0= interpolate(Constant(0.0), V)

# Variational problem at each time
u = TrialFunction(V)
v = TestFunction(V)

a = u*v*dx + dt*dt*c*c*inner(grad(u), grad(v))*dx
L = 2*u1*v*dx-u0*v*dx

delta = Expression("sin(c*10*t)",degree=2,c=c,t=t)

#Define boundary conditions
top ="on_boundary && near(x[1], 2)"
BCT = DirichletBC(V,Constant(0.0),top)

down ="on_boundary && near(x[1], -2)"
BCD = DirichletBC(V,Constant(0.0),down)

left = "on_boundary && near(x[0],-2)"
BCL = DirichletBC(V,delta,left)

right = "on_boundary && near(x[0],2)"
BCR = DirichletBC(V,Constant(0.0),right)

#bcs = [BCL.pyobject,BCD.pyobject,BCT.pyobject,BCR.pyobject]
bcs = [BCL.pyobject,BCD.pyobject,BCT.pyobject]

#bc = DirichletBC(V, 0, "on_boundary")

u=FeFunction(V)

while t <= T
    A, b = assemble_system(a, L, bcs)
    delta.pyobject.t = t
    [apply(bcc,b) for bcc in bcs]
    solve(A, vector(u), b)
    assign(u0,u1)
    assign(u1,u)
    global t +=dt
    #fenics.plot(u.pyobject,title="Acoustic wave Equation")#,mode="auto")

end
end#module


text:
@testset "Group algebras" begin
  G = small_group(8, 4)
  A = AlgGrp(FlintQQ, G)

  @testset "Regular matrix algebra" begin
    B, BtoA = Hecke.regular_matrix_algebra(A)

    @test dim(B) == dim(A)

    for i = 1:dim(A)
      for j = 1:dim(A)
        @test BtoA(B[i])*BtoA(B[j]) == BtoA(B[i]*B[j])
        @test (BtoA\A[i])*(BtoA\A[j]) == BtoA\(A[i]*A[j])
      end
    end
  end

  @testset "Generators" begin
    g, full_basis, v = gens(A, Val{true})

    @test length(full_basis) == dim(A)

    M = zero_matrix(FlintQQ, dim(A), dim(A))
    for i = 1:dim(A)
      Hecke.elem_to_mat_row!(M, i, full_basis[i])
    end
    @test rank(M) == dim(A)

    for i = 1:dim(A)
      b = full_basis[i]
      a = one(A)
      for (j, k) in v[i]
        a *= g[j]^k
      end
      @test b == a
    end
  end

  @testset "Decomposition for abelian group algebras" begin
    G = abelian_group([2,4,6])
    QG = QQ[G]
    d = decompose(QG)
    idem = [y(one(x)) for (x, y) in d]
    @test isone(sum(idem))
    @test all(e^2 == e for e in idem)
    @test all(issimple(x) for (x, _) in d)

    G = abelian_group([2,4,6])
    F = GF(5)
    QG = F[G]
    d = decompose(QG)
    idem = [y(one(x)) for (x, y) in d]
    @test isone(sum(idem))
    @test all(e^2 == e for e in idem)
    @test all(issimple(x) for (x, _) in d)
  end
end


text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

mutable struct IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec <: SwaggerModel
    additionalPrinterColumns::Any # spec type: Union{ Nothing, Vector{IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceColumnDefinition} } # spec name: additionalPrinterColumns
    conversion::Any # spec type: Union{ Nothing, IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceConversion } # spec name: conversion
    group::Any # spec type: Union{ Nothing, String } # spec name: group
    names::Any # spec type: Union{ Nothing, IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionNames } # spec name: names
    scope::Any # spec type: Union{ Nothing, String } # spec name: scope
    subresources::Any # spec type: Union{ Nothing, IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceSubresources } # spec name: subresources
    validation::Any # spec type: Union{ Nothing, IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceValidation } # spec name: validation
    version::Any # spec type: Union{ Nothing, String } # spec name: version
    versions::Any # spec type: Union{ Nothing, Vector{IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionVersion} } # spec name: versions

    function IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec(;additionalPrinterColumns=nothing, conversion=nothing, group=nothing, names=nothing, scope=nothing, subresources=nothing, validation=nothing, version=nothing, versions=nothing)
        o = new()
        validate_property(IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec, Symbol("additionalPrinterColumns"), additionalPrinterColumns)
        setfield!(o, Symbol("additionalPrinterColumns"), additionalPrinterColumns)
        validate_property(IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec, Symbol("conversion"), conversion)
        setfield!(o, Symbol("conversion"), conversion)
        validate_property(IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec, Symbol("group"), group)
        setfield!(o, Symbol("group"), group)
        validate_property(IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec, Symbol("names"), names)
        setfield!(o, Symbol("names"), names)
        validate_property(IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec, Symbol("scope"), scope)
        setfield!(o, Symbol("scope"), scope)
        validate_property(IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec, Symbol("subresources"), subresources)
        setfield!(o, Symbol("subresources"), subresources)
        validate_property(IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec, Symbol("validation"), validation)
        setfield!(o, Symbol("validation"), validation)
        validate_property(IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec, Symbol("version"), version)
        setfield!(o, Symbol("version"), version)
        validate_property(IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec, Symbol("versions"), versions)
        setfield!(o, Symbol("versions"), versions)
        o
    end
end # type IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec

const _property_map_IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec = Dict{Symbol,Symbol}(Symbol("additionalPrinterColumns")=>Symbol("additionalPrinterColumns"), Symbol("conversion")=>Symbol("conversion"), Symbol("group")=>Symbol("group"), Symbol("names")=>Symbol("names"), Symbol("scope")=>Symbol("scope"), Symbol("subresources")=>Symbol("subresources"), Symbol("validation")=>Symbol("validation"), Symbol("version")=>Symbol("version"), Symbol("versions")=>Symbol("versions"))
const _property_types_IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec = Dict{Symbol,String}(Symbol("additionalPrinterColumns")=>"Vector{IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceColumnDefinition}", Symbol("conversion")=>"IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceConversion", Symbol("group")=>"String", Symbol("names")=>"IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionNames", Symbol("scope")=>"String", Symbol("subresources")=>"IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceSubresources", Symbol("validation")=>"IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceValidation", Symbol("version")=>"String", Symbol("versions")=>"Vector{IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionVersion}")
Base.propertynames(::Type{ IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec }) = collect(keys(_property_map_IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec))
Swagger.property_type(::Type{ IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec }, name::Symbol) = Union{Nothing,eval(Meta.parse(_property_types_IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec[name]))}
Swagger.field_name(::Type{ IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec }, property_name::Symbol) =  _property_map_IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec[property_name]

function check_required(o::IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec)
    (getproperty(o, Symbol("group")) === nothing) && (return false)
    (getproperty(o, Symbol("names")) === nothing) && (return false)
    (getproperty(o, Symbol("scope")) === nothing) && (return false)
    true
end

function validate_property(::Type{ IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionSpec }, name::Symbol, val)
end


text:
using JuMP, EAGO

                     m = Model()

                     EAGO.register_eago_operators!(m)

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

                     @variable(m, -140.37215752831116 <= q <= 140.41841564400983)

                     add_NL_constraint(m, :(swish(0.9038900968817085 + 0.1284043831226005*swish(0.06165362792774953 + 0.6866075626761576*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.8737233458006566*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + -0.3942911833193632*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + 0.6872447034250162*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.5711071882051262*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + 0.26042276084039084*swish(0.8058455478649482 + 0.7751639240502244*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.13474005943220124*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.6437669970537465*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + 0.5932192098608322*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.5325023046383324*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + 0.6458808355119907*swish(-0.1540966309548315 + 0.690406062481447*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + 0.4718956794952942*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.8703243890856593*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.8079540211479861*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.683716372184894*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + -0.6567358944011805*swish(-0.2486694730930381 + -0.9006272851005916*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.9841514005441985*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.7501520395123897*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.43486617405885397*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + -0.4797454164387962*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + -0.41502277707459934*swish(-0.9928729682863509 + 0.9588446333785003*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + 0.7154937103302039*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + -0.17921833371514895*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.7009330672719543*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.15311755902026114*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5])))) + swish(-0.8820041740138964 + 0.8813585352462416*swish(0.06165362792774953 + 0.6866075626761576*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.8737233458006566*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + -0.3942911833193632*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + 0.6872447034250162*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.5711071882051262*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + -0.30334290832683886*swish(0.8058455478649482 + 0.7751639240502244*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.13474005943220124*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.6437669970537465*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + 0.5932192098608322*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.5325023046383324*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + 0.6303754843616343*swish(-0.1540966309548315 + 0.690406062481447*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + 0.4718956794952942*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.8703243890856593*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.8079540211479861*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.683716372184894*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + 0.9344814932534002*swish(-0.2486694730930381 + -0.9006272851005916*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.9841514005441985*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.7501520395123897*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.43486617405885397*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + -0.4797454164387962*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + -0.8925753470795712*swish(-0.9928729682863509 + 0.9588446333785003*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + 0.7154937103302039*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + -0.17921833371514895*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.7009330672719543*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.15311755902026114*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5])))) + swish(-0.6413973695460733 + -0.5291254814289021*swish(0.06165362792774953 + 0.6866075626761576*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.8737233458006566*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + -0.3942911833193632*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + 0.6872447034250162*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.5711071882051262*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + -0.3315514300310589*swish(0.8058455478649482 + 0.7751639240502244*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.13474005943220124*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.6437669970537465*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + 0.5932192098608322*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.5325023046383324*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + 0.9076257425527015*swish(-0.1540966309548315 + 0.690406062481447*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + 0.4718956794952942*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.8703243890856593*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.8079540211479861*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.683716372184894*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + -0.9763381142518175*swish(-0.2486694730930381 + -0.9006272851005916*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.9841514005441985*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.7501520395123897*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.43486617405885397*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + -0.4797454164387962*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + -0.06362970408750801*swish(-0.9928729682863509 + 0.9588446333785003*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + 0.7154937103302039*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + -0.17921833371514895*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.7009330672719543*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.15311755902026114*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5])))) + swish(0.9122346082558659 + 0.2864216745322903*swish(0.06165362792774953 + 0.6866075626761576*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.8737233458006566*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + -0.3942911833193632*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + 0.6872447034250162*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.5711071882051262*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + 0.7014729451110155*swish(0.8058455478649482 + 0.7751639240502244*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.13474005943220124*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.6437669970537465*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + 0.5932192098608322*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.5325023046383324*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + -0.27913045286088156*swish(-0.1540966309548315 + 0.690406062481447*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + 0.4718956794952942*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.8703243890856593*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.8079540211479861*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.683716372184894*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + 0.014698309183167169*swish(-0.2486694730930381 + -0.9006272851005916*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.9841514005441985*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.7501520395123897*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.43486617405885397*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + -0.4797454164387962*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + -0.9872323021033105*swish(-0.9928729682863509 + 0.9588446333785003*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + 0.7154937103302039*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + -0.17921833371514895*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.7009330672719543*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.15311755902026114*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5])))) + swish(0.6835137249354726 + 0.06184589975771315*swish(0.06165362792774953 + 0.6866075626761576*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.8737233458006566*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + -0.3942911833193632*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + 0.6872447034250162*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.5711071882051262*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + 0.6514470819403977*swish(0.8058455478649482 + 0.7751639240502244*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.13474005943220124*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.6437669970537465*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + 0.5932192098608322*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.5325023046383324*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + 0.1907919388573478*swish(-0.1540966309548315 + 0.690406062481447*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + 0.4718956794952942*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.8703243890856593*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.8079540211479861*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.683716372184894*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + 0.3162639033084287*swish(-0.2486694730930381 + -0.9006272851005916*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + -0.9841514005441985*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + 0.7501520395123897*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.43486617405885397*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + -0.4797454164387962*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5]))) + 0.2338844135686573*swish(-0.9928729682863509 + 0.9588446333785003*swish(0.28804974063451105 + 0.7911631812636903*$(x[1]) + 0.6415196610101699*$(x[2]) + -0.09319048786154349*$(x[3]) + 0.5261383650120517*$(x[4]) + -0.5505775194565721*$(x[5])) + 0.7154937103302039*swish(0.7342872210188394 + 0.669146525148411*$(x[1]) + 0.2634123220650846*$(x[2]) + -0.9804313836692913*$(x[3]) + 0.770312239258653*$(x[4]) + 0.24263357188873957*$(x[5])) + -0.17921833371514895*swish(-0.6886620050375161 + 0.8091467022606786*$(x[1]) + 0.910808980108254*$(x[2]) + -0.3183669784784451*$(x[3]) + 0.5442365253482557*$(x[4]) + -0.6054042374016482*$(x[5])) + -0.7009330672719543*swish(0.5813944367886887 + 0.520001186683257*$(x[1]) + -0.3951433421155799*$(x[2]) + 0.803037085072233*$(x[3]) + 0.9067157149850686*$(x[4]) + 0.001120584088625698*$(x[5])) + 0.15311755902026114*swish(-0.16131179027810427 + 0.7148051479719681*$(x[1]) + 0.7364049274130124*$(x[2]) + -0.647777979207961*$(x[3]) + 0.24628792618437867*$(x[4]) + 0.6449790156418587*$(x[5])))) - $q <= 0.0))

                     @objective(m, Min, q)

                     return m

max_stars_repo_name: PSORLab/RSActivationFunctions

max_issues_repo_name: PSORLab/RSActivationFunctions

max_forks_repo_name: PSORLab/RSActivationFunctions


text:
"""
    RSOCtoPSDBridge{T} <: Bridges.Variable.AbstractBridge

Transforms constrained variables in
[`VecMathOptInterface.RotatedSecondOrderCone`](@ref)
to constrained variables in
[`VecMathOptInterface.PositiveSemidefiniteConeTriangle`](@ref).
"""
struct RSOCtoPSDBridge{T} <: AbstractBridge
    # `t` is `variables[1]`
    # `u` is `variables[2]/2`
    # `x` is `variables[[3, 5, 8, ...]]`
    variables::Vector{MOI.VariableIndex}
    psd::Union{
        MOI.ConstraintIndex{
            MOI.VectorOfVariables,
            MOI.PositiveSemidefiniteConeTriangle,
        },
        MOI.ConstraintIndex{MOI.VectorOfVariables,MOI.Nonnegatives},
    }
    off_diag::Vector{MOI.ConstraintIndex{MOI.VariableIndex,MOI.EqualTo{T}}}
    diag::Vector{
        MOI.ConstraintIndex{MOI.ScalarAffineFunction{T},MOI.EqualTo{T}},
    }
end

function bridge_constrained_variable(
    ::Type{RSOCtoPSDBridge{T}},
    model::MOI.ModelLike,
    set::MOI.RotatedSecondOrderCone,
) where {T}
    off_diag = MOI.ConstraintIndex{MOI.VariableIndex,MOI.EqualTo{T}}[]
    diag = MOI.ConstraintIndex{MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}[]
    if set.dimension <= 2
        variables, psd = MOI.add_constrained_variables(
            model,
            MOI.Nonnegatives(set.dimension),
        )
    else
        dim = set.dimension - 1
        variables, psd = MOI.add_constrained_variables(
            model,
            MOI.PositiveSemidefiniteConeTriangle(dim),
        )
        # This is `2 * u`
        u2 = variables[3]
        k = 3
        for j in 3:dim
            k += 1
            for i in 2:(j-1)
                k += 1
                push!(
                    off_diag,
                    MOI.add_constraint(
                        model,
                        variables[k],
                        MOI.EqualTo(zero(T)),
                    ),
                )
            end
            k += 1
            func = MOIU.operate(-, T, u2, variables[k])
            push!(diag, MOI.add_constraint(model, func, MOI.EqualTo(zero(T))))
        end
        @assert k == MOIU.trimap(dim, dim)
    end
    return RSOCtoPSDBridge{T}(variables, psd, off_diag, diag)
end

function supports_constrained_variable(
    ::Type{<:RSOCtoPSDBridge},
    ::Type{MOI.RotatedSecondOrderCone},
)
    return true
end

function MOIB.added_constrained_variable_types(::Type{<:RSOCtoPSDBridge})
    return Tuple{Type}[
        (MOI.PositiveSemidefiniteConeTriangle,),
        (MOI.Nonnegatives,),
    ]
end

function MOIB.added_constraint_types(::Type{RSOCtoPSDBridge{T}}) where {T}
    return Tuple{Type,Type}[
        (MOI.VariableIndex, MOI.EqualTo{T}),
        (MOI.ScalarAffineFunction{T}, MOI.EqualTo{T}),
    ]
end

# Attributes, Bridge acting as a model
function MOI.get(bridge::RSOCtoPSDBridge, ::MOI.NumberOfVariables)::Int64
    return length(bridge.variables)
end

function MOI.get(bridge::RSOCtoPSDBridge, ::MOI.ListOfVariableIndices)
    return copy(bridge.variables)
end

function MOI.get(
    bridge::RSOCtoPSDBridge,
    ::MOI.NumberOfConstraints{MOI.VectorOfVariables,S},
)::Int64 where {S<:Union{MOI.PositiveSemidefiniteConeTriangle,MOI.Nonnegatives}}
    if bridge.psd isa MOI.ConstraintIndex{MOI.VectorOfVariables,S}
        return 1
    else
        return 0
    end
end

function MOI.get(
    bridge::RSOCtoPSDBridge,
    ::MOI.ListOfConstraintIndices{MOI.VectorOfVariables,S},
) where {S<:Union{MOI.PositiveSemidefiniteConeTriangle,MOI.Nonnegatives}}
    if bridge.psd isa MOI.ConstraintIndex{MOI.VectorOfVariables,S}
        return [bridge.psd]
    else
        return MOI.ConstraintIndex{MOI.VectorOfVariables,S}[]
    end
end

function MOI.get(
    bridge::RSOCtoPSDBridge{T},
    ::MOI.NumberOfConstraints{MOI.VariableIndex,MOI.EqualTo{T}},
)::Int64 where {T}
    return length(bridge.off_diag)
end

function MOI.get(
    bridge::RSOCtoPSDBridge{T},
    ::MOI.ListOfConstraintIndices{MOI.VariableIndex,MOI.EqualTo{T}},
) where {T}
    return copy(bridge.off_diag)
end

function MOI.get(
    bridge::RSOCtoPSDBridge{T},
    ::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T},MOI.EqualTo{T}},
)::Int64 where {T}
    return length(bridge.diag)
end

function MOI.get(
    bridge::RSOCtoPSDBridge{T},
    ::MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{T},MOI.EqualTo{T}},
) where {T}
    return copy(bridge.diag)
end

# References
function MOI.delete(model::MOI.ModelLike, bridge::RSOCtoPSDBridge)
    for ci in bridge.diag
        MOI.delete(model, ci)
    end
    MOI.delete(model, bridge.variables)
    return
end

# Attributes, Bridge acting as a constraint

function MOI.get(::MOI.ModelLike, ::MOI.ConstraintSet, bridge::RSOCtoPSDBridge)
    if bridge.psd isa
       MOI.ConstraintIndex{MOI.VectorOfVariables,MOI.Nonnegatives}
        dim = length(bridge.variables)
    else
        dim = length(bridge.diag) + 3
    end
    return MOI.RotatedSecondOrderCone(dim)
end

function _variable_map(bridge::RSOCtoPSDBridge, i::MOIB.IndexInVector)
    if bridge.psd isa
       MOI.ConstraintIndex{MOI.VectorOfVariables,MOI.Nonnegatives}
        return i.value
    elseif i.value == 1
        return 1
    elseif i.value == 2
        return 3
    else
        return MOIU.trimap(1, i.value - 1)
    end
end

function _variable(bridge::RSOCtoPSDBridge, i::MOIB.IndexInVector)
    return bridge.variables[_variable_map(bridge, i)]
end

function MOI.get(
    model::MOI.ModelLike,
    attr::MOI.ConstraintPrimal,
    bridge::RSOCtoPSDBridge,
)
    values = MOI.get(model, attr, bridge.psd)
    n = MOI.dimension(MOI.get(model, MOI.ConstraintSet(), bridge))
    mapped = [values[_variable_map(bridge, MOIB.IndexInVector(i))] for i in 1:n]
    if length(mapped) >= 2
        mapped[2] /= 2
    end
    return mapped
end

function MOI.get(
    model::MOI.ModelLike,
    attr::MOI.ConstraintDual,
    bridge::RSOCtoPSDBridge,
)
    dual = MOI.get(model, attr, bridge.psd)
    n = MOI.dimension(MOI.get(model, MOI.ConstraintSet(), bridge))
    mapped = [dual[_variable_map(bridge, MOIB.IndexInVector(i))] for i in 1:n]
    for ci in bridge.diag
        mapped[2] += MOI.get(model, attr, ci)
    end
    for i in 2:length(mapped)
        # For `i = 2`, we multiply by 2 because it is `2u`.
        # For `i > 2`, we multiply by 2 because to account for the difference
        # of scalar product `MOIU.set_dot`.
        mapped[i] *= 2
    end
    return mapped
end

function MOI.get(
    model::MOI.ModelLike,
    attr::MOI.VariablePrimal,
    bridge::RSOCtoPSDBridge,
    i::MOIB.IndexInVector,
)
    value = MOI.get(model, attr, _variable(bridge, i))
    if i.value == 2
        return value / 2
    else
        return value
    end
end

function MOIB.bridged_function(
    bridge::RSOCtoPSDBridge{T},
    i::MOIB.IndexInVector,
) where {T}
    func = _variable(bridge, i)
    if i.value == 2
        return MOIU.operate(/, T, func, convert(T, 2))
    else
        return convert(MOI.ScalarAffineFunction{T}, func)
    end
end

function unbridged_map(
    bridge::RSOCtoPSDBridge{T},
    vi::MOI.VariableIndex,
    i::MOIB.IndexInVector,
) where {T}
    if i.value == 2
        func = MOIU.operate(*, T, convert(T, 2), vi)
    else
        func = convert(MOI.ScalarAffineFunction{T}, vi)
    end
    return (_variable(bridge, i) => func,)
end


text:
# Copyright (c) 2018: Matthew Wilhelm & Matthew Stuber.
# This code is licensed under MIT license (see LICENSE.md for full details)
#############################################################################
# EAGO
# A development environment for robust and global optimization
# See https://github.com/PSORLab/EAGO.jl
#############################################################################
# src/eago_optimizer/node_bb.jl
# Defines storage for a node in the B&B tree & utilities functions
#############################################################################
@enum(BranchDirection, BD_NONE, BD_NEG, BD_POS)

"""
$(TYPEDEF)

Stores information associated with each node in Branch & Bound tree.

$(TYPEDFIELDS)
"""
struct NodeBB{N,T<:AbstractFloat}
    "Lower bounds of variable box."
    lower_variable_bound::NTuple{N,T}
    "Upper bounds of variable box."
    upper_variable_bound::NTuple{N,T}
    "Lower bound of problem solution on nodeBB"
    lower_bound::T
    "Upper bound of problem solution on nodeBB"
    upper_bound::T
    "Depth of node in B&B tree."
    depth::Int
    "Unique id for each node."
    id::Int
    "Last Variable Branched On"
    last_branch::Int
    "Branch Direction"
    branch_direction::BranchDirection
end

# Constructors
function NodeBB{N,T}() where {N,T<:AbstractFloat}
    NodeBB{N,T}(ntuple(x->zero(T), N),
                ntuple(x->zero(T), N),
                -Inf, Inf, 0, 1, 0, BD_NONE)
end
function NodeBB(x::NodeBB{N,T}) where {N,T<:AbstractFloat}
    NodeBB{N,T}(x.lower_variable_bound, x.upper_variable_bound,
                x.lower_bound, x.upper_bound, x.depth, x.id,
                x.last_branch, x.branch_direction)
end

# Copy utilities
function Base.copy(x::NodeBB{N,T}) where {N,T<:AbstractFloat}
    NodeBB{N,T}(x.lower_variable_bound,
                x.upper_variable_bound,
                x.lower_bound, x.upper_bound,
                x.depth, x.id, x.last_branch, x.branch_direction)
end

# Access functions for broadcasting data easily
lower_variable_bound(x::NodeBB{N,T}) where {N,T<:AbstractFloat} = x.lower_variable_bound
upper_variable_bound(x::NodeBB{N,T}) where {N,T<:AbstractFloat} = x.upper_variable_bound
Base.@propagate_inbounds lower_variable_bound(x::NodeBB{N,T}, i::Int) where {N,T<:AbstractFloat} = x.lower_variable_bound[i]
Base.@propagate_inbounds upper_variable_bound(x::NodeBB{N,T}, i::Int) where {N,T<:AbstractFloat} = x.upper_variable_bound[i]
Base.@propagate_inbounds lower_variable_bound(x::NodeBB{N,T}, id::Int, nid::Int) where {N,T<:AbstractFloat} = x.lower_variable_bound[id:nid]
Base.@propagate_inbounds upper_variable_bound(x::NodeBB{N,T}, id::Int, nid::Int) where {N,T<:AbstractFloat} = x.upper_variable_bound[id:nid]
lower_bound(x::NodeBB{N,T}) where {N,T<:AbstractFloat} = x.lower_bound
upper_bound(x::NodeBB{N,T}) where {N,T<:AbstractFloat} = x.upper_bound
depth(x::NodeBB) = x.depth
last_branch(x::NodeBB) = x.last_branch
branch_direction(x::NodeBB) = x.branch_direction

# Iterations Functions
Base.isless(x::NodeBB{N,T}, y::NodeBB{N,T}) where {N,T<:AbstractFloat} = x.lower_bound < y.lower_bound
Base.length(x::NodeBB{N,T}) where {N,T<:AbstractFloat} = N
function Base.isempty(x::NodeBB{N,T}) where {N,T<:AbstractFloat}
    for i = 1:N
        lower = @inbounds x.lower_variable_bound[i]
        upper = @inbounds x.upper_variable_bound[i]
        (lower > upper) && (return true)
    end
    return false
end

"""
$(FUNCTIONNAME)

Checks that node `x` and `y` have equal domains withing a tolerance of `atol`.
"""
function same_box(x::NodeBB{N,T}, y::NodeBB{N,T}, r::T) where {N,T<:AbstractFloat}
    for i = 1:N
        ~isapprox(x.lower_variable_bound[i], y.lower_variable_bound[i], atol=r) && (return false)
        ~isapprox(x.upper_variable_bound[i], y.upper_variable_bound[i], atol=r) && (return false)
    end
    return true
end

# Compute middle & diameter
diam(x::NodeBB{N,T}) where {N,T<:AbstractFloat} = x.upper_variable_bound - x.lower_variable_bound
mid(x::NodeBB{N,T}) where {N,T<:AbstractFloat} = 0.5*(x.upper_variable_bound + x.lower_variable_bound)
Base.@propagate_inbounds mid(x::NodeBB{N,T}, i) where {N,T<:AbstractFloat} = 0.5*(x.upper_variable_bound[i] + x.lower_variable_bound[i])


text:
using HDF5

abstract type Solution{dType, tType, N} end
abstract type DeterministicSolution{dType, tType, N} <: Solution{dType, tType, N} end
abstract type StochasticSolution{dType, tType, NQ, NW} <: Solution{dType, tType, NQ} end

timesteps(sol::Solution) = error("time() not implemented for ", typeof(sol))
hdf5(sol::Solution)   = error("hdf5() not implemented for ", typeof(sol))
ntime(sol::Solution)  = error("ntime() not implemented for ", typeof(sol))
nsave(sol::Solution)  = error("nsave() not implemented for ", typeof(sol))
offset(sol::Solution) = error("offset() not implemented for ", typeof(sol))

create_hdf5(sol::Solution, file) = error("create_hdf5() not implemented for ", typeof(sol))
CommonFunctions.write_to_hdf5(sol::Solution, h5::HDF5File, offset=0) = error("write_to_hdf5() not implemented for ", typeof(sol))

conv(sol::StochasticSolution) = error("conv() not implemented for ", typeof(sol))

nsamples(sol::DeterministicSolution) = sol.ni
nsamples(sol::StochasticSolution) = sol.ns

CommonFunctions.eachtimestep(sol::Solution) = 1:sol.nt*sol.nsave
CommonFunctions.eachsample(sol::Solution) = 1:nsamples(sol)

"Create solution for ODE."
function Solution(equation::AbstractEquationODE, Δt, ntime::Int; kwargs...)
    SSolutionODE(equation, Δt, ntime; kwargs...)
end

"Create solution for partitioned ODE."
function Solution(equation::AbstractEquationPODE, Δt, ntime::Int; kwargs...)
    SSolutionPODE(equation, Δt, ntime; kwargs...)
end

"Create solution for DAE."
function Solution(equation::AbstractEquationDAE, Δt, ntime::Int; kwargs...)
    SSolutionDAE(equation, Δt, ntime; kwargs...)
end

"Create solution for partitioned DAE."
function Solution(equation::AbstractEquationPDAE, Δt, ntime::Int; kwargs...)
    SSolutionPDAE(equation, Δt, ntime; kwargs...)
end

"Create solution for SDE."
function Solution(equation::SDE, Δt, ntime::Int; kwargs...)
    SSolutionSDE(equation, Δt, ntime; kwargs...)
end

function Solution(equation::SDE, Δt, dW, dZ, ntime::Int; kwargs...)
    SSolutionSDE(equation, Δt, dW, dZ, ntime; kwargs...)
end

"Create solution for PSDE."
function Solution(equation::Union{PSDE,SPSDE}, Δt, ntime::Int; kwargs...)
    SSolutionPSDE(equation, Δt, ntime; kwargs...)
end

function Solution(equation::Union{PSDE,SPSDE}, Δt, dW, dZ, ntime::Int; kwargs...)
    SSolutionPSDE(equation, Δt, dW, dZ, ntime; kwargs...)
end

"Print error for solutions of equations not implemented, yet."
function Solution(equation::Equation, Δt, ntime::Int; kwargs...)
    error("No solution found for equation ", equation)
end

"Create parallel solution for ODE."
function ParallelSolution(equation::AbstractEquationODE, Δt, ntime::Int; kwargs...)
    PSolutionODE(equation, Δt, ntime; kwargs...)
end

"Create parallel solution for partitioned ODE."
function ParallelSolution(equation::AbstractEquationPODE, Δt, ntime::Int; kwargs...)
    PSolutionPODE(equation, Δt, ntime; kwargs...)
end

"Create parallel solution for DAE."
function ParallelSolution(equation::AbstractEquationDAE, Δt, ntime::Int; kwargs...)
    PSolutionDAE(equation, Δt, ntime; kwargs...)
end

"Create parallel solution for partitioned DAE."
function ParallelSolution(equation::AbstractEquationPDAE, Δt, ntime::Int; kwargs...)
    PSolutionPDAE(equation, Δt, ntime; kwargs...)
end

"Create parallel solution for SDE."
function ParallelSolution(equation::SDE, Δt, ntime::Int; kwargs...)
    PSolutionSDE(equation, Δt, ntime; kwargs...)
end

"Create parallel solution for PSDE."
function ParallelSolution(equation::Union{PSDE,SPSDE}, Δt, ntime::Int; kwargs...)
    PSolutionPSDE(equation, Δt, ntime; kwargs...)
end

"Print error for parallel solutions of equations not implemented, yet."
function ParallelSolution(equation::Equation, Δt, ntime::Int; kwargs...)
    error("No parallel solution found for equation ", equation)
end


text:
#
# Denoise an S2 valued image demonstrating the effect of using different base points m
#
# L2-TV functional with anisotropic TV
#
# This example is used in Section 6.2 of
#
# > R. Bergmann, R. Herzog, M. Silva Louzeiro, D. Tenbrinck, J. Vidal Núñez:
# > _Fenchel Duality Theory and a Primal-Dual Algorithm on Riemannian Manifolds_,
# > arXiv: [1908.02022](https://arxiv.org/abs/1908.02022)
#
using CSV, DataFrames, LinearAlgebra, Manopt, Manifolds
#
# Settings
experiment_name = "S2_WhirlImage_CP"
export_orig = false
export_primal = false
export_primal_video = false
export_table = false
asy_render_size = 2
#
# Automatic Settings
export_any = export_orig || export_primal || export_primal_video || export_table
results_folder = joinpath(@__DIR__, "Image_TV")
video_folder = joinpath(results_folder, "video")
(export_any && !isdir(results_folder)) && mkdir(results_folder)
(export_primal_video && !isdir(video_folder)) && mkdir(video_folder)
#
# Experiment Parameters
σ = 0.25
τ = 0.25
γ = 0.2
θ = 1.0
α = 1.5
#
# Data
pixelM = Sphere(2)
f = artificial_S2_whirl_image(64)
#
# load TV model
#
include("Image_TV_commons.jl")

if export_orig
    orig_file = joinpath(results_folder, experiment_name * "-orig.asy")
    asymptote_export_S2_data(orig_file; data=f)
    render_asymptote(orig_file; render=asy_render_size)
end
struct DebugRenderAsy <: DebugAction
    name::String
    folder::String
    DebugRenderAsy(f, n) = new(n, f)
end
function (d::DebugRenderAsy)(::PrimalDualProblem, ::ChambollePockOptions, i)
    if i >= 0
        orig_file = joinpath(d.folder, d.name * "-vid-$(lpad(i[1],7,"0")).asy")
        asymptote_export_S2_data(orig_file; data=f)
        render_asymptote(orig_file; render=asy_render_size)
    end
end
#
# Experiments (entries overwrite defaults from below)
data_mean = mean(pixelM, vec(f), GradientDescentEstimation(); stop_iter=5)
mean_image = fill(data_mean, size(f))
west_image = fill([1.0, 0.0, 0.0], size(f))
#
# Build Experiments
experiments = [
    Dict(:name => "mMean", :m => deepcopy(mean_image)),
    Dict(:name => "mWest", :m => deepcopy(west_image)),
]

#
# Defaults
x0 = deepcopy(f)
m = deepcopy(mean_image)
records = Array{Array{Tuple{Int,Float64,Array},1},1}()
for e in experiments
    name = e[:name]
    print("\n --- Running Experiment $name ---")
    println(
        " Values σ:",
        get(e, :σ, σ),
        " | τ:",
        get(e, :τ, τ),
        " | θ:",
        get(e, :θ, θ),
        " | γ:",
        get(e, :γ, γ),
    )
    #
    # Any Entry in the dictionary overwrites the above default
    @time o = ChambollePock(
        M,
        N,
        cost,
        get(e, :x, x0),
        get(e, :ξ, zero_vector(N, get(e, :n, Λ(get(e, :m, m))))),
        get(e, :m, m),
        get(e, :n, Λ(get(e, :m, m))),
        proxFidelity,
        proxPriorDual,
        AdjDΛ;
        linearized_forward_operator=DΛ,
        primal_stepsize=get(e, :σ, σ),
        dual_stepsize=get(e, :τ, τ),
        relaxation=get(e, :θ, θ),
        acceleration=get(e, :γ, γ),
        relax=:dual,
        debug=[
            :Iteration,
            " | ",
            :Cost,
            "\n",
            export_primal_video ? DebugRenderAsy(video_folder, experiment_name * name) : "",
            100,
            :Stop,
        ],
        record=[:Iteration, :Cost, :Iterate],
        stopping_criterion=StopAfterIteration(get(e, :maxIter, 300)),
        variant=:linearized,
        return_options=true,
    )
    push!(records, get_record(o))
    if export_primal
        result_file = joinpath(results_folder, experiment_name * "-result.asy")
        asymptote_export_S2_data(result_file; data=get_solver_result(o))
        render_asymptote(result_file; render=asy_render_size)
    end
    if export_primal_video
        source = join_path(video_folder, experiment_name * name * "-vid-*.png")
        dest = join_path(results_folder, experiment_name * name * ".mp4")
        # run(`ffmpeg -framerate 15 -pattern_type glob -i $(source) -c:v libx264 -vf pad=ceil\(iw/2\)*2:ceil\(ih/2\)*2 -pix_fmt yuv420p $(dest)`)
    end
end
#
# Finalize - export costs
if export_table
    A = cat(
        first.(records[1]),
        [[r[2] for r in records[i]] for i in 1:length(records)]...;
        dims=2,
    )
    CSV.write(
        joinpath(results_folder, experiment_name * "-Result.csv"),
        DataFrame(A);
        header=["i", [e[:name] for e in experiments]...],
    )
end


text:
f(x::Vector) = (1.0 - x[1])^2
function g!(x::Vector, storage::Vector)
	storage[1] = -2.0 * (1.0 - x[1])
end

x = [0.0]
gradient = [0.0]
ls_x = [0.0]
ls_gradient = [0.0]
g!(x, gradient)
dx = -gradient
d = DifferentiableFunction(f, g!)

t, f_up, g_up = Optim.backtracking_line_search!(d, x, dx, ls_x, ls_gradient)
@assert f(x + t * dx) < f(x) + 0.9 * t * -dot(gradient, dx)


text:
using Genie.Router
using IndexController
using ClassifyController

route("/", IndexController.index)
route("/index", IndexController.index)

route("/classify", ClassifyController.anno)
route("/classify/submit", ClassifyController.submit, method = POST, named = :submit_classify)
# route("/classify/save", ClassifyController.save, method = POST, named = :save_classify)


text:
# artificial_dissipation.jl
# this file contains all the functions needede to construct and apply
# artificial dissipation

@doc """
### EulerEquationMod.applyDissipation

  This function multiplies the dissipation matrix operator for each element
  by the values in a 3D array (typically eqn.q) for each node of the element
  and stores the results in eqn.res.

  The dissipation matrix operators must be stored in
  eqn.dissipation_mat, a numNodesPerElement x numNodesPerElement x numEl array.

  Inputs:
    mesh
    sbp
    eqn
    opts
    arr: a 3D array to apply the dissipation matrix to

  Aliasing restrictions: no guarantees what happens if arr is eqn.res

"""->
function applyDissipation(mesh::AbstractMesh{Tmsh},
           sbp::AbstractOperator, eqn::AbstractSolutionData{Tsol},
           opts, arr::AbstractArray{T, 3}) where {Tmsh, Tsol, T}
# applies the artificial dissipation to the array arr
# arr must be mesh.numDofPerNode by sbp.numNodesPerElement by mesh.numEl

  # holds the filtered q variables
  q_filt = zeros(Tsol, mesh.numNodesPerElement, mesh.numDofPerNode)
  len = mesh.numNodesPerElement*mesh.numDofPerNode
  for i=1:mesh.numEl
    filt_i = sview(eqn.dissipation_mat, :, :, i)
    q_vals = sview(eqn.q, :, :, i)  # mesh.numDofPerNode x sbp.numnodes
    # apply filter matrix to q_vals transposed, so it is applied to
    # all the rho components, then all the x momentum, etc.
    smallmatmatT!(filt_i, q_vals, q_filt)

    # update eqn.res, remembering to transpose q_filt
    for j=1:mesh.numNodesPerElement
      for k=1:mesh.numDofPerNode
        eqn.res[k, j, i] -= q_filt[j, k]
      end
    end

  end  # end loop over elements

  return nothing
end

@doc """
### EulerEquationMod.calcDissipationOperator

  This function calculates the numNodesPerElement x numNodesPerElement
  dissipation matrix operator for each element and returns them in an array
  numNodesPerElement x numNodesPerElement x numEl array.

  The dissipation matrix operator is calculated as epsilon*filt.'*h_jac*filt,
  where filt is a (usually diagonal) filter matrix, h_jac is a scaling term
  that incorporates information about the shape of the element.

  Inputs:
    mesh
    sbp
    eqn
    opts
    dissipation_name: an String of the function name used to retrieve
                      the function that generates the matrix filt from a
                      dictonary

  Outputs:
    dissipation_mat: a numNodesPerElement x numNodesPerElement x numEl array

    Aliasing restrictions: none

"""->
function calcDissipationOperator(mesh::AbstractMesh{Tmsh},
                     sbp::AbstractOperator, eqn::AbstractEulerData{Tsol},
                     opts, dissipation_name::String) where {Tmsh, Tsol}
# calculates and returns the artificial dissipation operator array

  epsilon = eqn.params.dissipation_const  # dissipation constant

  # get the dissipation filter matrix for the reference element
  dissipation_func = dissipation_dict[dissipation_name]
  filt = getDissipationFilterOperator(sbp, dissipation_func)

  # store a sbp.numnodes square matrix for each element
  dissipation_mat = zeros(Tmsh, sbp.numnodes, sbp.numnodes, mesh.numEl)

  # filter matrix for a non-reference element
  filt_i = Array{Tmsh}(sbp.numnodes, sbp.numnodes)
  hinv = inv(diagm(sbp.w))
  h = diagm(sbp.w)
  for i=1:mesh.numEl
    # modify filter matrix to be in real (non reference) space
#=
    for col = 1:sbp.numnodes
      for row = 1:sbp.numnodes
  filt_i[row, col] = filt[row, col]/mesh.jac[row, i]
      end
    end
=#
    # scale the mass (digonal) mass matrix by jacobian determinent
    # then multiply by h = (1/jac)^(1/p)
#    h_jac = sbp.w./(mesh.jac[:, i].^2.0)

    h_jac = sbp.w./(mesh.jac[:, i].^1.5)
    # JC modification 11/4
#    h_jac = sbp.w./(mesh.jac[:, i])

    h_jac_inv = 1./h_jac

    # this is the proper artificial dissipation
    dissipation_mat[:, :, i] = epsilon*filt.'*diagm(h_jac)*filt

    # this is the used for preconditioning the iterative solver
#    dissipation_mat[:, :, i] = epsilon*filt.'*diagm(sbp.w)*filt
  end  # end loop over elements

  return dissipation_mat

end  # end function

@doc """
### EulerEquatoinMod.getDissipatoinFilterOperator

  This function gets the dissipation filter operator used to construction
  the artificial dissipation matrix.

  The filter is calculated as V*filter_kernel*inv(V), where V is a matrix
  that converts the interpolating SBP basis to a modal basis and filter_kernal
  is a matrix (typically diagonal) that performs the filtering of the modal
  basis coefficients.

  Inputs:
    sbp: SBP operator
    filter: function to call to calculate the filter kernal

  Outputs:
    F: a numNodesPerElement x numNodesPerElement filter matrix
"""->
function getDissipationFilterOperator(sbp::TriSBP{T}, filter::Function) where T
# calculate the filter operator (including the conversion to and from
# the modal basis) used for artificial dissipation
# the filter function defines the filter kernel

  vtx = [-1. -1.; 1. -1.; -1. 1.]
  x, y = SummationByParts.SymCubatures.calcnodes(sbp.cub, vtx)
  # loop over ortho polys up to degree d
  d = sbp.degree
  eta_c = (d-1)/(d+1)
  s = d
  alpha = 36.0

  V = zeros(T, (sbp.numnodes, div((d+1)*(d+2), 2)) )
#  V = zeros(T, (sbp.numnodes, convert(Int, (d+1)*(d+2)/2)) )
  lambda = zeros(T, (sbp.numnodes) )
  ptr = 0
  for r = 0:d
    for j = 0:r
      i = r-j
      V[:,ptr+1] = SummationByParts.OrthoPoly.proriolpoly(x, y, i, j)
      #TODO: generalize the filter interface
      lambda[ptr+1] = 1.0 - filter(r/(d+1), eta_c, alpha, s)
      ptr += 1
    end
  end
  lambda[ptr+1:end] = 1.0
  #println("lambda = ",lambda)

  Z = nullspace(V')
  Vt = [V Z]
  F = Vt*diagm(lambda)*inv(Vt)
  return F
end

function damp1(eta, eta_c, alpha, s)
  if (eta <= eta_c)
    return 1.0
  else
    return exp(-alpha*((eta-eta_c)/(1-eta_c))^(2*s))
  end
end

global const dissipation_dict = Dict{String, Function}(
"damp1" => damp1
)


text:
using Pkg;
Pkg.add("PyPlot");
Pkg.add("IJulia");
Pkg.add(url="https://github.com/OpenJAC/JAC.jl")