text:
"""
    MOBIL
See Treiber & Kesting, 'Modeling Lane-Changing Decisions with MOBIL'

# Constructor
	MOBIL(timestep::Float64;rec::SceneRecord=SceneRecord(2,timestep), mlon::LaneFollowingDriver=IntelligentDriverModel(),safe_decel::Float64=2.0,       politeness::Float64=0.35,advantage_threshold::Float64=0.1)

# Fields
- `dir::Int`
- `rec::SceneRecord`
- `mlon::LaneFollowingDriver=IntelligentDriverModel()`
- `safe_decel::Float64=2.0`
- `politeness::Float64=0.35`
- `advantage_threshold::Float64=0.1`
"""
@with_kw mutable struct MOBIL <: LaneChangeModel{LaneChangeChoice}
    dir::Int64
    rec::SceneRecord
    mlon::LaneFollowingDriver
    safe_decel::Float64 # safe deceleration (positive value)
    politeness::Float64 # politeness factor (suggested p ∈ [0.2,0.5])
    advantage_threshold::Float64 # Δaₜₕ
end

function MOBIL(
    timestep::Float64;
    rec::SceneRecord=SceneRecord(2,timestep),
    mlon::LaneFollowingDriver=IntelligentDriverModel(),
    safe_decel::Float64=2.0, # [m/s²]
    politeness::Float64=0.35,
    advantage_threshold::Float64=0.1,
    )
    return MOBIL(DIR_MIDDLE, rec, mlon, safe_decel, politeness, advantage_threshold)
end

"""
Return the name of the lane changing model
"""
get_name(::MOBIL) = "MOBIL"

"""
Set the desired speed of the longitudinal model within MOBIL
"""
function set_desired_speed!(model::MOBIL, v_des::Float64)
    set_desired_speed!(model.mlon, v_des)
    model
end
function observe!(model::MOBIL, scene::Frame{Entity{S, D, I}}, roadway::Roadway, egoid::I) where {S, D, I}

    rec = model.rec
    update!(rec, scene)

    vehicle_index = findfirst(egoid, rec[0])
    veh_ego = scene[vehicle_index]
    v = vel(veh_ego.state)
    egostate_M = veh_ego.state

    left_lane_exists = convert(Float64, get(N_LANE_LEFT, rec, roadway, vehicle_index)) > 0
    right_lane_exists = convert(Float64, get(N_LANE_RIGHT, rec, roadway, vehicle_index)) > 0
    fore_M = get_neighbor_fore_along_lane(scene, vehicle_index, roadway, VehicleTargetPointFront(), VehicleTargetPointRear(), VehicleTargetPointFront())
    rear_M = get_neighbor_rear_along_lane(scene, vehicle_index, roadway, VehicleTargetPointFront(), VehicleTargetPointFront(), VehicleTargetPointRear())

    # accel if we do not make a lane change
    accel_M_orig = rand(observe!(reset_hidden_state!(model.mlon), scene, roadway, egoid)).a
    model.dir = DIR_MIDDLE

    advantage_threshold = model.advantage_threshold

    if left_lane_exists

        rear_L = get_neighbor_rear_along_left_lane(scene, vehicle_index, roadway, VehicleTargetPointFront(), VehicleTargetPointFront(), VehicleTargetPointRear())

        # candidate position after lane change is over
        footpoint = get_footpoint(veh_ego)
        lane = get_lane(roadway, veh_ego)
        lane_L = roadway[LaneTag(lane.tag.segment, lane.tag.lane + 1)]
        roadproj = proj(footpoint, lane_L, roadway)
        frenet_L = Frenet(RoadIndex(roadproj), roadway)
        egostate_L = VehicleState(frenet_L, roadway, vel(veh_ego.state))

        Δaccel_n = 0.0
        passes_safety_criterion = true
        if rear_L.ind != nothing
            id = scene[rear_L.ind].id
            accel_n_orig = rand(observe!(reset_hidden_state!(model.mlon), scene, roadway, id)).a

            # update ego state in scene
            scene[vehicle_index] = Entity(veh_ego, egostate_L)
            accel_n_test = rand(observe!(reset_hidden_state!(model.mlon), scene, roadway, id)).a

            body = inertial2body(get_rear(scene[vehicle_index]), get_front(scene[rear_L.ind])) # project ego to be relative to target
            s_gap = body.x

            # restore ego state
            scene[vehicle_index] = veh_ego
            passes_safety_criterion = accel_n_test ≥ -model.safe_decel && s_gap ≥ 0
            Δaccel_n = accel_n_test - accel_n_orig
        end

        if passes_safety_criterion

            Δaccel_o = 0.0
            if rear_M.ind != nothing
                id = scene[rear_M.ind].id
                accel_o_orig = rand(observe!(reset_hidden_state!(model.mlon), scene, roadway, id)).a

                # update ego state in scene
                scene[vehicle_index] = Entity(veh_ego, egostate_L)
                accel_o_test = rand(observe!(reset_hidden_state!(model.mlon), scene, roadway, id)).a

                # restore ego state
                scene[vehicle_index] = veh_ego
                Δaccel_o = accel_o_test - accel_o_orig
            end

            # update ego state in scene
            scene[vehicle_index] = Entity(veh_ego, egostate_L)
            accel_M_test = rand(observe!(reset_hidden_state!(model.mlon), scene, roadway, egoid)).a
            # restore ego state
            scene[vehicle_index] = veh_ego

            Δaccel_M = accel_M_test - accel_M_orig

            Δaₜₕ = Δaccel_M + model.politeness*(Δaccel_n + Δaccel_o)

            if Δaₜₕ > advantage_threshold
                model.dir = DIR_LEFT
                advantage_threshold = Δaₜₕ
            end
        end
    end

    if right_lane_exists

        rear_R = get_neighbor_rear_along_right_lane(scene, vehicle_index, roadway, VehicleTargetPointFront(), VehicleTargetPointFront(), VehicleTargetPointRear())

        # candidate position after lane change is over
        footpoint = get_footpoint(veh_ego)
        lane = roadway[veh_ego.state.posF.roadind.tag]
        lane_R = roadway[LaneTag(lane.tag.segment, lane.tag.lane - 1)]
        roadproj = proj(footpoint, lane_R, roadway)
        frenet_R = Frenet(RoadIndex(roadproj), roadway)
        egostate_R = VehicleState(frenet_R, roadway, vel(veh_ego.state))

        Δaccel_n = 0.0
        passes_safety_criterion = true
        if rear_R.ind != nothing
            id = scene[rear_R.ind].id
            accel_n_orig = rand(observe!(reset_hidden_state!(model.mlon), scene, roadway, id)).a

            # update ego vehicle in scene
            scene[vehicle_index] = Entity(veh_ego, egostate_R)
            accel_n_test = rand(observe!(reset_hidden_state!(model.mlon), scene, roadway, id)).a

            body = inertial2body(get_rear(scene[vehicle_index]), get_front(scene[rear_R.ind])) # project ego to be relative to target
            s_gap = body.x

            # restore ego vehicle state
            scene[vehicle_index] = veh_ego

            passes_safety_criterion = accel_n_test ≥ -model.safe_decel && s_gap ≥ 0
            Δaccel_n = accel_n_test - accel_n_orig
        end

        if passes_safety_criterion

            Δaccel_o = 0.0
            if rear_M.ind != nothing
                id = scene[rear_M.ind].id
                accel_o_orig = rand(observe!(reset_hidden_state!(model.mlon), scene, roadway, id)).a

                # update ego vehicle in scene
                scene[vehicle_index] = Entity(veh_ego, egostate_R)
                accel_o_test = rand(observe!(reset_hidden_state!(model.mlon), scene, roadway, id)).a
                # restore ego vehicle state
                scene[vehicle_index] = veh_ego

                Δaccel_o = accel_o_test - accel_o_orig
            end

            # update ego vehicle in scene
            scene[vehicle_index] = Entity(veh_ego, egostate_R)
            accel_M_test = rand(observe!(reset_hidden_state!(model.mlon), scene, roadway, egoid)).a
            # restor ego vehicle state
            scene[vehicle_index] = veh_ego

            Δaccel_M = accel_M_test - accel_M_orig

            Δaₜₕ = Δaccel_M + model.politeness*(Δaccel_n + Δaccel_o)
            if Δaₜₕ > advantage_threshold
                model.dir = DIR_RIGHT
                advantage_threshold = Δaₜₕ
            elseif Δaₜₕ == advantage_threshold
                # in case of tie, if we are accelerating we go left, else, right
                if Δaccel_M > model.politeness*(Δaccel_n + Δaccel_o)
                    model.dir = DIR_LEFT
                else
                    model.dir = DIR_RIGHT
                end
            end
        end
    end

    model
end
Base.rand(rng::AbstractRNG, model::MOBIL) = LaneChangeChoice(model.dir)


text:
using CImGui
using CImGui.CSyntax
using CImGui.CSyntax.CStatic
using CImGui.GLFWBackend
using CImGui.OpenGLBackend
using CImGui.GLFWBackend.GLFW
using CImGui.OpenGLBackend.ModernGL
using Printf

@static if Sys.isapple()
    # OpenGL 3.2 + GLSL 150
    const glsl_version = 150
    GLFW.WindowHint(GLFW.CONTEXT_VERSION_MAJOR, 3)
    GLFW.WindowHint(GLFW.CONTEXT_VERSION_MINOR, 2)
    GLFW.WindowHint(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE) # 3.2+ only
    GLFW.WindowHint(GLFW.OPENGL_FORWARD_COMPAT, GL_TRUE) # required on Mac
else
    # OpenGL 3.0 + GLSL 130
    const glsl_version = 130
    GLFW.WindowHint(GLFW.CONTEXT_VERSION_MAJOR, 3)
    GLFW.WindowHint(GLFW.CONTEXT_VERSION_MINOR, 0)
    # GLFW.WindowHint(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE) # 3.2+ only
    # GLFW.WindowHint(GLFW.OPENGL_FORWARD_COMPAT, GL_TRUE) # 3.0+ only
end

# setup GLFW error callback
error_callback(err::GLFW.GLFWError) = @error "GLFW ERROR: code $(err.code) msg: $(err.description)"
GLFW.SetErrorCallback(error_callback)

# create window
window = GLFW.CreateWindow(1280, 720, "Demo")
@assert window != C_NULL
GLFW.MakeContextCurrent(window)
GLFW.SwapInterval(1)  # enable vsync

# setup Dear ImGui context
ctx = CImGui.CreateContext()

# setup Dear ImGui style
CImGui.StyleColorsDark()
# CImGui.StyleColorsClassic()
# CImGui.StyleColorsLight()

# load Fonts
# - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use `CImGui.PushFont/PopFont` to select them.
# - `CImGui.AddFontFromFileTTF` will return the `Ptr{ImFont}` so you can store it if you need to select the font among multiple.
# - If the file cannot be loaded, the function will return C_NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
# - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling `CImGui.Build()`/`GetTexDataAsXXXX()``, which `ImGui_ImplXXXX_NewFrame` below will call.
# - Read 'fonts/README.txt' for more instructions and details.
fonts_dir = joinpath(@__DIR__, "..", "fonts")
fonts = CImGui.GetIO().Fonts
# default_font = CImGui.AddFontDefault(fonts)
# CImGui.AddFontFromFileTTF(fonts, joinpath(fonts_dir, "Cousine-Regular.ttf"), 15)
# CImGui.AddFontFromFileTTF(fonts, joinpath(fonts_dir, "DroidSans.ttf"), 16)
# CImGui.AddFontFromFileTTF(fonts, joinpath(fonts_dir, "Karla-Regular.ttf"), 10)
# CImGui.AddFontFromFileTTF(fonts, joinpath(fonts_dir, "ProggyTiny.ttf"), 10)
CImGui.AddFontFromFileTTF(fonts, joinpath(fonts_dir, "Roboto-Medium.ttf"), 16)
# @assert default_font != C_NULL

# setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(window, true)
ImGui_ImplOpenGL3_Init(glsl_version)

show_demo_window = true
show_another_window = false
clear_color = Cfloat[0.45, 0.55, 0.60, 1.00]
while !GLFW.WindowShouldClose(window)
    # oh my global scope
    global show_demo_window
    global show_another_window
    global clear_color

    GLFW.PollEvents()
    # start the Dear ImGui frame
    ImGui_ImplOpenGL3_NewFrame()
    ImGui_ImplGlfw_NewFrame()
    CImGui.NewFrame()

    # show the big demo window
    show_demo_window && @c CImGui.ShowDemoWindow(&show_demo_window)

    # show a simple window that we create ourselves.
    # we use a Begin/End pair to created a named window.
    @cstatic f=Cfloat(0.0) counter=Cint(0) begin
        CImGui.Begin("Hello, world!")  # create a window called "Hello, world!" and append into it.
        CImGui.Text("This is some useful text.")  # display some text
        @c CImGui.Checkbox("Demo Window", &show_demo_window)  # edit bools storing our window open/close state
        @c CImGui.Checkbox("Another Window", &show_another_window)

        @c CImGui.SliderFloat("float", &f, 0, 1)  # edit 1 float using a slider from 0 to 1
        CImGui.ColorEdit3("clear color", clear_color)  # edit 3 floats representing a color
        CImGui.Button("Button") && (counter += 1)

        CImGui.SameLine()
        CImGui.Text("counter = $counter")
        CImGui.Text(@sprintf("Application average %.3f ms/frame (%.1f FPS)", 1000 / CImGui.GetIO().Framerate, CImGui.GetIO().Framerate))

        CImGui.End()
    end

    # show another simple window.
    if show_another_window
        @c CImGui.Begin("Another Window", &show_another_window)  # pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
        CImGui.Text("Hello from another window!")
        CImGui.Button("Close Me") && (show_another_window = false;)
        CImGui.End()
    end

    # rendering
    CImGui.Render()
    GLFW.MakeContextCurrent(window)
    display_w, display_h = GLFW.GetFramebufferSize(window)
    glViewport(0, 0, display_w, display_h)
    glClearColor(clear_color...)
    glClear(GL_COLOR_BUFFER_BIT)
    ImGui_ImplOpenGL3_RenderDrawData(CImGui.GetDrawData())

    GLFW.MakeContextCurrent(window)
    GLFW.SwapBuffers(window)
end

# cleanup
ImGui_ImplOpenGL3_Shutdown()
ImGui_ImplGlfw_Shutdown()
CImGui.DestroyContext(ctx)

GLFW.DestroyWindow(window)

ext: jl


text:
# This file is a part of Julia. License is MIT: https://julialang.org/license

# TODO: make this a general purpose solution
function Base.cconvert(::Type{Ptr{DiffOptionsStruct}}, pathspecs::AbstractString)
    str_ref = Base.cconvert(Ref{Cstring}, [pathspecs])
    sa = StrArrayStruct(Base.unsafe_convert(Ref{Cstring}, str_ref), 1)
    do_ref = Ref(DiffOptionsStruct(pathspec = sa))
    do_ref, str_ref
end
function Base.unsafe_convert(::Type{Ptr{DiffOptionsStruct}}, rr::Tuple{Ref{DiffOptionsStruct}, Ref{Cstring}})
    Base.unsafe_convert(Ptr{DiffOptionsStruct}, first(rr))
end

"""
    diff_tree(repo::GitRepo, tree::GitTree, pathspecs::AbstractString=""; cached::Bool=false)

Generate a [`GitDiff`](@ref) between `tree` (which will be used for the "old"
side of the [`DiffDelta`](@ref)) and `repo` (which will be used for the "new" side).
If `repo` is `cached`, calls [`git_diff_tree_to_index`](https://libgit2.github.com/libgit2/#HEAD/group/diff/git_diff_tree_to_index).
The `cached` version is generally used to examine the diff for staged changes from one
commit to the next. If `cached` is `false`, calls
[`git_diff_tree_to_workdir_with_index`](https://libgit2.github.com/libgit2/#HEAD/group/diff/git_diff_tree_to_workdir_with_index).
This compares the current working directory against the [`GitIndex`](@ref) and can,
for example, be used to examine the changes in staged files before a commit.
"""
function diff_tree(repo::GitRepo, tree::GitTree, pathspecs::AbstractString=""; cached::Bool=false)
    ensure_initialized()
    diff_ptr_ptr = Ref{Ptr{Cvoid}}(C_NULL)
    if cached
        @check ccall((:git_diff_tree_to_index, :libgit2), Cint,
                     (Ptr{Ptr{Cvoid}}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{DiffOptionsStruct}),
                     diff_ptr_ptr, repo.ptr, tree.ptr, C_NULL, isempty(pathspecs) ? C_NULL : pathspecs)
    else
        @check ccall((:git_diff_tree_to_workdir_with_index, :libgit2), Cint,
                     (Ptr{Ptr{Cvoid}}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{DiffOptionsStruct}),
                     diff_ptr_ptr, repo.ptr, tree.ptr, isempty(pathspecs) ? C_NULL : pathspecs)
    end
    return GitDiff(repo, diff_ptr_ptr[])
end

"""
    diff_tree(repo::GitRepo, oldtree::GitTree, newtree::GitTree)

Generate a [`GitDiff`](@ref) between `oldtree` (which will be used for the "old"
side of the [`DiffDelta`](@ref)) and `newtree` (which will be used for the "new"
side of the `DiffDelta`). Equivalent to [`git_diff_tree_to_tree`](https://libgit2.github.com/libgit2/#HEAD/group/diff/git_diff_tree_to_tree).
This can be used to generate a diff between two commits. For instance, it could
be used to compare a commit made 2 months ago with the current latest commit, or
to compare a commit on another branch with the current latest commit on `master`.
"""
function diff_tree(repo::GitRepo, oldtree::GitTree, newtree::GitTree)
    ensure_initialized()
    diff_ptr_ptr = Ref{Ptr{Cvoid}}(C_NULL)
    @check ccall((:git_diff_tree_to_tree, :libgit2), Cint,
                  (Ptr{Ptr{Cvoid}}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{DiffOptionsStruct}),
                   diff_ptr_ptr, repo.ptr, oldtree.ptr, newtree.ptr, C_NULL)
    return GitDiff(repo, diff_ptr_ptr[])
end

"""
    GitDiffStats(diff::GitDiff)

Get the diff statistics from the [`GitDiff`](@ref) `diff`. This object records a
summary of changes made across the `diff`. In particular, it records how many
files were changed, how many insertions were made, and how many deletions were made.
"""
function GitDiffStats(diff::GitDiff)
    ensure_initialized()
    diff_stat_ptr_ptr = Ref{Ptr{Cvoid}}(C_NULL)
    @check ccall((:git_diff_get_stats, :libgit2), Cint,
                  (Ptr{Ptr{Cvoid}}, Ptr{Cvoid}),
                  diff_stat_ptr_ptr, diff.ptr)
    return GitDiffStats(diff.owner, diff_stat_ptr_ptr[])
end

"""
    files_changed(diff_stat::GitDiffStats) -> Csize_t

Return how many files were changed (added/modified/deleted) in the [`GitDiff`](@ref)
summarized by `diff_stat`. The result may vary depending on the [`DiffOptionsStruct`](@ref)
used to generate the parent `GitDiff` of `diff_stat` (for instance, whether ignored files
are to be included or not).
"""
function files_changed(diff_stat::GitDiffStats)
    ensure_initialized()
    return ccall((:git_diff_stats_files_changed, :libgit2), Csize_t, (Ptr{Cvoid},), diff_stat.ptr)
end

"""
    insertions(diff_stat::GitDiffStats) -> Csize_t

Return the total number of insertions (lines added) in the [`GitDiff`](@ref)
summarized by `diff_stat`. The result may vary depending on the [`DiffOptionsStruct`](@ref)
used to generate the parent `GitDiff` of `diff_stat` (for instance, whether ignored files
are to be included or not).
"""
function insertions(diff_stat::GitDiffStats)
    ensure_initialized()
    return ccall((:git_diff_stats_insertions, :libgit2), Csize_t, (Ptr{Cvoid},), diff_stat.ptr)
end

"""
    deletions(diff_stat::GitDiffStats) -> Csize_t

Return the total number of deletions (lines removed) in the [`GitDiff`](@ref)
summarized by `diff_stat`. The result may vary depending on the [`DiffOptionsStruct`](@ref)
used to generate the parent `GitDiff` of `diff_stat` (for instance, whether ignored files
are to be included or not).
"""
function deletions(diff_stat::GitDiffStats)
    ensure_initialized()
    return ccall((:git_diff_stats_deletions, :libgit2), Csize_t, (Ptr{Cvoid},), diff_stat.ptr)
end

function count(diff::GitDiff)
    ensure_initialized()
    return ccall((:git_diff_num_deltas, :libgit2), Cint, (Ptr{Cvoid},), diff.ptr)
end

function Base.getindex(diff::GitDiff, i::Integer)
    if i < 1 || i > count(diff)
        throw(BoundsError(diff, (i,)))
    end
    ensure_initialized()
    delta_ptr = ccall((:git_diff_get_delta, :libgit2),
                      Ptr{DiffDelta},
                      (Ptr{Cvoid}, Csize_t), diff.ptr, i-1)
    return unsafe_load(delta_ptr)
end

function Base.show(io::IO, diff_stat::GitDiffStats)
    println(io, "GitDiffStats:")
    println(io, "Files changed: $(files_changed(diff_stat))")
    println(io, "Insertions: $(insertions(diff_stat))")
    println(io, "Deletions: $(deletions(diff_stat))")
end

function Base.show(io::IO, diff::GitDiff)
    println(io, "GitDiff:")
    println(io, "Number of deltas: $(count(diff))")
    show(io, GitDiffStats(diff))
end

max_stars_repo_name: greimel/julia

max_issues_repo_name: greimel/julia

max_forks_repo_name: greimel/julia


text:
abstract SceneItem

# -----------------------------------------------------------------------

immutable Scene <: Widget
  widget::PyObject # qt view
  scene::PyObject # qt scene
  items::Vector{SceneItem}
end

# set up the scene
function Scene(pos::P2 = P2(2000,0), sz::P2 = P2(1000,1000); show=true)

  scene = QT.QGraphicsScene()
  widget = QT.QGraphicsView(scene)

  # adjust position and window coordinates
  screenx, screeny = pos
  w, h = sz
  widget[:setGeometry](screenx, screeny, w+1, h+1)

  # w, h = size(widget[:contentsRect]()[:size]())
  # scene[:setSceneRect](-w/2, -h/2, w, h)

  if show
    showwidget(widget)
  end

  s = Scene(widget, scene, SceneItem[])
  recenterScene(s)
  currentScene!(s)
  s
end

# rescale w,h to contents size
function recenterScene(scene::Scene)
  w, h = size(scene.widget[:contentsRect]()[:size]())
  scene.scene[:setSceneRect](-w/2, -h/2, w, h)
  nothing
end

function Base.push!(scene::Scene, item::SceneItem)
  scene.scene[:addItem](item.o)
  push!(scene.items, item)
  item
end

function Base.empty!(scene::Scene)
  empty!(scene.items)
  scene.scene[:clear]()
end

# # coordinates of widget on screen
# showwidget(scene::Scene) = showwidget(scene.widget)
# hidewidget(scene::Scene) = hidewidget(scene.widget)
# widgetpos(scene::Scene) = widgetpos(scene.widget)
# widgetsize(scene::Scene) = widgetsize(scene.widget)
# movewidget(scene::Scene, x::Int, y::Int) = movewidget(scene.widget, x, y)
# resizewidget(scene::Scene, width::Int, height::Int) = resizewidget(scene.widget, width, height)
# move_resizewidget(scene::Scene, x::Int, y::Int, width::Int, height::Int) = move_resizewidget(scene.widget, x, y, width, height)

# coordinates within scene
rect(scene::Scene) = scene.scene[:sceneRect]()
Base.size(scene::Scene) = size(rect(scene)[:size]())
top(scene::Scene) = rect(scene)[:top]()
bottom(scene::Scene) = rect(scene)[:bottom]()
left(scene::Scene) = rect(scene)[:left]()
right(scene::Scene) = rect(scene)[:right]()
topleft(scene::Scene) = position(rect(scene)[:topLeft]())
bottomright(scene::Scene) = position(rect(scene)[:bottomRight]())

background!(scene::Scene, args...) = (scene.scene[:setBackgroundBrush](makebrush(args...)); scene)
background!(args...) = background!(currentScene(), args...)

# -----------------------------------------------------------------------

convertToRGBInt(x::Real) = max(0, min(round(Int, x * 255.0), 255))

makecolor(color::Symbol) = QT.QColor(string(color))
makecolor(color::AbstractString) = QT.QColor(color)
makecolor(args...) = QT.QColor(map(convertToRGBInt, args)...)  # args: r, g, b [, a]

makebrush(args...) = QT.QBrush(makecolor(args...))
makepen(width::Real, args...) = width == 0 ? QT.QPen(0) : QT.QPen(makecolor(args...), float(width))

# -----------------------------------------------------------------------

type CurrentScene
  nullablescene::Nullable{Scene}
  defaultBrush::PyObject
  defaultPen::PyObject
end
# const CURRENT_SCENE = CurrentScene(Nullable{Scene}(), makebrush(:black), makepen(2, :black))

function currentScene()
  # create a new scene if it doesn't exist yet
  isnull(CURRENT_SCENE.nullablescene) && currentScene!(Scene())
  get(CURRENT_SCENE.nullablescene)
end
currentScene!(scene::Scene) = (CURRENT_SCENE.nullablescene = Nullable(scene))

defaultBrush() = CURRENT_SCENE.defaultBrush
defaultPen() = CURRENT_SCENE.defaultPen
defaultBrush!(args...) = (CURRENT_SCENE.defaultBrush = makebrush(args...); nothing)
defaultPen!(args...) = (CURRENT_SCENE.defaultPen = makepen(args...); nothing)

# -----------------------------------------------------------------------

# note: position is the center!!

Base.size(o::PyObject) = P2(o[:width](), o[:height]())  # assume we're passed in a QSize
Base.position(o::PyObject) = P2(o[:x](), o[:y]())  # assume we're passed in a QPoint

P2(item::SceneItem) = position(item)
P3(item::SceneItem) = position3d(item)
Base.size(item::SceneItem) = size(item.o[:size]())
Base.position(item::SceneItem) = position(item.o[:pos]())
position3d(item::SceneItem) = P3(position(item)..., zvalue(item))
position!(item::SceneItem, p::P2) = (item.o[:setPos](p...); item)
position!(item::SceneItem, p::P3) = (position!(item, P2(p)); zvalue!(item, p[3]); item)
zvalue(item::SceneItem) = item.o[:zValue]()
zvalue!(item::SceneItem, z::Real) = (item.o[:setZValue](float(z)); item)
rotation(item::SceneItem) = item.o[:rotation]()
rotation!(item::SceneItem, deg::Real) = (item.o[:setRotation](float(deg)); item)
visible(item::SceneItem) = item.o[:isVisible]()
visible!(item::SceneItem, b::Bool) = (item.o[:setVisible](b); item)
Base.parent(item::SceneItem) = item.o[:parentItem]()
parent!(item::SceneItem, parent::SceneItem) = (item.o[:setParentItem](parent.o); item)

brush!(item::SceneItem, args...) = brush!(item, makebrush(args...))
brush!(item::SceneItem, brush::PyObject) = (item.o[:setBrush](brush); item)
pen!(item::SceneItem, width::Real, args...) = pen!(item, makepen(float(width), args...))
pen!(item::SceneItem, pen::PyObject) = (item.o[:setPen](pen); item)

# these are relative changes
move!(item::SceneItem, p::P2) = (item.o[:moveBy](p...); item)
movex!(item::SceneItem, x::Real) = move!(item, P2(x, 0))
movey!(item::SceneItem, y::Real) = move!(item, P2(0, y))
Base.scale!(item::SceneItem, p::P2) = (item.o[:scale](p...); item)
Base.scale!(item::SceneItem, s::Real) = scale!(item, P2(s, s))
scalex!(item::SceneItem, x::Real) = scale!(item, P2(x, 0))
scaley!(item::SceneItem, y::Real) = scale!(item, P2(y, 0))
rotate!(item::SceneItem, deg::Real) = rotation!(item, deg + rotation(item))

# -----------------------------------------------------------------------

immutable Ellipse <: SceneItem; o::PyObject; end
function Ellipse(radius::P2, pos::Point = ORIGIN)
  rx, ry = radius
  item = Ellipse(QT.QGraphicsEllipseItem(-rx, -ry, rx*2.0, ry*2.0))
  position!(item, pos)
  brush!(item, defaultBrush())
  pen!(item, defaultPen())
  item
end
Circle(radius::Real, center::Point = ORIGIN) = Ellipse(P2(radius, radius), center)

ellipse!(scene::Scene, args...) = push!(scene, Ellipse(args...))
ellipse!(args...) = ellipse!(currentScene(), args...)
circle!(scene::Scene, args...) = push!(scene, Circle(args...))
circle!(args...) = circle!(currentScene(), args...)

# -----------------------------------------------------------------------

immutable Rect <: SceneItem; o::PyObject; end
function Rect(sz::P2, pos::Point = ORIGIN)
  w, h = sz
  item = Rect(QT.QGraphicsRectItem(-w/2, -h/2, w, h))
  position!(item, pos)
  brush!(item, defaultBrush())
  pen!(item, defaultPen())
  item
end
Square(w::Real, pos::Point = ORIGIN) = Rect(P2(w, w), pos)

rect!(scene::Scene, args...) = push!(scene, Rect(args...))
rect!(args...) = rect!(currentScene(), args...)
square!(scene::Scene, args...) = push!(scene, Square(args...))
square!(args...) = square!(currentScene(), args...)

# -----------------------------------------------------------------------

immutable SceneText <: SceneItem; o::PyObject; end
function SceneText(s::AbstractString, pos::Point = ORIGIN)
  item = SceneText(QT.QGraphicsSimpleTextItem(s))
  position!(item, pos)
  # brush!(item, defaultBrush())
  # pen!(item, defaultPen())
  item
end

text!(scene::Scene, args...) = push!(scene, SceneText(args...))
text!(args...) = text!(currentScene(), args...)

Base.size(item::SceneText) = size(item.o[:boundingRect]()[:size]())
Base.position(item::SceneText) = position(item.o[:boundingRect]()[:pos]()) + size(item)/2
function position!(item::SceneText, p::P2)
  p = p - size(item)/2
  item.o[:setPos](p...)
  item
end
settext(item::SceneText, s::AbstractString) = (item.o[:setText](s); item)

# -----------------------------------------------------------------------

# TODO: line's aren't centered currently, which will mess up scaling and rotating.. fix?

immutable Line <: SceneItem; o::PyObject; end
Line(p1::P2, p2::P2) = (l = Line(QT.QGraphicsLineItem(p1[1], p1[2], p2[1], p2[2])); zvalue!(l, -10000.0); l)
Line(p1::P3, p2::P3) = (l = Line(P2(p1), P2(p2)); zvalue!(l, (p1[3] + p2[3]) / 2.0 - 0.0001); l)

line!(scene::Scene, p1::Point, p2::Point) = push!(scene, Line(p1, p2))
line!(scene::Scene, x1::Real, y1::Real, x2::Real, y2::Real) = line!(scene, P2(x1,y1), P2(x2,y2))
line!(scene::Scene, item1::SceneItem, item2::SceneItem) = line!(scene, position3d(item1), position3d(item2))
line!(scene::Scene, p1::Point, item2::SceneItem) = line!(scene, P3(p1), position3d(item2))
line!(scene::Scene, item1::SceneItem, p2::Point) = line!(scene, position3d(item1), P3(p2))
line!(args...) = line!(currentScene(), args...)

# -----------------------------------------------------------------------


text:
module program

end

max_stars_repo_name: tmaone/xsh

max_issues_repo_name: turing-complete/xsh

max_forks_repo_name: turing-complete/xsh


text:
d = iy - ix
@inbounds for i = ix:ix-1+n
    x[i] = x[i] + y[d+i]*a
end


text:
module LearnBase

# AGGREGATION MODES
include("aggmode.jl")

# OBSERVATION DIMENSIONS
include("obsdim.jl")

# LEARNING COSTS (e.g. loss & penalty)
include("costs.jl")

# OTHER CONCEPTS
include("other.jl")

end # module


text:
ON_TRAVIS = get(ENV, "TRAVIS", "false") == "true"

if ON_TRAVIS
    BENCHMARK_FILES = [
        "dummy.jl",
        "gdemo.jl",
        "mvnormal.jl",
    ]
else
    BENCHMARK_FILES = [
        "dummy.jl",
        "gdemo.jl",
        "mvnormal.jl",
    ]
end

BENCHMARK_FILES = map(BENCHMARK_FILES) do x joinpath(@__DIR__, x) end

COMMENT_TEMPLATES = Dict{Symbol, String}()
COMMENT_TEMPLATES[:CI_BM_COMPLETE_FOR_COMMIT] = """

The benchmark job for this commit has completed.
Here is the benchmark [report]( {{{ :report_url }}}) and commit ({{{ :report_repo }}}@{{{ :commit_id }}}).
The benchmark log (printed via `log_report`) can be found below.

```
{{#:report_logs}}
{{.}}
{{/:report_logs}}
```
"""


text:
using VectorBackedLists
using Test

d = [1,2,3,4]
dl = list(d)

s = start(dl)
_, t = next(dl, s) # t points at 2
_, n = next(dl, t) # n points at 3
_, q = next(dl, n) # q points at 4

move_before!(dl, n, t)
@test collect(dl) == [1,3,2,4]

insert_after!(dl, q, 4)
@test collect(dl) == [1,3,2,4,4]

insert_after!(dl, t, 100)
@test collect(dl) == [1,3,2,100,4,4]

s100 = start(dl)
for i in 1:3
    global s100
    _, s100 = next(dl, s100)
end

s3 = start(dl)
for i in 1:1
    global s3
    _, s3 = next(dl, s3)
end

move_before!(dl, s100, s3)
@test collect(dl) == [1,100,3,2,4,4]

sdl = sublist(dl, n, q)
@test collect(sdl) == [3,2]

l = list([1,2,3,4])

a = [1,2,3,4]
l = list(a)
s, i = start(l), 1
while !done(l,s)
    global s, i
    @test l[s] == a[i]
    i += 1
    _, s = next(l,s)
end

s = start(l)
l[s] = 20
@test a[1] == 20

push!(l,21)
@test collect(l) == [20,2,3,4,21]

# Test convenience API
list2 = list([:a,:b,:c])

it = start(list2)
vect2 = Vector{eltype(list2)}()
while it != done(list2)
    val = list2[it]
    push!(vect2, val)
    global it = advance(list2,it)
end

@test vect2 == collect(list2)

# Test small types for indices
list3 = list([:a,:b,:c], Int32)
vect3 = collect(list3)
@test vect3 == [:a,:b,:c]


text:
# using Revise
# using Distributed
# addprocs(4)

using RoME
# @everywhere using RoME

using Test

include(joinpath(@__DIR__,"BeehiveTestUtils.jl"))

@testset "sanity check on Hex example" begin

## start with an empty factor graph object
fg = initfg()

# fg.solverParams
# fg.solverParams.isfixedlag = true
# fg.solverParams.qfl = 20
posecount = 0

# Add the first pose :x0
addVariable!(fg, :x0, Pose2)
posecount += 1

# Add at a fixed location PriorPose2 to pin :x0 to a starting location (10,10, pi/4)
addFactor!(fg, [:x0], PriorPose2( MvNormal([0.0; 0.0; 0.0],
                                           Matrix(Diagonal([0.1;0.1;0.05].^2))) ), autoinit=false )

# Add landmarks with Bearing range measurements
addVariable!(fg, :l1, Point2, labels=[:LANDMARK;])
p2br = Pose2Point2BearingRange(Normal(0,0.03),Normal(20.0,0.5))
addFactor!(fg, [:x0; :l1], p2br, autoinit=false )

## hex 1

posecount = driveHex(fg, posecount)

# Add landmarks with Bearing range measurements
p2br2 = Pose2Point2BearingRange(Normal(0,0.03),Normal(20.0,0.5))
addFactor!(fg, [Symbol("x$(posecount-1)"); :l1], p2br2, autoinit=false )

## hex 2

posecount = offsetHexLeg(fg, posecount, direction=:right)

# Add landmarks with Bearing range measurements
addVariable!(fg, :l2, Point2, labels=[:LANDMARK])
p2br = Pose2Point2BearingRange(Normal(0,0.03),Normal(20.0,0.5))
addFactor!(fg, [Symbol("x$(posecount-1)"); :l2], p2br, autoinit=false )

posecount = driveHex(fg, posecount, steps=5)

# Add landmarks with Bearing range measurements
p2br2 = Pose2Point2BearingRange(Normal(0,0.03),Normal(20.0,0.5))
addFactor!(fg, [Symbol("x$(posecount-1)"); :l2], p2br2, autoinit=false )

# writeGraphPdf(fg,engine="neato")

getSolverParams(fg).drawtree = true
getSolverParams(fg).showtree = true
getSolverParams(fg).downsolve = false
getSolverParams(fg).multiproc = false
# fg.solverParams.async = true

# solve
tree, smt, chi = solveTree!(fg, recordcliqs=ls(fg))

## See visualization

# hist = getCliqSolveHistory(tree, :x1)

#  Do some plotting
using RoMEPlotting
Gadfly.set_default_plot_size(35cm,25cm)
drawPosesLandms(fg, meanmax=:max) |> PDF("/tmp/test.pdf");  @async run(`evince /tmp/test.pdf`)

## check outcome on first hex

@test 80 < sum(-3.0 .< getPoints(getKDE(fg, :x0))[1,:] .< 3.0)
@test 80 < sum(-3.0 .< getPoints(getKDE(fg, :x0))[2,:] .< 3.0)
@test 80 < sum(-0.3 .< getPoints(getKDE(fg, :x0))[3,:] .< 0.3)

@test 80 < sum(7.0 .< getPoints(getKDE(fg, :x1))[1,:] .< 13.0)
@test 80 < sum(-3.0 .< getPoints(getKDE(fg, :x1))[2,:] .< 3.0)
@test 80 < sum(0.7 .< getPoints(getKDE(fg, :x1))[3,:] .< 1.3)

@test 80 < sum(12.0 .< getPoints(getKDE(fg, :x2))[1,:] .< 18.0)
@test 80 < sum(6.0 .< getPoints(getKDE(fg, :x2))[2,:] .< 11.0)
@test 80 < sum(1.8 .< getPoints(getKDE(fg, :x2))[3,:] .< 2.4)

@test 80 < sum(7.0 .< getPoints(getKDE(fg, :x3))[1,:] .< 13.0)
@test 80 < sum(15.0 .< getPoints(getKDE(fg, :x3))[2,:] .< 20.0)
# @test 80 < sum(-0.3 .< getPoints(getKDE(fg, :x3))[3,:] .< 0.3)

@test 80 < sum(-4.0 .< getPoints(getKDE(fg, :x4))[1,:] .< 4.0)
@test 80 < sum(15.0 .< getPoints(getKDE(fg, :x4))[2,:] .< 20.0)
@test 80 < sum(-2.4 .< getPoints(getKDE(fg, :x4))[3,:] .< -1.8)

@test 80 < sum(-8.0 .< getPoints(getKDE(fg, :x5))[1,:] .< -2.0)
@test 80 < sum(6.0 .< getPoints(getKDE(fg, :x5))[2,:] .< 11.0)
@test 80 < sum(-1.3 .< getPoints(getKDE(fg, :x5))[3,:] .< -0.7)

@test 80 < sum(-3.0 .< getPoints(getKDE(fg, :x6))[1,:] .< 3.0)
@test 80 < sum(-3.0 .< getPoints(getKDE(fg, :x6))[2,:] .< 3.0)
@test 80 < sum(-0.3 .< getPoints(getKDE(fg, :x6))[3,:] .< 0.3)

@test 80 < sum(17.0 .< getPoints(getKDE(fg, :l1))[1,:] .< 23.0)
@test 80 < sum(-5.0 .< getPoints(getKDE(fg, :l1))[2,:] .< 5.0)

# check outcome on second hex

# @test 80 < sum(-3.0 .< getPoints(getKDE(fg, :x0))[1,:] .< 3.0)
# @test 80 < sum(-3.0 .< getPoints(getKDE(fg, :x0))[2,:] .< 3.0)
# @test 80 < sum(-0.3 .< getPoints(getKDE(fg, :x0))[3,:] .< 0.3)
#
# @test 80 < sum(7.0 .< getPoints(getKDE(fg, :x1))[1,:] .< 13.0)
# @test 80 < sum(-3.0 .< getPoints(getKDE(fg, :x1))[2,:] .< 3.0)
# @test 80 < sum(0.7 .< getPoints(getKDE(fg, :x1))[3,:] .< 1.3)
#
# @test 80 < sum(12.0 .< getPoints(getKDE(fg, :x2))[1,:] .< 18.0)
# @test 80 < sum(6.0 .< getPoints(getKDE(fg, :x2))[2,:] .< 11.0)
# @test 80 < sum(1.8 .< getPoints(getKDE(fg, :x2))[3,:] .< 2.4)
#
# @test 80 < sum(7.0 .< getPoints(getKDE(fg, :x3))[1,:] .< 13.0)
# @test 80 < sum(15.0 .< getPoints(getKDE(fg, :x3))[2,:] .< 20.0)
# # @test 80 < sum(-0.3 .< getPoints(getKDE(fg, :x3))[3,:] .< 0.3)
#
# @test 80 < sum(-4.0 .< getPoints(getKDE(fg, :x4))[1,:] .< 4.0)
# @test 80 < sum(15.0 .< getPoints(getKDE(fg, :x4))[2,:] .< 20.0)
# @test 80 < sum(-2.4 .< getPoints(getKDE(fg, :x4))[3,:] .< -1.8)
#
# @test 80 < sum(-8.0 .< getPoints(getKDE(fg, :x5))[1,:] .< -2.0)
# @test 80 < sum(6.0 .< getPoints(getKDE(fg, :x5))[2,:] .< 11.0)
# @test 80 < sum(-1.3 .< getPoints(getKDE(fg, :x5))[3,:] .< -0.7)
#
# @test 80 < sum(-3.0 .< getPoints(getKDE(fg, :x6))[1,:] .< 3.0)
# @test 80 < sum(-3.0 .< getPoints(getKDE(fg, :x6))[2,:] .< 3.0)
# @test 80 < sum(-0.3 .< getPoints(getKDE(fg, :x6))[3,:] .< 0.3)
#
# @test 80 < sum(17.0 .< getPoints(getKDE(fg, :l1))[1,:] .< 23.0)
# @test 80 < sum(-5.0 .< getPoints(getKDE(fg, :l1))[2,:] .< 5.0)

end # testset


text:
# This file contains useful utilities that really should be part of other
# packages. We keep them here for now, but eventually they will be moved
# somewhere else.

"""
    URI_file(base, filespec)

Construct an absolute URI to `filespec` relative to `base`.
"""
URI_file(base, filespec) = URI_file(base, URI("file:///$filespec"))
function URI_file(base, filespec::URI)
    base = join(map(URIParser.escape, split(base, Base.Filesystem.path_separator_re)), "/")
    return URI(filespec, path = base * filespec.path)
end

"""
    pwd(URI)

Return `pwd()` as a `URI` resource.
"""
Base.pwd(::Type{URI}) = URI_file(pwd(), "")

# TODO Fix for julia 0.7 and enable again
# """
#     @LOCAL(filespec)

# Construct an absolute URI to `filespec` relative to the source file containing the macro call.
# """
# macro LOCAL(filespec)
#     # v0.7: base = String(__source__.file)
#     #       filespec isa String && return URI_file(base, filespec) # can construct eagerly
#     #       return :(URI_file($base, $(esc(filespec))))
#     return :(URI_file(@__DIR__, $(esc(filespec))))
# end


text:
using RCall
include("ProblemGenerator.jl")

########################################################################
#Plotting States (Figure 3)
########################################################################
probFigure3 = ModelSetup(:ISD,:notStochastic)
  solFigure3 = @time solve(probFigure3,CVODE_BDF(linear_solver=:GMRES),saveat=0.1)

allStateData = DataFrame()
for (i,st) in enumerate(statesNames)
    allStateData[!,Symbol(st)] = vec(solFigure3[:,:,i,:])
end

timeLength = length(solFigure3.t)
allStateData.Cell = repeat(1:nCells,timeLength)
allStateData.Time = repeat(solFigure3.t,inner=nCells)
allStateData.Infected = repeat(vec(probFigure3.u0[:,:,2] .> 0.0),timeLength)

@rput allStateData
R"""
library(ggplot2)
library(ggpubr)

stateAve = aggregate(allStateData[,1:14], list(allStateData$Infected,allStateData$Time), mean)
colnames(stateAve)[1] <- "Cell.State"
colnames(stateAve)[2] <- "Time"

logic<- unlist(lapply(stateAve$Cell.State, function(x) x == TRUE))
stateAve$Cell.State[which(logic == TRUE)] <- "Primary"
stateAve$Cell.State[which(logic == FALSE)] <- "Secondary"
low = aggregate(allStateData[,1:14], list(allStateData$Infected,allStateData$Time), FUN = 'quantile',probs=0.05)
high = aggregate(allStateData[,1:14], list(allStateData$Infected,allStateData$Time), FUN = 'quantile',probs=0.95)

commonFigureOptions <- list( scale_x_continuous(breaks=seq(0, 48, 12)),
  theme_pubr(border=TRUE),
  ylab("nM"),
  xlab("Time (hours)"),
  theme(plot.title = element_text(hjust = 0.5),aspect.ratio = 1))

p1 <- ggplot(stateAve) + geom_line(aes(y=DNA, x=Time, group=Cell.State, color = Cell.State))+
  geom_ribbon(aes(ymin=low$DNA, ymax=high$DNA, x=Time,group=Cell.State,fill = Cell.State), alpha = 0.3) +
  ggtitle("DNA") +
  commonFigureOptions

p2 <- ggplot(stateAve) + geom_line(aes(y=IFNb, x=Time, group=Cell.State, color = Cell.State))+
  geom_ribbon(aes(ymin=low$IFNb, ymax=high$IFNb, x=Time,group=Cell.State,fill = Cell.State), alpha = 0.3) +
  ggtitle("IFNb") +
  commonFigureOptions

p3 <- ggplot(stateAve) + geom_line(aes(y=IRF7, x=Time, group=Cell.State, color = Cell.State))+
  geom_ribbon(aes(ymin=low$IRF7, ymax=high$IRF7, x=Time,group=Cell.State,fill = Cell.State), alpha = 0.3) +
  ggtitle("IRF7") +
  commonFigureOptions

p4 <- ggplot(stateAve) + geom_line(aes(y=TREX1, x=Time, group=Cell.State, color = Cell.State))+
  geom_ribbon(aes(ymin=low$TREX1, ymax=high$TREX1, x=Time,group=Cell.State,fill = Cell.State), alpha = 0.3) +
  ggtitle("TREX1") +
  commonFigureOptions

figure <- ggarrange(p1, p2, p3, p4,
                    labels = c("A", "B", "C", "D"),
                    common.legend = TRUE, legend = "right",
                    align = "hv",
                    ncol = 2, nrow = 2)

ggsave("./Figures/Figure3.pdf")
"""


text:
using NiLang, Test
using NiLang: UNSAFE_POP!, UNSAFE_PUSH!, UNSAFE_COPYPOP!, UNSAFE_COPYPUSH!

@testset "stack operations" begin
    x =0.3
    @instr PUSH!(x)
    @test x === 0.0
    @instr POP!(x)
    @test x === 0.3
    @instr PUSH!(x)
    x = 0.4
    @test_throws InvertibilityError @instr POP!(x)
    y = 0.5
    @instr PUSH!(y)
    @instr UNSAFE_POP!(x)
    @test x == 0.5

    x =0.3
    st = Float64[]
    @instr PUSH!(st, x)
    @test x === 0.0
    @test length(st) == 1
    @instr POP!(st, x)
    @test length(st) == 0
    @test x === 0.3
    @instr PUSH!(st, x)
    @test length(st) == 1
    x = 0.4
    @test_throws InvertibilityError @instr POP!(x)
    @test length(st) == 1

    y = 0.5
    @instr PUSH!(st, y)
    @instr UNSAFE_POP!(st, x)
    @test x == 0.5

    @i function test(x)
        x2 ← zero(x)
        x2 += x^2
        PUSH!(x)
        SWAP(x, x2)
    end
    @test test(3.0) == 9.0
    l = length(NiLang.GLOBAL_STACK)
    @test check_inv(test, (3.0,))
    @test length(NiLang.GLOBAL_STACK) == l
end

@testset "copied push/pop stack operations" begin
    x =0.3
    @instr COPYPUSH!(x)
    @test x === 0.3
    @instr COPYPOP!(x)
    @test x === 0.3
    @instr COPYPUSH!(x)
    x = 0.4
    @test_throws InvertibilityError @instr COPYPOP!(x)
    y = 0.5
    @instr COPYPUSH!(y)
    @instr UNSAFE_COPYPOP!(x)
    @test x == 0.5

    st = []
    x = [0.3]
    @instr COPYPUSH!(st, x)
    @test st[1] !== [0.3]
    @test st[1] ≈ [0.3]

    x =0.3
    st = Float64[]
    @instr COPYPUSH!(st, x)
    @test x === 0.3
    @test length(st) == 1
    @instr COPYPOP!(st, x)
    @test length(st) == 0
    @test x === 0.3
    @instr COPYPUSH!(st, x)
    @test length(st) == 1
    x = 0.4
    @test_throws InvertibilityError @instr COPYPOP!(x)
    @test length(st) == 1

    y = 0.5
    @instr COPYPUSH!(st, y)
    @instr UNSAFE_COPYPOP!(st, x)
    @test x == 0.5

    @i function test(x, x2)
        x2 += x^2
        COPYPUSH!(x)
        SWAP(x, x2)
    end
    @test test(3.0, 0.0) == (9.0, 3.0)
    l = length(NiLang.GLOBAL_STACK)
    @test check_inv(test, (3.0, 0.0))
    @test length(NiLang.GLOBAL_STACK) == l
end


text:
### polar form of the non-convex AC equations

export
    ACPPowerModel, StandardACPForm

""
abstract type AbstractACPForm <: AbstractPowerFormulation end

""
abstract type StandardACPForm <: AbstractACPForm end

""
const ACPPowerModel = GenericPowerModel{StandardACPForm}

"default AC constructor"
ACPPowerModel(data::Dict{String,Any}; kwargs...) =
    GenericPowerModel(data, StandardACPForm; kwargs...)

""
function variable_voltage(pm::GenericPowerModel{T}, n::Int=pm.cnw; kwargs...) where T <: AbstractACPForm
    variable_voltage_angle(pm, n; kwargs...)
    variable_voltage_magnitude(pm, n; kwargs...)
end

""
function variable_voltage_ne(pm::GenericPowerModel{T}, n::Int=pm.cnw; kwargs...) where T <: AbstractACPForm
end

"do nothing, this model does not have complex voltage constraints"
function constraint_voltage(pm::GenericPowerModel{T}, n::Int) where T <: AbstractACPForm
end

"do nothing, this model does not have complex voltage constraints"
function constraint_voltage_ne(pm::GenericPowerModel{T}, n::Int) where T <: AbstractACPForm
end

"`v[i] == vm`"
function constraint_voltage_magnitude_setpoint(pm::GenericPowerModel{T}, n::Int, i, vm) where T <: AbstractACPForm
    v = pm.var[:nw][n][:vm][i]

    @constraint(pm.model, v == vm)
end

"""
```
sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*v^2
sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) == sum(qg[g] for g in bus_gens) - qd + bs*v^2
```
"""
function constraint_kcl_shunt(pm::GenericPowerModel{T}, n::Int, i::Int, bus_arcs, bus_arcs_dc, bus_gens, pd, qd, gs, bs) where T <: AbstractACPForm
    vm = pm.var[:nw][n][:vm][i]
    p = pm.var[:nw][n][:p]
    q = pm.var[:nw][n][:q]
    pg = pm.var[:nw][n][:pg]
    qg = pm.var[:nw][n][:qg]
    p_dc = pm.var[:nw][n][:p_dc]
    q_dc = pm.var[:nw][n][:q_dc]

    pm.con[:nw][n][:kcl_p][i] = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*vm^2)
    pm.con[:nw][n][:kcl_q][i] = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) == sum(qg[g] for g in bus_gens) - qd + bs*vm^2)
end

"""
```
sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*v^2
sum(q[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*v^2
```
"""
function constraint_kcl_shunt_ne(pm::GenericPowerModel{T}, n::Int, i, bus_arcs, bus_arcs_dc, bus_arcs_ne, bus_gens, pd, qd, gs, bs) where T <: AbstractACPForm
    vm = pm.var[:nw][n][:vm][i]
    p = pm.var[:nw][n][:p]
    q = pm.var[:nw][n][:q]
    p_ne = pm.var[:nw][n][:p_ne]
    q_ne = pm.var[:nw][n][:q_ne]
    pg = pm.var[:nw][n][:pg]
    qg = pm.var[:nw][n][:qg]
    p_dc = pm.var[:nw][n][:p_dc]
    q_dc = pm.var[:nw][n][:q_dc]

    @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc)  + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*vm^2)
    @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc)  + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*vm^2)
end

"""
Creates Ohms constraints (yt post fix indicates that Y and T values are in rectangular form)

```
p[f_idx] == g/tm*v[f_bus]^2 + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus]))
q[f_idx] == -(b+c/2)/tm*v[f_bus]^2 - (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus]))
```
"""
function constraint_ohms_yt_from(pm::GenericPowerModel{T}, n::Int, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm) where T <: AbstractACPForm
    p_fr = pm.var[:nw][n][:p][f_idx]
    q_fr = pm.var[:nw][n][:q][f_idx]
    vm_fr = pm.var[:nw][n][:vm][f_bus]
    vm_to = pm.var[:nw][n][:vm][t_bus]
    va_fr = pm.var[:nw][n][:va][f_bus]
    va_to = pm.var[:nw][n][:va][t_bus]

    @NLconstraint(pm.model, p_fr ==        g/tm^2*vm_fr^2 + (-g*tr+b*ti)/tm^2*(vm_fr*vm_to*cos(va_fr-va_to)) + (-b*tr-g*ti)/tm^2*(vm_fr*vm_to*sin(va_fr-va_to)) )
    @NLconstraint(pm.model, q_fr == -(b+c/2)/tm^2*vm_fr^2 - (-b*tr-g*ti)/tm^2*(vm_fr*vm_to*cos(va_fr-va_to)) + (-g*tr+b*ti)/tm^2*(vm_fr*vm_to*sin(va_fr-va_to)) )
end

"""
Creates Ohms constraints (yt post fix indicates that Y and T values are in rectangular form)

```
p[t_idx] == g*v[t_bus]^2 + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[t_bus]-t[f_bus])) + (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus]))
q[t_idx] == -(b+c/2)*v[t_bus]^2 - (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus]))
```
"""
function constraint_ohms_yt_to(pm::GenericPowerModel{T}, n::Int, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm) where T <: AbstractACPForm
    p_to = pm.var[:nw][n][:p][t_idx]
    q_to = pm.var[:nw][n][:q][t_idx]
    vm_fr = pm.var[:nw][n][:vm][f_bus]
    vm_to = pm.var[:nw][n][:vm][t_bus]
    va_fr = pm.var[:nw][n][:va][f_bus]
    va_to = pm.var[:nw][n][:va][t_bus]

    @NLconstraint(pm.model, p_to ==        g*vm_to^2 + (-g*tr-b*ti)/tm^2*(vm_to*vm_fr*cos(va_to-va_fr)) + (-b*tr+g*ti)/tm^2*(vm_to*vm_fr*sin(va_to-va_fr)) )
    @NLconstraint(pm.model, q_to == -(b+c/2)*vm_to^2 - (-b*tr+g*ti)/tm^2*(vm_to*vm_fr*cos(va_to-va_fr)) + (-g*tr-b*ti)/tm^2*(vm_to*vm_fr*sin(va_to-va_fr)) )
end

"""
Creates Ohms constraints for AC models (y post fix indicates that Y values are in rectangular form)

```
p[f_idx] == g*(v[f_bus]/tr)^2 + -g*v[f_bus]/tr*v[t_bus]*cos(t[f_bus]-t[t_bus]-as) + -b*v[f_bus]/tr*v[t_bus]*sin(t[f_bus]-t[t_bus]-as)
q[f_idx] == -(b+c/2)*(v[f_bus]/tr)^2 + b*v[f_bus]/tr*v[t_bus]*cos(t[f_bus]-t[t_bus]-as) + -g*v[f_bus]/tr*v[t_bus]*sin(t[f_bus]-t[t_bus]-as)
```
"""
function constraint_ohms_y_from(pm::GenericPowerModel{T}, n::Int, f_bus, t_bus, f_idx, t_idx, g, b, c, tm, ta) where T <: AbstractACPForm
    p_fr = pm.var[:nw][n][:p][f_idx]
    q_fr = pm.var[:nw][n][:q][f_idx]
    vm_fr = pm.var[:nw][n][:vm][f_bus]
    vm_to = pm.var[:nw][n][:vm][t_bus]
    va_fr = pm.var[:nw][n][:va][f_bus]
    va_to = pm.var[:nw][n][:va][t_bus]

    @NLconstraint(pm.model, p_fr ==        g*(vm_fr/tm)^2 - g*vm_fr/tm*vm_to*cos(va_fr-va_to-ta) + -b*vm_fr/tm*vm_to*sin(va_fr-va_to-ta) )
    @NLconstraint(pm.model, q_fr == -(b+c/2)*(vm_fr/tm)^2 + b*vm_fr/tm*vm_to*cos(va_fr-va_to-ta) + -g*vm_fr/tm*vm_to*sin(va_fr-va_to-ta) )
end

"""
Creates Ohms constraints for AC models (y post fix indicates that Y values are in rectangular form)

```
p[t_idx] == g*v[t_bus]^2 + -g*v[t_bus]*v[f_bus]/tr*cos(t[t_bus]-t[f_bus]+as) + -b*v[t_bus]*v[f_bus]/tr*sin(t[t_bus]-t[f_bus]+as)
q_to == -(b+c/2)*v[t_bus]^2 + b*v[t_bus]*v[f_bus]/tr*cos(t[f_bus]-t[t_bus]+as) + -g*v[t_bus]*v[f_bus]/tr*sin(t[t_bus]-t[f_bus]+as)
```
"""
function constraint_ohms_y_to(pm::GenericPowerModel{T}, n::Int, f_bus, t_bus, f_idx, t_idx, g, b, c, tm, ta) where T <: AbstractACPForm
    p_to = pm.var[:nw][n][:p][t_idx]
    q_to = pm.var[:nw][n][:q][t_idx]
    vm_fr = pm.var[:nw][n][:vm][f_bus]
    vm_to = pm.var[:nw][n][:vm][t_bus]
    va_fr = pm.var[:nw][n][:va][f_bus]
    va_to = pm.var[:nw][n][:va][t_bus]

    @NLconstraint(pm.model, p_to ==        g*vm_to^2 - g*vm_to*vm_fr/tm*cos(va_to-va_fr+ta) + -b*vm_to*vm_fr/tm*sin(va_to-va_fr+ta) )
    @NLconstraint(pm.model, q_to == -(b+c/2)*vm_to^2 + b*vm_to*vm_fr/tm*cos(va_to-va_fr+ta) + -g*vm_to*vm_fr/tm*sin(va_to-va_fr+ta) )
end

""
function variable_voltage_on_off(pm::GenericPowerModel{T}, n::Int=pm.cnw; kwargs...) where T <: AbstractACPForm
    variable_voltage_angle(pm, n; kwargs...)
    variable_voltage_magnitude(pm, n; kwargs...)
end

"do nothing, this model does not have complex voltage constraints"
function constraint_voltage_on_off(pm::GenericPowerModel{T}, n::Int=pm.cnw) where T <: AbstractACPForm
end

"""
```
p[f_idx] == z*(g/tm*v[f_bus]^2 + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus])))
q[f_idx] == z*(-(b+c/2)/tm*v[f_bus]^2 - (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus])))
```
"""
function constraint_ohms_yt_from_on_off(pm::GenericPowerModel{T}, n::Int, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, vad_min, vad_max) where T <: AbstractACPForm
    p_fr = pm.var[:nw][n][:p][f_idx]
    q_fr = pm.var[:nw][n][:q][f_idx]
    vm_fr = pm.var[:nw][n][:vm][f_bus]
    vm_to = pm.var[:nw][n][:vm][t_bus]
    va_fr = pm.var[:nw][n][:va][f_bus]
    va_to = pm.var[:nw][n][:va][t_bus]
    z = pm.var[:nw][n][:branch_z][i]

    @NLconstraint(pm.model, p_fr ==        z*(g/tm^2*vm_fr^2 + (-g*tr+b*ti)/tm^2*(vm_fr*vm_to*cos(va_fr-va_to)) + (-b*tr-g*ti)/tm^2*(vm_fr*vm_to*sin(va_fr-va_to))) )
    @NLconstraint(pm.model, q_fr == z*(-(b+c/2)/tm^2*vm_fr^2 - (-b*tr-g*ti)/tm^2*(vm_fr*vm_to*cos(va_fr-va_to)) + (-g*tr+b*ti)/tm^2*(vm_fr*vm_to*sin(va_fr-va_to))) )
end

"""
```
p[t_idx] == z*(g*v[t_bus]^2 + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[t_bus]-t[f_bus])) + (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus])))
q[t_idx] == z*(-(b+c/2)*v[t_bus]^2 - (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus])))
```
"""
function constraint_ohms_yt_to_on_off(pm::GenericPowerModel{T}, n::Int, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, vad_min, vad_max) where T <: AbstractACPForm
    p_to = pm.var[:nw][n][:p][t_idx]
    q_to = pm.var[:nw][n][:q][t_idx]
    vm_fr = pm.var[:nw][n][:vm][f_bus]
    vm_to = pm.var[:nw][n][:vm][t_bus]
    va_fr = pm.var[:nw][n][:va][f_bus]
    va_to = pm.var[:nw][n][:va][t_bus]
    z = pm.var[:nw][n][:branch_z][i]

    @NLconstraint(pm.model, p_to ==        z*(g*vm_to^2 + (-g*tr-b*ti)/tm^2*(vm_to*vm_fr*cos(va_to-va_fr)) + (-b*tr+g*ti)/tm^2*(vm_to*vm_fr*sin(va_to-va_fr))) )
    @NLconstraint(pm.model, q_to == z*(-(b+c/2)*vm_to^2 - (-b*tr+g*ti)/tm^2*(vm_to*vm_fr*cos(va_to-va_fr)) + (-g*tr-b*ti)/tm^2*(vm_to*vm_fr*sin(va_to-va_fr))) )
end

"""
```
p_ne[f_idx] == z*(g/tm*v[f_bus]^2 + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus])))
q_ne[f_idx] == z*(-(b+c/2)/tm*v[f_bus]^2 - (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus])))
```
"""
function constraint_ohms_yt_from_ne(pm::GenericPowerModel{T}, n::Int, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, vad_min, vad_max) where T <: AbstractACPForm
    p_fr = pm.var[:nw][n][:p_ne][f_idx]
    q_fr = pm.var[:nw][n][:q_ne][f_idx]
    vm_fr = pm.var[:nw][n][:vm][f_bus]
    vm_to = pm.var[:nw][n][:vm][t_bus]
    va_fr = pm.var[:nw][n][:va][f_bus]
    va_to = pm.var[:nw][n][:va][t_bus]
    z = pm.var[:nw][n][:branch_ne][i]

    @NLconstraint(pm.model, p_fr ==        z*(g/tm^2*vm_fr^2 + (-g*tr+b*ti)/tm^2*(vm_fr*vm_to*cos(va_fr-va_to)) + (-b*tr-g*ti)/tm^2*(vm_fr*vm_to*sin(va_fr-va_to))) )
    @NLconstraint(pm.model, q_fr == z*(-(b+c/2)/tm^2*vm_fr^2 - (-b*tr-g*ti)/tm^2*(vm_fr*vm_to*cos(va_fr-va_to)) + (-g*tr+b*ti)/tm^2*(vm_fr*vm_to*sin(va_fr-va_to))) )
end

"""
```
p_ne[t_idx] == z*(g*v[t_bus]^2 + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[t_bus]-t[f_bus])) + (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus])))
q_ne[t_idx] == z*(-(b+c/2)*v[t_bus]^2 - (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus])))
```
"""
function constraint_ohms_yt_to_ne(pm::GenericPowerModel{T}, n::Int, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, vad_min, vad_max) where T <: AbstractACPForm
    p_to = pm.var[:nw][n][:p_ne][t_idx]
    q_to = pm.var[:nw][n][:q_ne][t_idx]
    vm_fr = pm.var[:nw][n][:vm][f_bus]
    vm_to = pm.var[:nw][n][:vm][t_bus]
    va_fr = pm.var[:nw][n][:va][f_bus]
    va_to = pm.var[:nw][n][:va][t_bus]
    z = pm.var[:nw][n][:branch_ne][i]

    @NLconstraint(pm.model, p_to ==        z*(g*vm_to^2 + (-g*tr-b*ti)/tm^2*(vm_to*vm_fr*cos(va_to-va_fr)) + (-b*tr+g*ti)/tm^2*(vm_to*vm_fr*sin(va_to-va_fr))) )
    @NLconstraint(pm.model, q_to == z*(-(b+c/2)*vm_to^2 - (-b*tr+g*ti)/tm^2*(vm_to*vm_fr*cos(va_to-va_fr)) + (-g*tr-b*ti)/tm^2*(vm_to*vm_fr*sin(va_to-va_fr))) )
end

"`angmin <= branch_z[i]*(t[f_bus] - t[t_bus]) <= angmax`"
function constraint_voltage_angle_difference_on_off(pm::GenericPowerModel{T}, n::Int, i, f_bus, t_bus, angmin, angmax, vad_min, vad_max) where T <: AbstractACPForm
    va_fr = pm.var[:nw][n][:va][f_bus]
    va_to = pm.var[:nw][n][:va][t_bus]
    z = pm.var[:nw][n][:branch_z][i]

    @constraint(pm.model, z*(va_fr - va_to) <= angmax)
    @constraint(pm.model, z*(va_fr - va_to) >= angmin)
end

"`angmin <= branch_ne[i]*(t[f_bus] - t[t_bus]) <= angmax`"
function constraint_voltage_angle_difference_ne(pm::GenericPowerModel{T}, n::Int, i, f_bus, t_bus, angmin, angmax, vad_min, vad_max) where T <: AbstractACPForm
    va_fr = pm.var[:nw][n][:va][f_bus]
    va_to = pm.var[:nw][n][:va][t_bus]
    z = pm.var[:nw][n][:branch_ne][i]

    @constraint(pm.model, z*(va_fr - va_to) <= angmax)
    @constraint(pm.model, z*(va_fr - va_to) >= angmin)
end

"""
```
p[f_idx] + p[t_idx] >= 0
q[f_idx] + q[t_idx] >= -c/2*(v[f_bus]^2/tr^2 + v[t_bus]^2)
```
"""
function constraint_loss_lb(pm::GenericPowerModel{T}, n::Int, f_bus, t_bus, f_idx, t_idx, c, tr) where T <: AbstractACPForm
    vm_fr = pm.var[:nw][n][:vm][f_bus]
    vm_to = pm.var[:nw][n][:vm][t_bus]
    p_fr = pm.var[:nw][n][:p][f_idx]
    q_fr = pm.var[:nw][n][:q][f_idx]
    p_to = pm.var[:nw][n][:p][t_idx]
    q_to = pm.var[:nw][n][:q][t_idx]

    @constraint(m, p_fr + p_to >= 0)
    @constraint(m, q_fr + q_to >= -c/2*(vm_fr^2/tr^2 + vm_to^2))
end


text:
using Printf

abstract type PerformanceCurve end

xmetric(::Type{<: PerformanceCurve}) = error("unimplemented")
xmetric(::T) where {T <: PerformanceCurve} = xmetric(T)

ymetric(::Type{<: PerformanceCurve}) = error("unimplemented")
ymetric(::T) where {T <: PerformanceCurve} = ymetric(T)

xlabel(::Type{<: PerformanceCurve}) = error("unimplemented")
xlabel(::T) where {T <: PerformanceCurve} = xlabel(T)

ylabel(::Type{<: PerformanceCurve}) = error("unimplemented")
ylabel(::T) where {T <: PerformanceCurve} = ylabel(T)

xvalues(::PerformanceCurve) = error("unimplemented")
yvalues(::PerformanceCurve) = error("unimplemented")

startpoint(::Type{<: PerformanceCurve}, xs, ys) = error("unimplemented")
startpoint(::T, args...) where {T <: PerformanceCurve} = startpoint(T, args...)

endpoint(::Type{<: PerformanceCurve}, xs, ys) = error("unimplemented")
endpoint(::T, args...) where {T <: PerformanceCurve} = endpoint(T, args...)

sortage!(::Type{<: PerformanceCurve}, xs, ys) = error("unimplemented")

function downsample(xs::AbstractVector{Float64}, ys::AbstractVector{Float64})
    keep = [1]
    for i in 2:length(xs)
        if !(xs[i] ≈ xs[i-1] && ys[i] ≈ ys[i-1])
            push!(keep, i)
        end
    end
    keep
end

function prepare!(::Type{T},
                 xs::AbstractVector{Float64},
                 ys::AbstractVector{Float64};
                 down=true) where {T <: PerformanceCurve}

    if size(xs) != size(ys)
        throw(DimensionMismatch("$(xlabel(T)) and $(ylabel(T)) vectors have different sizes"))
    elseif any(<(0.0), xs)
        throw(ArgumentError("$(xlabel(T)) less than 0.0 provided"))
    elseif any(<(0.0), ys)
        throw(ArgumentError("$(ylabel(T)) less than 0.0 provided"))
    elseif any(>(1.0), xs)
        throw(ArgumentError("$(xlabel(T)) greater than 1.0 provided"))
    elseif any(>(1.0), ys)
        throw(ArgumentError("$(ylabel(T)) greater than 1.0 provided"))
    end

    sortage!(T, xs, ys)

    if down
        d = downsample(xs, ys)
        xs = xs[d]
        ys = ys[d]
    end

    s = startpoint(T, xs, ys)
    if !all((xs[begin], ys[begin]) .≈ s)
        pushfirst!(xs, s[begin])
        pushfirst!(ys, s[end])
    end

    e = endpoint(T, xs, ys)
    if !all((xs[end], ys[end]) .≈ e)
        push!(xs, e[begin])
        push!(ys, e[end])
    end

    xs, ys
end

Base.length(c::PerformanceCurve) = length(xvalues(c))

function MLBase.roc(T::Type{<:PerformanceCurve},
                    arena::AbstractArena,
                    edges::Vector{EdgeEvidence},
                    args...)
    g = graph(arena)
    gt = [Int(has_edge(g, e.src, e.dst)) for e in edges]
    scores = [e.evidence for e in edges]
    if all(==(scores[1]), scores)
        T(gt)
    else
        x, y = xmetric(T), ymetric(T)
        r = roc(gt, scores, args...)
        T(map(x, r), map(y, r))
    end
end

auc(c::PerformanceCurve) = let xs = xvalues(c), ys = yvalues(c)
    @views dot(ys[2:end] + ys[1:end-1], xs[2:end] - xs[1:end-1]) / 2.0
end

struct Curve
    xs::Vector{Float64}
    ys::Vector{Float64}
    function Curve(xs::AbstractVector{Float64}, ys::AbstractVector{Float64})
        if length(xs) != length(ys)
            throw(DimensionMismatch("the x- and y-position vectors must have the same length"))
        end
        new(xs, ys)
    end
end
Curve(r::PerformanceCurve) = Curve(xvalues(r), yvalues(r))

Base.length(c::Curve) = length(c.xs)

function Base.:+(a::Curve, b::Curve)
    xs, ys = Float64[], Float64[]
    i, j = 1, 1
    @views while i <= length(a) && j <= length(b)
        if a.xs[i] ≈ b.xs[j]
            push!(xs, a.xs[i])
            push!(ys, a.ys[i] + b.ys[j])
            i += 1
            j += 1
        elseif a.xs[i] < b.xs[j]
            push!(xs, a.xs[i])
            push!(ys, a.ys[i] + interpolate(b.xs[j-1:j], b.ys[j-1:j], a.xs[i]))
            i += 1
        else
            push!(xs, b.xs[j])
            push!(ys, b.ys[j] + interpolate(a.xs[i-1:i], a.ys[i-1:i], b.xs[j]))
            j += 1
        end
    end
    Curve(xs, ys)
end

function Base.:-(a::Curve, b::Curve)
    xs, ys = Float64[], Float64[]
    i, j = 1, 1
    @views while i <= length(a) && j <= length(b)
        if a.xs[i] ≈ b.xs[j]
            push!(xs, a.xs[i])
            push!(ys, a.ys[i] - b.ys[j])
            i += 1
            j += 1
        elseif a.xs[i] < b.xs[j]
            push!(xs, a.xs[i])
            push!(ys, a.ys[i] - interpolate(b.xs[j-1:j], b.ys[j-1:j], a.xs[i]))
            i += 1
        else
            push!(xs, b.xs[j])
            push!(ys, b.ys[j] - interpolate(a.xs[i-1:i], a.ys[i-1:i], b.xs[j]))
            j += 1
        end
    end
    Curve(xs, ys)
end

function interpolate(xs::AbstractVector{Float64}, ys::AbstractVector{Float64}, x::Float64)
    m = (ys[2] - ys[1]) / (xs[2] - xs[1])
    m * (x - xs[1]) + ys[1]
end

Base.:/(c::Curve, k::Number) = Curve(c.xs, c.ys / k)

Statistics.mean(cs::AbstractVector{T}) where {T <: PerformanceCurve} = T(mean(Curve.(cs)))

struct ROC <: PerformanceCurve
    fpr::Vector{Float64}
    tpr::Vector{Float64}
    function ROC(fpr::Vector{Float64}, tpr::Vector{Float64}; kwargs...)
        fpr, tpr = prepare!(ROC, deepcopy(fpr), deepcopy(tpr); kwargs...)
        new(fpr, tpr)
    end
end
ROC() = ROC([0.0, 1.0], [0.0, 1.0])
ROC(::AbstractArray{Int}) = ROC()
ROC(c::Curve) = ROC(c.xs, c.ys)

fpr(r::ROC) = r.fpr

tpr(r::ROC) = r.tpr

xmetric(::Type{ROC}) = false_positive_rate

ymetric(::Type{ROC}) = true_positive_rate

xlabel(::Type{ROC}) = :FPR

ylabel(::Type{ROC}) = :TPR

startpoint(::Type{ROC}, fpr, tpr) = (0.0, 0.0)

endpoint(::Type{ROC}, fpr, tpr) = (1.0, 1.0)

xvalues(r::ROC) = fpr(r)

yvalues(r::ROC) = tpr(r)

function sortage!(::Type{ROC}, fpr, tpr)
    if !(issorted(fpr) && issorted(tpr))
        p = sortperm(collect(zip(fpr, tpr)))
        fpr[:] = fpr[p]
        tpr[:] = tpr[p]
    end

    if !issorted(tpr)
        throw(ArgumentError("the $T curve is not monotonic"))
    end

    fpr, tpr
end

struct PRC <: PerformanceCurve
    recall::Vector{Float64}
    precision::Vector{Float64}
    function PRC(recall::Vector{Float64}, precision::Vector{Float64}; kwargs...)
        recall, precision = prepare!(PRC, deepcopy(recall), deepcopy(precision); kwargs...)
        new(recall, precision)
    end
end
PRC(baseline::Float64=0.5) = PRC([0.0, 0.0, 1.0, 1.0], [1.0, baseline, baseline, 0.0])
PRC(gt::AbstractArray{Int}) = PRC(mean(gt))
PRC(c::Curve) = PRC(c.xs, c.ys)

recall(r::PRC) = r.recall

precision(r::PRC) = r.precision

xmetric(::Type{PRC}) = MLBase.recall

ymetric(::Type{PRC}) = MLBase.precision

xlabel(::Type{PRC}) = :Recall

ylabel(::Type{PRC}) = :Precision

startpoint(::Type{PRC}, recall, precision) = (0.0, 1.0)

endpoint(::Type{PRC}, recall, precision) = (1.0, 0.0)

xvalues(r::PRC) = recall(r)

yvalues(r::PRC) = precision(r)

function prcorder((r1, p1), (r2, p2))
    isequal(r1, r2) && return isless(p2, p1)
    isless(r1, r2)
end

function sortage!(::Type{PRC}, recall, precision)
    p = sortperm(collect(zip(recall, precision)); lt = prcorder)
    recall[:] = recall[p]
    precision[:] = precision[p]

    recall, precision
end

@recipe function plotroc(r::ROC)
    a = auc(r)
    if !get(plotattributes, :noauc, false)
        label := if haskey(plotattributes, :label) && plotattributes[:label] != ""
            @sprintf "%s (AUC = %0.3f)" plotattributes[:label] a
        elseif !haskey(plotattributes, :label)
            @sprintf "AUC = %0.3f" a
        end
    end

    xlims := (0, 1)
    ylims := (0, 1)

    grid -> false
    legend --> ifelse(a ≥ 0.5, :bottomright, :topleft)
    size --> (600, 600)
    xguide --> "FPR"
    yguide --> "TPR"
    linewidth --> 2

    @series begin
        r.fpr, r.tpr
    end

    @series begin
        seriestype := :path
        line := :dash
        linewidth := 2
        seriescolor := :dimgray
        label := nothing
        [0,1], [0,1]
    end
end

safelog(x::Float64) = iszero(x) ? zero(x) : log(x)
function rescale(scores::AbstractArray{Float64})
    a, b = extrema(scores)
    @. (scores - a) / (b - a)
end

function perf(arena::AbstractArena, edges::Vector{EdgeEvidence}, kernel::Function)
    g = graph(arena)
    gt = Float64[has_edge(g, e.src, e.dst) for e in edges]
    scores = rescale([e.evidence for e in edges])
    ll = 0.
    for (g, s) in zip(gt, scores)
        ll += kernel(g, s)
    end
    ll / length(edges)
end

logloss(arena, edges) = perf(arena, edges, (g,s) -> -(g * safelog(s) + (1. - g) * safelog(1. - s)))
brier(arena, edges) = perf(arena, edges, (g,s) -> (g - s)^2)


text:
using CSV
using DataFrames
using Plots
using Statistics

pyplot()

function convert_to_array(str)
    els = split(str, ',')

    if "n/a" in els
        @warn "Benchmark contains 'n/a' values. These will be ignored."
        filter!(el -> el != "n/a", els)
    end

    return parse.(Float64, els)
end

labels = Dict(
              "gemmkernels" => "Our implementation",
              "cublas" => "cuBLAS",
              "cutlass" => "CUTLASS",
              "cudajl" => "CUDA.jl",
             )

seriesnumbers = Dict(
              "gemmkernels" => 1,
              "cublas" => 2,
              "cutlass" => 3,
              "cudajl" => 4,
             )

markershapes = Dict(
                    "nn" => :circle,
                    "tt" => :cross,
                    "tn" => :diamond,
                    "nt" => :dtriangle,
                   )

for file in readdir()
    if isfile(file) && splitext(basename(file))[2] == ".csv"
        filename = splitext(basename(file))[1]

        implementation = split(filename, "-")[1] # e.g. gemmkernels
        layout = split(filename, "-")[2] # e.g. nn

        label = layout == "nn" ? labels[implementation] : ""
        seriesnr = seriesnumbers[implementation]
        markershape = markershapes[layout]

        df = DataFrame(CSV.File(file))

        N = df[!, :N]
        runtime_arr = convert_to_array.(df[!, :runtime]) .* 1e3 # in ps
        flops_factor = 2
        tflops = [flops_factor * N[i] ^ 3 ./ runtime_arr[i] for i = 1 : length(N)]

        plot!(N, mean.(tflops), seriescolor=seriesnr, label=label, xscale=:log2, markershape=markershape, ribbon=std.(tflops), fillalpha=.5)
    end
end

title!("Performance of mixed-precision GEMM")
xlabel!("N")
ylabel!("TFLOPS")
savefig("plot.pdf")


text:
export TensorNetworkLayout, order_greedy
export abstract_contract

struct TensorNetworkLayout
    graph::SimpleGraph{Int}
    log2_shapes::Vector{Vector{Float64}}
    function TensorNetworkLayout(graph, log2_shapes)
        @assert nv(graph) == length(log2_shapes) "size of graph ($(nv(graph))) and length of shapes ($(length(log2_shapes))) does not match!"
        new(graph, log2_shapes)
    end
end

LightGraphs.edges(tn::TensorNetworkLayout) = edges(tn.graph)

"""
abstract contraction of  each edge, returns the time complexity and space complexity.
"""
function abstract_contract_edge!(edge, log2_shapes::Vector{Vector{Float64}}, edge_info::EdgeInfo,
        neighbors::Vector{Vector{ET}}, strategy::String) where ET
    haskey(edge_info, edge) || error("edge $edge not found!")
    i, j = src(edge), dst(edge)
    remove!(edge_info, [i, j, neighbors[i]..., neighbors[j]...])
    local log2_shapei, log2_shapej, log2_shapeij
    idxi_j = indexof(j, neighbors[i])
    idxj_i = indexof(i, neighbors[j])
    log2_shapeij = log2_shapes[i][idxi_j]
    deleteat!(log2_shapes[i], idxi_j)
    deleteat!(log2_shapes[j], idxj_i)
    deleteat!(neighbors[i], idxi_j)
    deleteat!(neighbors[j], idxj_i)
    log2_shapei, log2_shapej = sum(log2_shapes[i]), sum(log2_shapes[j])
    for node in neighbors[j]  # rm multi-edge
        idxj_n = indexof(node, neighbors[j])
        idxn_j = indexof(j, neighbors[node])
        if node in neighbors[i]
            idxi_n = indexof(node, neighbors[i])
            idxn_i = indexof(i, neighbors[node])
            log2_shapes[i][idxi_n] += log2_shapes[j][idxj_n]
            log2_shapes[node][idxn_i] += log2_shapes[node][idxn_j]
            deleteat!(log2_shapes[node], idxn_j)
            deleteat!(neighbors[node], idxn_j)
        else
            push!(log2_shapes[i], log2_shapes[j][idxj_n])
            push!(neighbors[i], node)
            neighbors[node][idxn_j] = i
        end
    end
    add!(edge_info, [i, neighbors[i]...], log2_shapes, neighbors, strategy)
    log2_tc = log2_shapei + log2_shapeij + log2_shapej
    log2_sc = log2_shapei + log2_shapej
    # completely remove j
    empty!(log2_shapes[j])
    empty!(neighbors[j])
    return log2_tc, log2_sc
end

"""
    order_greedy(tn::TensorNetworkLayout; strategy="min_dim")

Compute greedy order, return the time and space complexities.
"""
function order_greedy(tn::TensorNetworkLayout; strategy="min_dim", edge_pool=collect(edges(tn)))
    order = SimpleEdge{Int}[]
    log2_shapes = deepcopy(tn.log2_shapes)
    neighbors = deepcopy(tn.graph.fadjlist)
    edge_info = edgeinfo(edges(tn), log2_shapes, neighbors, strategy)
    log2_tcs = Float64[] # time complexity
    log2_scs = Float64[] # space complexity

    while !isempty(edge_pool)
        edge = select(edge_info, strategy, neighbors, edge_pool)
        push!(order, edge)
        log2_tc_step, log2_sc_step = abstract_contract_edge!(edge, log2_shapes, edge_info, neighbors, strategy)
        push!(log2_tcs, log2_tc_step)
        push!(log2_scs, log2_sc_step)
        deleteat!(edge_pool, indexof(edge, edge_pool))

        i, j = src(edge), dst(edge)
        for (l, el) in enumerate(edge_pool)
            if j == src(el) || j == dst(el)
                k = src(el) == j ? dst(el) : src(el)
                edge_pool[l] = uedge(i, k)
            end
        end
        edge_pool = unique(edge_pool)
    end
    return log2_tcs, log2_scs, order
end

function abstract_contract(tn::TensorNetworkLayout, order)
    @assert check_healthy(tn) "tensor network shape mismatch!"
    log2_tcs = Float64[]
    log2_scs = Float64[]
    log2_shapes = deepcopy(tn.log2_shapes)
    neighbors = deepcopy(tn.graph.fadjlist)
    edge_info = edgeinfo(edges(tn), log2_shapes, neighbors, "min_dim")
    maxsize = 0.0
    for edge in order
        log2_tc, log2_sc = abstract_contract_edge!(edge, log2_shapes, edge_info, neighbors, "min_dim")
        push!(log2_tcs, log2_tc)
        push!(log2_scs, compute_log2_sc(log2_shapes))
        maxsize = max(maxsize, maximum(sum.(log2_shapes)))
    end
    return log2_tcs, log2_scs, maxsize
end

function check_healthy(tn::TensorNetworkLayout)
    res = true
    for i in vertices(tn.graph)
        for j in neighbors(tn.graph, i)
            res = res && (edgesize(tn, i, j) == edgesize(tn, j, i))
        end
    end
    return res
end

log2size(s) = isempty(s) ? -Inf : sum(s)
compute_log2_sc(log2_shapes) = (isempty(log2_shapes) || all(isempty, log2_shapes)) ? 0.0 : log2sumexp2(log2size.(log2_shapes))

edgesize(tn::TensorNetworkLayout, m::Int, n::Int) = tn.log2_shapes[n][indexof(m, neighbors(tn.graph, n))]


text:
# ---
# jupyter:
#   jupytext:
#     formats: ipynb,jl:hydrogen
#     text_representation:
#       extension: .jl
#       format_name: hydrogen
#       format_version: '1.3'
#       jupytext_version: 1.11.2
#   kernelspec:
#     display_name: Julia 1.6.2
#     language: julia
#     name: julia-1.6
# ---

# %%
module O

struct Foo{A, B}
    a::A
    b::B
end

struct Bar{A, B}
    a::A
    b::B
    Bar(a::A = 12) where A = new{A, A}(a, 2a)
end

end

# %%
O.Foo(12, 34)

# %%
O.Foo{Float64, Float64}(12, 34)

# %%
methods(O.Foo)

# %%
methods(O.Foo{Float64, Float64})

# %%
O.Bar()

# %%
O.Bar(12.34)

# %%
methods(O.Bar)

# %%
methods(O.Bar{Float64, Float64})

# %%
O.Bar(Int8(3))

# %%
O.Bar(Int8(64))

# %%
@eval O struct Bar{A, B}
    a::A
    b::B
    Bar(a::A = 12) where A = new{A, A}(a, A(2)a)
end

# %%
O.Bar(Int8(64))

# %%
O.Bar(UInt8(128))

# %%
2UInt8(128)

# %%
UInt8(2)UInt8(128)

# %%

max_stars_repo_path: 0019/inner constructor.jl

max_stars_repo_name: genkuroki/public

max_issues_repo_path: 0019/inner constructor.jl

max_issues_repo_name: genkuroki/public

max_forks_repo_path: 0019/inner constructor.jl

max_forks_repo_name: genkuroki/public


text:
using vOptGeneric
using Test, LinearAlgebra
using GLPK, GLPKMathProgInterface

function run_tests()
        m = vModel(solver = GLPKSolverMIP())

        @variable(m, x[1:6,1:6], Bin)
        @variable(m, y, Bin)
        M = 50
        p1 =   [M 4 5 M M M;
                M M 2 1 2 7;
                M M M 5 2 M;
                M M 5 M M 3;
                M M M M M 4;
                M M M M M M]
        p2 =   [M 3 1 M M M;
                M M 1 4 2 2;
                M M M 1 7 M;
                M M 1 M M 2;
                M M M M M 2;
                M M M M M M]

        @addobjective(m, Min , sum(x[i,j]*p1[i,j] for i=1:6, j=1:6))
        @addobjective(m, Min , sum(x[i,j]*p2[i,j] for i=1:6, j=1:6))
        @constraint(m, sum(x[1,j] for j = 1:6) == 1)
        @constraint(m, sum(x[i,6] for i = 1:6) == 1)
        @constraint(m, cstr[i=2:5], sum(x[i,j] for j = 1:6) - sum(x[j,i] for j =1:6) == 0)

        solve(m, method=:epsilon)

        Y_N = getY_N(m)
        f1 = map(x -> x[1], Y_N)
        f2 = map(x -> x[2], Y_N)

        @test f1 == [8.0,10.0,11.0,13.0]
        @test f2 == [9.0,7.0,5.0,4.0]
        @test getvalue(x, 1) == [0.0 1.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 1.0; 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0]
        printX_E(m)

        writeMOP(m, "test.txt")
        m = parseMOP("test.txt", solver = GLPKSolverMIP())
        solve(m, method=:dichotomy)
        Y_N = getY_N(m)
        f1 = map(x -> x[1], Y_N)
        f2 = map(x -> x[2], Y_N)
        @test f1 == [8.0, 11.0, 13.0]
        @test f2 == [9.0, 5.0, 4.0]

        m = vModel(solver = GLPKSolverMIP())
        # using CPLEX
        # m = vModel(solver = CplexSolver())

        p1 = [77,94,71,63,96,82,85,75,72,91,99,63,84,87,79,94,90,60,69,62]
        p2 = [65,90,90,77,95,84,70,94,66,92,74,97,60,60,65,97,93,60,69,74]
        w = [80,87,68,72,66,77,99,85,70,93,98,72,100,89,67,86,91,79,71,99]
        c = 900
        size = length(p1)

        @variable(m, x[1:size], Bin)
        @addobjective(m, Max, dot(x, p1))
        @addobjective(m, Max, dot(x, p2))
        @constraint(m, dot(x, w) <= c)

        solve(m, method=:chalmet)

        Y_N = getY_N(m)
        f1 = map(x -> x[1], Y_N)
        f2 = map(x -> x[2], Y_N)

        @test f1 == [918.0, 924.0, 927.0, 934.0, 935.0, 940.0, 943.0, 948.0, 949.0, 952.0, 955.0]
        @test f2 == [984.0, 975.0, 972.0, 971.0, 947.0, 943.0, 940.0, 939.0, 915.0, 909.0, 906.0]
        @test getvalue(x, 1) == [0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0]

        solve(m, method=:lex)
        Y_N = getY_N(m)
        @test Y_N == [[955.0, 906.0], [918.0, 984.0]]
end

run_tests()


text:
#==============================================================================#
# ResourceGroups.jl
#
# This file is generated from:
# https://github.com/aws/aws-sdk-js/blob/master/apis/resource-groups-2017-11-27.normal.json
#==============================================================================#

__precompile__()

module ResourceGroups

using AWSCore

"""
    using AWSSDK.ResourceGroups.create_group
    create_group([::AWSConfig], arguments::Dict)
    create_group([::AWSConfig]; Name=, ResourceQuery=, <keyword arguments>)

    using AWSCore.Services.resource_groups
    resource_groups([::AWSConfig], "POST", "/groups", arguments::Dict)
    resource_groups([::AWSConfig], "POST", "/groups", Name=, ResourceQuery=, <keyword arguments>)

# CreateGroup Operation

Creates a group with a specified name, description, and resource query.

# Arguments

## `Name = ::String` -- *Required*
The name of the group, which is the identifier of the group in other operations. A resource group name cannot be updated after it is created. A resource group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`; these are reserved. A resource group name must be unique within your account.

## `Description = ::String`
The description of the resource group. Descriptions can have a maximum of 511 characters, including letters, numbers, hyphens, underscores, punctuation, and spaces.

## `ResourceQuery = [ ... ]` -- *Required*
The resource query that determines which AWS resources are members of this group.
```
 ResourceQuery = [
        "Type" => <required> "TAG_FILTERS_1_0",
        "Query" => <required> ::String
    ]
```

## `Tags = ::Dict{String,String}`
The tags to add to the group. A tag is a string-to-string map of key-value pairs. Tag keys can have a maximum character length of 127 characters, and tag values can have a maximum length of 255 characters.

# Returns

`CreateGroupOutput`

# Exceptions

`BadRequestException`, `ForbiddenException`, `MethodNotAllowedException`, `TooManyRequestsException` or `InternalServerErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/resource-groups-2017-11-27/CreateGroup)
"""
@inline create_group(aws::AWSConfig=default_aws_config(); args...) = create_group(aws, args)

@inline create_group(aws::AWSConfig, args) = AWSCore.Services.resource_groups(aws, "POST", "/groups", args)

@inline create_group(args) = create_group(default_aws_config(), args)

"""
    using AWSSDK.ResourceGroups.delete_group
    delete_group([::AWSConfig], arguments::Dict)
    delete_group([::AWSConfig]; GroupName=)

    using AWSCore.Services.resource_groups
    resource_groups([::AWSConfig], "DELETE", "/groups/{GroupName}", arguments::Dict)
    resource_groups([::AWSConfig], "DELETE", "/groups/{GroupName}", GroupName=)

# DeleteGroup Operation

Deletes a specified resource group. Deleting a resource group does not delete resources that are members of the group; it only deletes the group structure.

# Arguments

## `GroupName = ::String` -- *Required*
The name of the resource group to delete.

# Returns

`DeleteGroupOutput`

# Exceptions

`BadRequestException`, `ForbiddenException`, `NotFoundException`, `MethodNotAllowedException`, `TooManyRequestsException` or `InternalServerErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/resource-groups-2017-11-27/DeleteGroup)
"""
@inline delete_group(aws::AWSConfig=default_aws_config(); args...) = delete_group(aws, args)

@inline delete_group(aws::AWSConfig, args) = AWSCore.Services.resource_groups(aws, "DELETE", "/groups/{GroupName}", args)

@inline delete_group(args) = delete_group(default_aws_config(), args)

"""
    using AWSSDK.ResourceGroups.get_group
    get_group([::AWSConfig], arguments::Dict)
    get_group([::AWSConfig]; GroupName=)

    using AWSCore.Services.resource_groups
    resource_groups([::AWSConfig], "GET", "/groups/{GroupName}", arguments::Dict)
    resource_groups([::AWSConfig], "GET", "/groups/{GroupName}", GroupName=)

# GetGroup Operation

Returns information about a specified resource group.

# Arguments

## `GroupName = ::String` -- *Required*
The name of the resource group.

# Returns

`GetGroupOutput`

# Exceptions

`BadRequestException`, `ForbiddenException`, `NotFoundException`, `MethodNotAllowedException`, `TooManyRequestsException` or `InternalServerErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/resource-groups-2017-11-27/GetGroup)
"""
@inline get_group(aws::AWSConfig=default_aws_config(); args...) = get_group(aws, args)

@inline get_group(aws::AWSConfig, args) = AWSCore.Services.resource_groups(aws, "GET", "/groups/{GroupName}", args)

@inline get_group(args) = get_group(default_aws_config(), args)

"""
    using AWSSDK.ResourceGroups.get_group_query
    get_group_query([::AWSConfig], arguments::Dict)
    get_group_query([::AWSConfig]; GroupName=)

    using AWSCore.Services.resource_groups
    resource_groups([::AWSConfig], "GET", "/groups/{GroupName}/query", arguments::Dict)
    resource_groups([::AWSConfig], "GET", "/groups/{GroupName}/query", GroupName=)

# GetGroupQuery Operation

Returns the resource query associated with the specified resource group.

# Arguments

## `GroupName = ::String` -- *Required*
The name of the resource group.

# Returns

`GetGroupQueryOutput`

# Exceptions

`BadRequestException`, `ForbiddenException`, `NotFoundException`, `MethodNotAllowedException`, `TooManyRequestsException` or `InternalServerErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/resource-groups-2017-11-27/GetGroupQuery)
"""
@inline get_group_query(aws::AWSConfig=default_aws_config(); args...) = get_group_query(aws, args)

@inline get_group_query(aws::AWSConfig, args) = AWSCore.Services.resource_groups(aws, "GET", "/groups/{GroupName}/query", args)

@inline get_group_query(args) = get_group_query(default_aws_config(), args)

"""
    using AWSSDK.ResourceGroups.get_tags
    get_tags([::AWSConfig], arguments::Dict)
    get_tags([::AWSConfig]; Arn=)

    using AWSCore.Services.resource_groups
    resource_groups([::AWSConfig], "GET", "/resources/{Arn}/tags", arguments::Dict)
    resource_groups([::AWSConfig], "GET", "/resources/{Arn}/tags", Arn=)

# GetTags Operation

Returns a list of tags that are associated with a resource, specified by an ARN.

# Arguments

## `Arn = ::String` -- *Required*
The ARN of the resource for which you want a list of tags. The resource must exist within the account you are using.

# Returns

`GetTagsOutput`

# Exceptions

`BadRequestException`, `ForbiddenException`, `NotFoundException`, `MethodNotAllowedException`, `TooManyRequestsException` or `InternalServerErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/resource-groups-2017-11-27/GetTags)
"""
@inline get_tags(aws::AWSConfig=default_aws_config(); args...) = get_tags(aws, args)

@inline get_tags(aws::AWSConfig, args) = AWSCore.Services.resource_groups(aws, "GET", "/resources/{Arn}/tags", args)

@inline get_tags(args) = get_tags(default_aws_config(), args)

"""
    using AWSSDK.ResourceGroups.list_group_resources
    list_group_resources([::AWSConfig], arguments::Dict)
    list_group_resources([::AWSConfig]; GroupName=, <keyword arguments>)

    using AWSCore.Services.resource_groups
    resource_groups([::AWSConfig], "GET", "/groups/{GroupName}/resource-identifiers", arguments::Dict)
    resource_groups([::AWSConfig], "GET", "/groups/{GroupName}/resource-identifiers", GroupName=, <keyword arguments>)

# ListGroupResources Operation

Returns a list of ARNs of resources that are members of a specified resource group.

# Arguments

## `GroupName = ::String` -- *Required*
The name of the resource group.

## `maxResults = ::Int`
The maximum number of group member ARNs that are returned in a single call by ListGroupResources, in paginated output. By default, this number is 50.

## `nextToken = ::String`
The NextToken value that is returned in a paginated ListGroupResources request. To get the next page of results, run the call again, add the NextToken parameter, and specify the NextToken value.

# Returns

`ListGroupResourcesOutput`

# Exceptions

`UnauthorizedException`, `BadRequestException`, `ForbiddenException`, `NotFoundException`, `MethodNotAllowedException`, `TooManyRequestsException` or `InternalServerErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/resource-groups-2017-11-27/ListGroupResources)
"""
@inline list_group_resources(aws::AWSConfig=default_aws_config(); args...) = list_group_resources(aws, args)

@inline list_group_resources(aws::AWSConfig, args) = AWSCore.Services.resource_groups(aws, "GET", "/groups/{GroupName}/resource-identifiers", args)

@inline list_group_resources(args) = list_group_resources(default_aws_config(), args)

"""
    using AWSSDK.ResourceGroups.list_groups
    list_groups([::AWSConfig], arguments::Dict)
    list_groups([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.resource_groups
    resource_groups([::AWSConfig], "GET", "/groups", arguments::Dict)
    resource_groups([::AWSConfig], "GET", "/groups", <keyword arguments>)

# ListGroups Operation

Returns a list of existing resource groups in your account.

# Arguments

## `maxResults = ::Int`
The maximum number of resource group results that are returned by ListGroups in paginated output. By default, this number is 50.

## `nextToken = ::String`
The NextToken value that is returned in a paginated `ListGroups` request. To get the next page of results, run the call again, add the NextToken parameter, and specify the NextToken value.

# Returns

`ListGroupsOutput`

# Exceptions

`BadRequestException`, `ForbiddenException`, `MethodNotAllowedException`, `TooManyRequestsException` or `InternalServerErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/resource-groups-2017-11-27/ListGroups)
"""
@inline list_groups(aws::AWSConfig=default_aws_config(); args...) = list_groups(aws, args)

@inline list_groups(aws::AWSConfig, args) = AWSCore.Services.resource_groups(aws, "GET", "/groups", args)

@inline list_groups(args) = list_groups(default_aws_config(), args)

"""
    using AWSSDK.ResourceGroups.search_resources
    search_resources([::AWSConfig], arguments::Dict)
    search_resources([::AWSConfig]; ResourceQuery=, <keyword arguments>)

    using AWSCore.Services.resource_groups
    resource_groups([::AWSConfig], "POST", "/resources/search", arguments::Dict)
    resource_groups([::AWSConfig], "POST", "/resources/search", ResourceQuery=, <keyword arguments>)

# SearchResources Operation

Returns a list of AWS resource identifiers that matches a specified query. The query uses the same format as a resource query in a CreateGroup or UpdateGroupQuery operation.

# Arguments

## `ResourceQuery = [ ... ]` -- *Required*
The search query, using the same formats that are supported for resource group definition.
```
 ResourceQuery = [
        "Type" => <required> "TAG_FILTERS_1_0",
        "Query" => <required> ::String
    ]
```

## `MaxResults = ::Int`
The maximum number of group member ARNs returned by `SearchResources` in paginated output. By default, this number is 50.

## `NextToken = ::String`
The NextToken value that is returned in a paginated `SearchResources` request. To get the next page of results, run the call again, add the NextToken parameter, and specify the NextToken value.

# Returns

`SearchResourcesOutput`

# Exceptions

`UnauthorizedException`, `BadRequestException`, `ForbiddenException`, `MethodNotAllowedException`, `TooManyRequestsException` or `InternalServerErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/resource-groups-2017-11-27/SearchResources)
"""
@inline search_resources(aws::AWSConfig=default_aws_config(); args...) = search_resources(aws, args)

@inline search_resources(aws::AWSConfig, args) = AWSCore.Services.resource_groups(aws, "POST", "/resources/search", args)

@inline search_resources(args) = search_resources(default_aws_config(), args)

"""
    using AWSSDK.ResourceGroups.tag
    tag([::AWSConfig], arguments::Dict)
    tag([::AWSConfig]; Arn=, Tags=)

    using AWSCore.Services.resource_groups
    resource_groups([::AWSConfig], "PUT", "/resources/{Arn}/tags", arguments::Dict)
    resource_groups([::AWSConfig], "PUT", "/resources/{Arn}/tags", Arn=, Tags=)

# Tag Operation

Adds specified tags to a resource with the specified ARN. Existing tags on a resource are not changed if they are not specified in the request parameters.

# Arguments

## `Arn = ::String` -- *Required*
The ARN of the resource to which to add tags.

## `Tags = ::Dict{String,String}` -- *Required*
The tags to add to the specified resource. A tag is a string-to-string map of key-value pairs. Tag keys can have a maximum character length of 127 characters, and tag values can have a maximum length of 255 characters.

# Returns

`TagOutput`

# Exceptions

`BadRequestException`, `ForbiddenException`, `NotFoundException`, `MethodNotAllowedException`, `TooManyRequestsException` or `InternalServerErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/resource-groups-2017-11-27/Tag)
"""
@inline tag(aws::AWSConfig=default_aws_config(); args...) = tag(aws, args)

@inline tag(aws::AWSConfig, args) = AWSCore.Services.resource_groups(aws, "PUT", "/resources/{Arn}/tags", args)

@inline tag(args) = tag(default_aws_config(), args)

"""
    using AWSSDK.ResourceGroups.untag
    untag([::AWSConfig], arguments::Dict)
    untag([::AWSConfig]; Arn=, Keys=)

    using AWSCore.Services.resource_groups
    resource_groups([::AWSConfig], "PATCH", "/resources/{Arn}/tags", arguments::Dict)
    resource_groups([::AWSConfig], "PATCH", "/resources/{Arn}/tags", Arn=, Keys=)

# Untag Operation

Deletes specified tags from a specified resource.

# Arguments

## `Arn = ::String` -- *Required*
The ARN of the resource from which to remove tags.

## `Keys = [::String, ...]` -- *Required*
The keys of the tags to be removed.

# Returns

`UntagOutput`

# Exceptions

`BadRequestException`, `ForbiddenException`, `NotFoundException`, `MethodNotAllowedException`, `TooManyRequestsException` or `InternalServerErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/resource-groups-2017-11-27/Untag)
"""
@inline untag(aws::AWSConfig=default_aws_config(); args...) = untag(aws, args)

@inline untag(aws::AWSConfig, args) = AWSCore.Services.resource_groups(aws, "PATCH", "/resources/{Arn}/tags", args)

@inline untag(args) = untag(default_aws_config(), args)

"""
    using AWSSDK.ResourceGroups.update_group
    update_group([::AWSConfig], arguments::Dict)
    update_group([::AWSConfig]; GroupName=, <keyword arguments>)

    using AWSCore.Services.resource_groups
    resource_groups([::AWSConfig], "PUT", "/groups/{GroupName}", arguments::Dict)
    resource_groups([::AWSConfig], "PUT", "/groups/{GroupName}", GroupName=, <keyword arguments>)

# UpdateGroup Operation

Updates an existing group with a new or changed description. You cannot update the name of a resource group.

# Arguments

## `GroupName = ::String` -- *Required*
The name of the resource group for which you want to update its description.

## `Description = ::String`
The description of the resource group. Descriptions can have a maximum of 511 characters, including letters, numbers, hyphens, underscores, punctuation, and spaces.

# Returns

`UpdateGroupOutput`

# Exceptions

`BadRequestException`, `ForbiddenException`, `NotFoundException`, `MethodNotAllowedException`, `TooManyRequestsException` or `InternalServerErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/resource-groups-2017-11-27/UpdateGroup)
"""
@inline update_group(aws::AWSConfig=default_aws_config(); args...) = update_group(aws, args)

@inline update_group(aws::AWSConfig, args) = AWSCore.Services.resource_groups(aws, "PUT", "/groups/{GroupName}", args)

@inline update_group(args) = update_group(default_aws_config(), args)

"""
    using AWSSDK.ResourceGroups.update_group_query
    update_group_query([::AWSConfig], arguments::Dict)
    update_group_query([::AWSConfig]; GroupName=, ResourceQuery=)

    using AWSCore.Services.resource_groups
    resource_groups([::AWSConfig], "PUT", "/groups/{GroupName}/query", arguments::Dict)
    resource_groups([::AWSConfig], "PUT", "/groups/{GroupName}/query", GroupName=, ResourceQuery=)

# UpdateGroupQuery Operation

Updates the resource query of a group.

# Arguments

## `GroupName = ::String` -- *Required*
The name of the resource group for which you want to edit the query.

## `ResourceQuery = [ ... ]` -- *Required*
The resource query that determines which AWS resources are members of the resource group.
```
 ResourceQuery = [
        "Type" => <required> "TAG_FILTERS_1_0",
        "Query" => <required> ::String
    ]
```

# Returns

`UpdateGroupQueryOutput`

# Exceptions

`BadRequestException`, `ForbiddenException`, `NotFoundException`, `MethodNotAllowedException`, `TooManyRequestsException` or `InternalServerErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/resource-groups-2017-11-27/UpdateGroupQuery)
"""
@inline update_group_query(aws::AWSConfig=default_aws_config(); args...) = update_group_query(aws, args)

@inline update_group_query(aws::AWSConfig, args) = AWSCore.Services.resource_groups(aws, "PUT", "/groups/{GroupName}/query", args)

@inline update_group_query(args) = update_group_query(default_aws_config(), args)

end # module ResourceGroups

#==============================================================================#
# End of file
#==============================================================================#


text:
###################################################
## tools.jl
## path tool functions
###################################################

"""
    `pathRoads`: get a list of roads for a list of path nodes id
"""
function pathRoads(n::Network,p::Vector{Int})
    return [n.roads[p[i],p[i+1]] for i in 1:length(p)-1]
end

max_stars_repo_name: andrew-zhm/RoutingNetworks

max_issues_repo_name: andrew-zhm/RoutingNetworks

max_forks_repo_name: andrew-zhm/RoutingNetworks


text:
# each data point
mutable struct Point
    data::Array
    label::Int64
    not_visited::Bool
    pt::Union{Nothing, Bool}
    Point(data::Array) = new(data, -1, true, nothing)
end
# calculate distance between x1 and x2
dist(p1::Point, p2::Point) = sum((p2.data - p1.data) .^ 2)

"""
    DBSCAN(ε, minpts)
Density-based spatial clustering of applications with noise. In a word, if number of neighbors of a data is more than `minpts`, extend a cluster, if not, establish a cluster.

# Parameters:
- `ε`: maximum distance of neighbors.
- `minpts`: minimum number of neighbors of a data

# Example
```jldoctest
julia> model = DBSCAN(0.3, 5)
DBSCAN(0.09, 5, 0, Point[])

julia> model(x) |> size
(100, 3)
```
"""
mutable struct DBSCAN
    ε::Float64
    minpts::Int64
    label::Int64
    points::Array{Point, 1}
    DBSCAN(ε::Float64, minpts::Int64) = new(ε^2, minpts, 0, Array{Point}(undef, 0))
end

function (model::DBSCAN)(x)
    model.points = [Point(x[i, :]) for i in 1 : size(x, 1)]
    for p in model.points
        if p.not_visited
            p.not_visited = false
            neighbor_pts = range_query(model.points, p, model.ε)
            if length(neighbor_pts) < model.minpts
                # NOISE
                p.pt = false
            else
                # CORE POINT
                p.pt = true
                expand_cluster(model, p, neighbor_pts)
                model.label += 1
            end
        end
    end
    return [p.label for p in model.points]
end

function expand_cluster(model, p::Point, neighbor_pts::Array{Point, 1})
    p.label = model.label
    for q in neighbor_pts
        if q.not_visited
            q.not_visited = false
            neighbor_pts_q = range_query(model.points, q, model.ε)
            if length(neighbor_pts_q) >= model.minpts
                q.pt = true
                append!(neighbor_pts, neighbor_pts_q)
            end
        end
        if q.label == -1
            q.label = model.label
        end
    end

end

range_query(points::Array{Point, 1}, p::Point, ε::Float64) = filter(x -> dist(p, x) <= ε, points)


text:
import DistanceFields as DF
import Test

Test.@testset "DistanceFields.jl" begin
    a = fill(-1, 10)
    b = fill(100000.0, 10)
    b[1] = 0
    b[4] = 0
    DF.euclidean_distance_transform!(a, b)
    Test.@test a == [0, 1, 1, 0, 1, 4, 9, 16, 25, 36]
end