text:
using Compat # for CartesianIndices
using OSQP.MathOptInterfaceOSQP
using Compat.Test
using Compat.LinearAlgebra
using Compat.SparseArrays

using MathOptInterface
const MOI = MathOptInterface

using MathOptInterface.Test
const MOIT = MathOptInterface.Test

using MathOptInterface.Utilities
const MOIU = MathOptInterface.Utilities

const Affine = MOI.ScalarAffineFunction{Float64}

@testset "ProblemModificationCache" begin
    rng = MersenneTwister(1234)
    n = 15
    m = 10
    q = randn(rng, n)
    P = (X = sprandn(rng, n, n, 0.1); X' * X)
    P += eps() * I # needed for a test later on
    l = -rand(rng, m)
    u = rand(rng, m)
    A = sprandn(rng, m, n, 0.6)
    modcache = MathOptInterfaceOSQP.ProblemModificationCache(P, q, A, l, u)

    model = OSQP.Model()
    OSQP.setup!(model; P = P, q = q, A = A, l = l, u = u, verbose = false, eps_abs = 1e-8, eps_rel = 1e-16)
    baseresults = OSQP.solve!(model)
    @test baseresults.info.status == :Solved

    # Modify q, ensure that updating results in the same solution as calling setup! with the modified q
    @test !modcache.q.dirty
    modcache.q[3] = 5.
    @test modcache.q.dirty
    @test modcache.q.data[3] == 5.
    MathOptInterfaceOSQP.processupdates!(model, modcache)
    @test !modcache.q.dirty
    qmod_update_results = OSQP.solve!(model)
    @test !isapprox(baseresults.x, qmod_update_results.x; atol = 1e-1) # ensure that new results are significantly different
    model2 = OSQP.Model()
    OSQP.setup!(model2; P = P, q = modcache.q.data, A = A, l = l, u = u, verbose = false, eps_abs = 1e-8, eps_rel = 1e-16)
    qmod_setup_results = OSQP.solve!(model2)
    @test qmod_update_results.x ≈ qmod_setup_results.x atol = 1e-7

    # Modify A, ensure that updating results in the same solution as calling setup! with the modified A and q
    (rows, cols, _) = findnz(A)
    Amodindex = rand(rng, 1 : nnz(A))
    row = rows[Amodindex]
    col = cols[Amodindex]
    val = randn(rng)
    modcache.A[row, col] = val
    MathOptInterfaceOSQP.processupdates!(model, modcache)
    @test isempty(modcache.A.modifications)
    Amod_update_results = OSQP.solve!(model)
    @test !isapprox(baseresults.x, Amod_update_results.x; atol = 1e-1) # ensure that new results are significantly different
    @test !isapprox(qmod_update_results.x, Amod_update_results.x; atol = 1e-1) # ensure that new results are significantly different
    Amod = copy(A)
    Amod[row, col] = val
    model3 = OSQP.Model()
    OSQP.setup!(model3; P = P, q = modcache.q.data, A = Amod, l = l, u = u, verbose = false, eps_abs = 1e-8, eps_rel = 1e-16)
    Amod_setup_results = OSQP.solve!(model3)
    @test Amod_update_results.x ≈ Amod_setup_results.x atol = 1e-7

    # MatrixModificationCache: colon indexing
    modcache.P[:] = 0.
    for i = 1 : n
        modcache.P[i, i] = 1.
    end
    MathOptInterfaceOSQP.processupdates!(model, modcache)
    Pmod_update_results = OSQP.solve!(model)
    model4 = OSQP.Model()
    Pmod = sparse(1.0I, n, n)
    OSQP.setup!(model4; P = Pmod, q = modcache.q.data, A = Amod, l = l, u = u, verbose = false, eps_abs = 1e-8, eps_rel = 1e-16)
    Pmod_setup_results = OSQP.solve!(model4)
    @test Pmod_update_results.x ≈ Pmod_setup_results.x atol = 1e-8

    # Modifying the sparsity pattern is not allowed
    nzinds = map(CartesianIndex, zip(rows, cols))
    zinds = zinds = setdiff(vec(CartesianIndices(A)), nzinds)
    for zind in zinds
        @test_throws ArgumentError modcache.A[zind[1], zind[2]] = randn(rng)
    end
    @test_throws ArgumentError modcache.A[:] = 1
end

# FIXME: type piracy. Generalize and move to MOIU.
MOI.canget(optimizer::MOIU.CachingOptimizer, ::MOI.ConstraintPrimal, ::Type{<:MOI.ConstraintIndex}) = true
function MOI.get(optimizer::MOIU.CachingOptimizer, ::MOI.ConstraintPrimal, ci::MOI.ConstraintIndex{<:MOI.SingleVariable, <:Any})
    f = MOI.get(optimizer, MOI.ConstraintFunction(), ci)
    MOI.get(optimizer, MOI.VariablePrimal(), f.variable)
end
function MOI.get(optimizer::MOIU.CachingOptimizer, ::MOI.ConstraintPrimal, ci::MOI.ConstraintIndex{<:MOI.ScalarAffineFunction, <:Any})
    f = MOI.get(optimizer, MOI.ConstraintFunction(), ci)
    ret = f.constant
    for term in f.terms
        ret += term.coefficient * MOI.get(optimizer, MOI.VariablePrimal(), term.variable_index)
    end
    ret
end

const config = MOIT.TestConfig(atol=1e-4, rtol=1e-4)

function defaultoptimizer()
    optimizer = OSQPOptimizer()
    MOI.set!(optimizer, OSQPSettings.Verbose(), false)
    MOI.set!(optimizer, OSQPSettings.EpsAbs(), 1e-8)
    MOI.set!(optimizer, OSQPSettings.EpsRel(), 1e-16)
    MOI.set!(optimizer, OSQPSettings.MaxIter(), 10000)
    MOI.set!(optimizer, OSQPSettings.AdaptiveRhoInterval(), 25) # required for deterministic behavior
    optimizer
end

@testset "CachingOptimizer: linear problems" begin
    excludes = if Int == Int32
        ["linear7"] # https://github.com/JuliaOpt/MathOptInterface.jl/issues/377#issuecomment-394912761
    else
        String[]
    end
    optimizer = defaultoptimizer()
    MOIT.contlineartest(MOIU.CachingOptimizer(OSQPModel{Float64}(), optimizer), config, excludes)
end

@testset "CachingOptimizer: quadratic problems" begin
    excludes = String[]
    optimizer = defaultoptimizer()
    MOIT.qptest(MOIU.CachingOptimizer(OSQPModel{Float64}(), optimizer), config, excludes)
end

function test_optimizer_modification(modfun::Base.Callable, model::MOI.ModelLike, optimizer::T, idxmap::MOIU.IndexMap,
        cleanoptimizer::T, config::MOIT.TestConfig) where T<:MOI.AbstractOptimizer
    # apply modfun to both the model and the optimizer
    modfun(model)
    modfun(optimizer)

    # copy model into clean optimizer
    cleanidxmap = MOI.copy!(cleanoptimizer, model)
    @test cleanidxmap.varmap == idxmap.varmap
    @test cleanidxmap.conmap == idxmap.conmap

    # call optimize! on both optimizers
    MOI.optimize!(optimizer)
    MOI.optimize!(cleanoptimizer)

    # compare results
    atol = config.atol
    rtol = config.rtol
    @test MOI.get(optimizer, MOI.TerminationStatus()) == MOI.get(cleanoptimizer, MOI.TerminationStatus())
    @test MOI.get(optimizer, MOI.PrimalStatus()) == MOI.get(cleanoptimizer, MOI.PrimalStatus())
    @test MOI.get(optimizer, MOI.ObjectiveValue()) ≈ MOI.get(cleanoptimizer, MOI.ObjectiveValue()) atol=atol rtol=rtol

    if MOI.get(optimizer, MOI.PrimalStatus()) == MOI.FeasiblePoint
        modelvars = MOI.get(model, MOI.ListOfVariableIndices())
        for v_model in modelvars
            v_optimizer = idxmap[v_model]
            @test MOI.get(optimizer, MOI.VariablePrimal(), v_optimizer) ≈ MOI.get(cleanoptimizer, MOI.VariablePrimal(), v_optimizer) atol=atol rtol=rtol
        end
    end

    if config.duals
        @test MOI.get(optimizer, MOI.DualStatus()) == MOI.get(cleanoptimizer, MOI.DualStatus())
        if MOI.get(optimizer, MOI.DualStatus()) == MOI.FeasiblePoint
            for (F, S) in MOI.get(model, MOI.ListOfConstraints())
                cis_model = MOI.get(model, MOI.ListOfConstraintIndices{F, S}())
                for ci_model in cis_model
                    ci_optimizer = idxmap[ci_model]
                    @test MOI.get(optimizer, MOI.ConstraintDual(), ci_optimizer) ≈ MOI.get(cleanoptimizer, MOI.ConstraintDual(), ci_optimizer) atol=atol rtol=rtol
                end
            end
        end
    end
end

function zero_warm_start!(optimizer::MOI.ModelLike, vars, cons)
    for vi in vars
        MOI.set!(optimizer, MOI.VariablePrimalStart(), vi, 0.0)
    end
    for ci in cons
        MOI.set!(optimizer, MOI.ConstraintDualStart(), ci, -0.0)
    end
end

term(c, x::MOI.VariableIndex) = MOI.ScalarAffineTerm(c, x)
term(c, x::MOI.VariableIndex, y::MOI.VariableIndex) = MOI.ScalarQuadraticTerm(c, x, y)

@testset "No CachingOptimizer: problem modification after copy!" begin
    # Initial setup: modified version of MOIT.linear1test
    # min -x
    # st   x + y <= 1   (x + y - 1 ∈ Nonpositives)
    #       x, y >= 0   (x, y ∈ Nonnegatives)
    model = OSQPModel{Float64}()
    MOI.empty!(model)
    v = MOI.addvariables!(model, 2)
    x, y = v
    cf = MOI.ScalarAffineFunction([term.([0.0, 0.0], v); term.([1.0, 1.0], v); term.([0.0, 0.0], v)], 0.0)
    c = MOI.addconstraint!(model, cf, MOI.Interval(-Inf, 1.0))
    vc1 = MOI.addconstraint!(model, MOI.SingleVariable(v[1]), MOI.Interval(0.0, Inf))
    vc2 = MOI.addconstraint!(model, v[2], MOI.Interval(0.0, Inf))
    objf = MOI.ScalarAffineFunction([term.([0.0, 0.0], v); term.([-1.0, 0.0], v); term.([0.0, 0.0], v)], 0.0)
    MOI.set!(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), objf)
    MOI.set!(model, MOI.ObjectiveSense(), MOI.MinSense)

    optimizer = defaultoptimizer()
    idxmap = MOI.copy!(optimizer, model)
    @test MOI.canget(optimizer, MOI.ObjectiveSense())
    @test MOI.get(optimizer, MOI.ObjectiveSense()) == MOI.MinSense
    @test MOI.get(optimizer, MOI.NumberOfVariables()) == 2
    @test MOI.get(optimizer, MOI.ListOfVariableIndices()) == [MOI.VariableIndex(1), MOI.VariableIndex(2)]
    @test MOI.isvalid(optimizer, MOI.VariableIndex(2))
    @test !MOI.isvalid(optimizer, MOI.VariableIndex(3))

    MOI.optimize!(optimizer)

    # ensure that unmodified model is correct
    atol = config.atol
    rtol = config.rtol
    @test MOI.get(optimizer, MOI.TerminationStatus()) == MOI.Success
    @test MOI.get(optimizer, MOI.PrimalStatus()) == MOI.FeasiblePoint
    @test MOI.get(optimizer, MOI.ObjectiveValue()) ≈ -1 atol=atol rtol=rtol
    @test MOI.get(optimizer, MOI.VariablePrimal(), getindex.(Ref(idxmap), v)) ≈ [1, 0] atol=atol rtol=rtol
    @test MOI.get(optimizer, MOI.DualStatus()) == MOI.FeasiblePoint
    @test MOI.get(optimizer, MOI.ConstraintDual(), idxmap[c]) ≈ -1 atol=atol rtol=rtol
    @test MOI.get(optimizer, MOI.ConstraintDual(), idxmap[vc1]) ≈ 0 atol=atol rtol=rtol
    @test MOI.get(optimizer, MOI.ConstraintDual(), idxmap[vc2]) ≈ 1 atol=atol rtol=rtol

    # test default warm start
    tcold = MOI.get(optimizer, MOI.SolveTime())
    MOI.optimize!(optimizer)
    twarm = MOI.get(optimizer, MOI.SolveTime())
    @test twarm < 0.5 * tcold # conservative; should be about an order of magnitude in this case

    # test allocations
    allocs = @allocated MOI.optimize!(optimizer)
    @test allocs == 0

    # ensure that solving a second time results in the same answer after zeroing warm start
    zero_warm_start!(optimizer, values(idxmap.varmap), values(idxmap.conmap))
    test_optimizer_modification(m -> (), model, optimizer, idxmap, defaultoptimizer(), MOIT.TestConfig(atol=0.0, rtol=0.0))

    mapfrommodel(::MOI.AbstractOptimizer, x::Union{MOI.VariableIndex, <:MOI.ConstraintIndex}) = idxmap[x]
    mapfrommodel(::MOI.ModelLike, x::Union{MOI.VariableIndex, <:MOI.ConstraintIndex}) = x

    # change objective to min -2y
    test_optimizer_modification(model, optimizer, idxmap, defaultoptimizer(), config) do m
        newobjf = MOI.ScalarAffineFunction([term(-2.0, mapfrommodel(m, y))], 0.0)
        F = typeof(newobjf)
        MOI.set!(m, MOI.ObjectiveFunction{F}(), newobjf)
    end

    # add a constant to the objective
    objval_before = MOI.get(optimizer, MOI.ObjectiveValue())
    objconstant = 1.5
    test_optimizer_modification(model, optimizer, idxmap, defaultoptimizer(), config) do m
        attr = MOI.ObjectiveFunction{Affine}()
        MOI.modify!(m, attr, MOI.ScalarConstantChange(objconstant))
    end
    objval_after = MOI.get(optimizer, MOI.ObjectiveValue())
    @test objval_after ≈ objval_before + objconstant atol = 1e-8

    # change objective to min -y using ScalarCoefficientChange
    test_optimizer_modification(model, optimizer, idxmap, defaultoptimizer(), config) do m
        attr = MOI.ObjectiveFunction{Affine}()
        MOI.modify!(m, attr, MOI.ScalarCoefficientChange(mapfrommodel(m, y), -1.0))
    end
    @test MOI.get(optimizer, MOI.ObjectiveValue()) ≈ 0.5 * objval_before + objconstant atol = 1e-8

    # change x + y <= 1 to x + 2 y + 0.5 <= 1
    test_optimizer_modification(model, optimizer, idxmap, defaultoptimizer(), config) do m
        attr = MOI.ConstraintFunction()
        ci =  mapfrommodel(m, c)
        MOI.set!(m, attr, ci, MOI.ScalarAffineFunction(term.([1.0, 1.0, 1.0], mapfrommodel.(Ref(m), [x, x, y])), 0.5))
    end

    # change back to x + y <= 1 using ScalarCoefficientChange
    test_optimizer_modification(model, optimizer, idxmap, defaultoptimizer(), config) do m
        ci = mapfrommodel(m, c)
        MOI.modify!(m, ci, MOI.ScalarCoefficientChange(mapfrommodel(m, y), 1.0))
    end

    # flip the feasible set around from what it was originally and minimize +x
    test_optimizer_modification(model, optimizer, idxmap, defaultoptimizer(), config) do m
        # objective
        newobjf = MOI.SingleVariable(mapfrommodel(m, x))
        F = typeof(newobjf)
        MOI.set!(m, MOI.ObjectiveFunction{F}(), newobjf)

        # c
        attr = MOI.ConstraintFunction()
        ci = mapfrommodel(m, c)
        MOI.set!(m, attr, ci, MOI.ScalarAffineFunction(term.([1.0, 1.0], mapfrommodel.(Ref(m), [x, y])), 0.0))

        attr = MOI.ConstraintSet()
        MOI.set!(m, attr, ci, MOI.Interval(-1.0, Inf))

        # vc1
        attr = MOI.ConstraintSet()
        ci = mapfrommodel(m, vc1)
        MOI.set!(m, attr, ci, MOI.Interval(-Inf, 0.))

        # vc2
        attr = MOI.ConstraintSet()
        ci = mapfrommodel(m, vc2)
        MOI.set!(m, attr, ci, MOI.Interval(-Inf, 0.))
    end

    testflipped = function ()
        @test MOI.get(optimizer, MOI.TerminationStatus()) == MOI.Success
        @test MOI.get(optimizer, MOI.PrimalStatus()) == MOI.FeasiblePoint
        @test MOI.get(optimizer, MOI.ObjectiveValue()) ≈ -1 atol=atol rtol=rtol
        @test MOI.get(optimizer, MOI.VariablePrimal(), getindex.(Ref(idxmap), v)) ≈ [-1, 0] atol=atol rtol=rtol
        @test MOI.get(optimizer, MOI.DualStatus()) == MOI.FeasiblePoint
        @test MOI.get(optimizer, MOI.ConstraintDual(), idxmap[c]) ≈ 1 atol=atol rtol=rtol
        @test MOI.get(optimizer, MOI.ConstraintDual(), idxmap[vc1]) ≈ 0 atol=atol rtol=rtol
        @test MOI.get(optimizer, MOI.ConstraintDual(), idxmap[vc2]) ≈ -1 atol=atol rtol=rtol
    end
    testflipped()

    # update settings
    @test optimizer.results.info.status_polish == 0
    MOI.set!(optimizer, OSQPSettings.Polish(), true)
    MOI.optimize!(optimizer)
    @test optimizer.results.info.status_polish == 1
    testflipped()
end

@testset "No CachingOptimizer: Vector problem modification after copy!" begin
    # from basic.jl:
    model = OSQPModel{Float64}()
    x = MOI.addvariables!(model, 2)
    P11 = 11.
    q = [3., 4.]
    u = [0., 0., -15, 100, 80]
    A = sparse(Float64[-1 0; 0 -1; -1 -3; 2 5; 3 4])
    I, J, coeffs = findnz(A)
    objf = MOI.ScalarQuadraticFunction(term.(q, x), [term(2 * P11, x[1], x[1])], 0.0)
    MOI.set!(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), objf)
    MOI.set!(model, MOI.ObjectiveSense(), MOI.MinSense)
    cf = MOI.VectorAffineFunction(MOI.VectorAffineTerm.(Int64.(I), term.(coeffs, map(j -> getindex(x, j), J))), -u)
    c = MOI.addconstraint!(model, cf, MOI.Nonpositives(length(u)))

    optimizer = defaultoptimizer()
    idxmap = MOI.copy!(optimizer, model)
    @test MOI.canget(optimizer, MOI.ObjectiveSense())
    @test MOI.get(optimizer, MOI.ObjectiveSense()) == MOI.MinSense
    @test MOI.get(optimizer, MOI.NumberOfVariables()) == 2
    @test MOI.get(optimizer, MOI.ListOfVariableIndices()) == [MOI.VariableIndex(1), MOI.VariableIndex(2)]
    @test MOI.isvalid(optimizer, MOI.VariableIndex(2))
    @test !MOI.isvalid(optimizer, MOI.VariableIndex(3))

    MOI.optimize!(optimizer)

    # check result before modification
    atol = config.atol
    rtol = config.rtol
    @test MOI.get(optimizer, MOI.TerminationStatus()) == MOI.Success
    @test MOI.get(optimizer, MOI.PrimalStatus()) == MOI.FeasiblePoint
    @test MOI.get(optimizer, MOI.ObjectiveValue()) ≈ 20. atol=atol rtol=rtol
    @test MOI.get(optimizer, MOI.VariablePrimal(), getindex.(Ref(idxmap), x)) ≈ [0.; 5.] atol=atol rtol=rtol
    @test MOI.get(optimizer, MOI.DualStatus()) == MOI.FeasiblePoint
    @test MOI.get(optimizer, MOI.ConstraintDual(), idxmap[c]) ≈ -[1.666666666666; 0.; 1.3333333; 0.; 0.] atol=atol rtol=rtol

    # test allocations
    allocs = @allocated MOI.optimize!(optimizer)
    @test allocs == 0

    mapfrommodel(::MOI.AbstractOptimizer, x::Union{MOI.VariableIndex, <:MOI.ConstraintIndex}) = idxmap[x]
    mapfrommodel(::MOI.ModelLike, x::Union{MOI.VariableIndex, <:MOI.ConstraintIndex}) = x

    # make random modifications to constraints
    randvectorconfig = MOIT.TestConfig(atol=Inf, rtol=1e-4)
    rng = MersenneTwister(1234)
    for i = 1 : 100
        newcoeffs = copy(coeffs)
        modindex = rand(rng, 1 : length(newcoeffs))
        newcoeffs[modindex] = 0
        newconst = 5 .* (rand(rng, length(u)) .- 0.5)
        test_optimizer_modification(model, optimizer, idxmap, defaultoptimizer(), randvectorconfig) do m
            attr = MOI.ConstraintFunction()
            ci = mapfrommodel(m, c)
            newcf = MOI.VectorAffineFunction(MOI.VectorAffineTerm.(Int64.(I), term.(newcoeffs, map(j -> getindex(x, j), J))), newconst)
            MOI.set!(m, attr, ci, newcf)
        end
    end
end

@testset "Vector equality constraint" begin
    # Minimize ||A x - b||^2 = x' A' A x - (2 * A' * b)' x + b' * b
    # subject to C x = d

    generate_problem_data = function (rng, n, m)
        A = rand(rng, n, n)
        b = rand(rng, n)
        C = rand(rng, m, n)
        d = rand(rng, m)
        C⁺ = pinv(C)
        Q = I - C⁺ * C
        expected = Q * (pinv(A * Q) * (b - A * C⁺ * d)) + C⁺ * d # note: can be quite badly conditioned
        @test C * expected ≈ d atol = 1e-12

        P = Symmetric(sparse(triu(A' * A)))
        q = -2 * A' * b
        r = b' * b

        A, b, C, d, P, q, r, expected
    end

    make_objective = function (P, q, r, x)
        I, J, coeffs = findnz(P.data)
        MOI.ScalarQuadraticFunction(term.(q, x), term.(2 * coeffs, map(i -> x[i]::MOI.VariableIndex, I), map(j -> x[j]::MOI.VariableIndex, J)), r)
    end

    make_constraint_fun = function (C, d, x)
        I, J, coeffs = findnz(sparse(C))
        cf = MOI.VectorAffineFunction(MOI.VectorAffineTerm.(Int64.(I), term.(coeffs, map(j -> getindex(x, j)::MOI.VariableIndex, J))), -d)
    end

    check_results = function (optimizer, idxmap, x, A, b, expected)
        @test MOI.get(optimizer, MOI.TerminationStatus()) == MOI.Success
        @test MOI.get(optimizer, MOI.PrimalStatus()) == MOI.FeasiblePoint
        @test MOI.get.(Ref(optimizer), Ref(MOI.VariablePrimal()), getindex.(Ref(idxmap), x)) ≈ expected atol = 1e-4
        @test MOI.get(optimizer, MOI.ObjectiveValue()) ≈ norm(A * expected - b)^2 atol = 1e-4
    end

    n = 8
    m = 2
    rng = MersenneTwister(1234)

    A, b, C, d, P, q, r, expected = generate_problem_data(rng, n, m)
    model = OSQPModel{Float64}()
    x = MOI.addvariables!(model, n)
    MOI.set!(model, MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}}(), make_objective(P, q, r, x))
    MOI.set!(model, MOI.ObjectiveSense(), MOI.MinSense)
    c = MOI.addconstraint!(model, make_constraint_fun(C, d, x), MOI.Zeros(length(d)))

    optimizer = defaultoptimizer()
    idxmap = MOI.copy!(optimizer, model)
    MOI.optimize!(optimizer)
    check_results(optimizer, idxmap, x, A, b, expected)

    x = [idxmap[xi] for xi in x]
    for i = 1 : 10
        A, b, C, d, P, q, r, expected = generate_problem_data(rng, n, m)
        MOI.set!(optimizer, MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}}(), make_objective(P, q, r, x))
        attr = MOI.ConstraintFunction()
        MOI.set!(optimizer, attr, idxmap[c], make_constraint_fun(C, d, x))
        attr = MOI.ConstraintSet()
        MOI.set!(optimizer, attr, idxmap[c], MOI.Zeros(length(d))) # noop, but ok
        MOI.optimize!(optimizer)
        check_results(optimizer, idxmap, x, A, b, expected)
    end
end

@testset "RawSolver" begin
    optimizer = defaultoptimizer()
    @test MOI.canget(optimizer, MOI.RawSolver())
    let inner = MOI.get(optimizer, MOI.RawSolver())
        @test inner.workspace == C_NULL
    end

    model = OSQPModel{Float64}()
    MOI.empty!(model)
    x = MOI.addvariable!(model)
    c = MOI.addconstraint!(model, x, MOI.GreaterThan(2.0))
    MOI.set!(model, MOI.ObjectiveSense(), MOI.MinSense)
    MOI.set!(model, MOI.ObjectiveFunction{MOI.SingleVariable}(), MOI.SingleVariable(x))

    MOI.copy!(optimizer, model)
    inner = MOI.get(optimizer, MOI.RawSolver())
    @test inner.workspace != C_NULL
end

# TODO: consider moving to MOIT. However, current defaultcopy! is fine with BadObjectiveModel.
struct BadObjectiveModel <: MOIT.BadModel end # objective sense is not FeasibilitySense, but can't get objective function
MOI.canget(src::BadObjectiveModel, ::MOI.ObjectiveSense) = true
MOI.get(src::BadObjectiveModel, ::MOI.ObjectiveSense) = MOI.MinSense
MOI.canget(src::BadObjectiveModel, ::MOI.ObjectiveFunction{<:Any}) = false

@testset "failcopy" begin
    optimizer = OSQPOptimizer()
    MOIT.failcopytestc(optimizer)
    @test_throws MathOptInterfaceOSQP.UnsupportedObjectiveError MOI.copy!(optimizer, BadObjectiveModel())
end


text:
@testset "> Gruber" begin
    @testset ">>Is integer matrices (no units)" begin
        cell = [0 0.5 0.5; 0.5 0 0.5; 0.5 0.5 0]
        const lim = 5

        for a00=-1:1, a10 =-lim:lim + 1, a11=-1:1, a20=-lim:lim + 1, a21=-lim:lim + 1, a22=-1:1
            a = [a00 0 0; a10 a11 0; a20 a21 a22]
            abs(det(a)) > 0 || continue
            g = gruber(cell * a)
            @test abs(det(cell)) > 1e-12
            @test volume(cell * a) ≈ volume(g)
            @test all(isinteger, inv(cell) * g)
            @test all(isinteger, round.(inv(g) * cell, 8))
        end
    end

    @testset ">>Is integer matrices (with units)" begin
        cell = [0 0.5 0.5; 0.5 0 0.5; 0.5 0.5 0]u"nm"
        const lim = 5

        for a00=-1:1, a10 =-lim:lim + 1, a11=-1:1, a20=-lim:lim + 1, a21=-lim:lim + 1, a22=-1:1
            a = [a00 0 0; a10 a11 0; a20 a21 a22]
            abs(det(a)) > 0 || continue
            g = gruber(cell * a)
            @test abs(det(ustrip.(cell))) > 1e-12
            @test volume(cell * a) ≈ volume(g)
            @test all(isinteger, inv(cell) * g)
            @test all(isinteger, round.(inv(g) * cell, 8))
            break
        end
    end

    @testset ">> Regressions" begin
          cells = Any[
            [0.10658442  0.85196214  0.11820731;
              0.08762888  0.06597675  0.33166737;
              0.90830071  0.79275198  0.28060048],
            [0.315935703201265183 -0.491002658691486404 -0.450428983281787709;
              0.143383123347384012 -0.208941528033948387  0.315007354520186578;
              0.4831297491880433   -0.127532144165201089  0.433845061278055],
            -[0.5  -0.5   1.0; 0.0  -0.5  -0.5; -0.5   0.0  -0.5]
          ]
          expecteds = Any[
              [0.118207309999999996 0.01162288999999999684 -0.74537772000000002137;
              0.33166737000000001689 0.2440384899999999968 0.02165213000000000554;
              0.28060047999999998547 -0.62770023000000008118 0.11554872999999998839],
              [0.175066955490221221  0.275362027791566488 0.491002658691486404;
              0.065558404686564375 -0.380565759206750953 0.208941528033948387;
              -0.355597605022842211 -0.078247456255212788 0.127532144165201089],
              [-0.5 -0.5  0;  0 -0.5 -0.5; 0.5 0  0.5]
          ]
          for (cell, expected) in zip(cells, expecteds)
            actual = gruber(cell)
            @test actual ≈ expected
          end
    end

    @testset ">> Error if singular" begin
        @test_throws ArgumentError gruber([1 0 0; 0 1 0; 0 2 0])
    end

    @testset ">> Error if max iter" begin
        @test_throws ErrorException gruber([1 0 0; 1 1  0; 4 5 1]; itermax=2)
    end
end

ext: jl


text:
"""
	get_SB_ratio( sig, b1 )
Description of ```get_SB_ratio```
------------------------------
Returns signal-to-background ratio defined as: ```r = A₁ε₁ / A₂ε₂ ```

See also get_SB_ratio( sig, b1, b2 ).
"""
function get_SB_ratio( sig, b1 )
	num = sig[1]*sig[2]
	den1= b1[1]*b1[2]

	r = den1 != 0 ?  num/(den1) : 0
	return r
end

"""
	get_SB_ratio( sig, b1, b2 )
Description of ```get_SB_ratio```
------------------------------
Returns signal-to-background ratio defined as: ```r = A₁ε₁ / (A₂ε₂ + A₃ε₃ ) ```

See also get_SB_ratio( sig, b1).
"""
function get_SB_ratio( sig, b1, b2 )
	num = sig[1]*sig[2]
	den1= b1[1]*b1[2]
	den2= b2[1]*b2[2]

	r = (den1 + den2) != 0 ? num/(den1+den2) : 0
	return r
end


text:
using FunctionOperators, MacroTools, LinearAlgebra, Test, BenchmarkTools

d = rand(10, 3, 2)im
Ω = FunctionOperator{Complex{Float64}}(x -> x, x -> x, (10, 3, 2), (10, 3, 2))
Q = FunctionOperator{Complex{Float64}}(x -> x, x -> x, (10, 3, 2), (10, 3, 2))
C = FunctionOperator{Complex{Float64}}(x -> repeat(x, outer=(1,1,2)), x -> x[:,:,1], (10, 3), (10, 3, 2))
T = FunctionOperator{Complex{Float64}}(x -> x, x -> x, (10, 3), (10, 3))

samp = rand(10, 3);
E = Ω * Q * C
normₙ(A) = sum(svdvals(A))
norm₁(A) = norm(A, 1)
norm₂(A) = norm(A, 2)

pos(x) = x < 0 ? zero(x) : x
Λ!(v,p) = @. v = sign(v) * pos(abs(v) - p)

SVT(A,p) = begin
    F = svd(A)
    F.U*Diagonal(Λ!(F.S,p))*F.Vt
end

function getCostFunc(E::FunOp, T::FunOp, d::Array{Complex{Float64},3})
    (L,S,d,λ_L,λ_S) -> 0.5*norm₂(E*(L + S) - d)^2 + λ_L*normₙ(L) + λ_S*norm₁(T * S)
end
cost = getCostFunc(E, T, d)

function AL_2(d::Array{Complex{Float64}, 3},  # measurement data
        Ω::FunOp,                             # sampling operator
        Q::FunOp,                             # Fourier operator
        C::FunOp,                             # coil sensitivity operator
        T::FunOp;                             # sparsifying operator
        scale_L::Float64 = 1.,
        scale_S::Float64 = 1.,
        λ_L::Float64 = 0.01,
        λ_S::Float64 = 0.05,
        δ₁::Complex{Float64} = 1im / 10.,
        δ₂::Float64 = 1. / 100,
        iterL::Int64 = 3,
        iterS::Int64 = iterL,
        N::Int64 = 10)

    #Initialize
    E = Ω * Q * C
    x₀ = E' * d
    L = copy(x₀)
    S = zeros(Complex{Float64}, size(L))
    X = L + S
    V₁ = zeros(Complex{Float64}, size(d))
    V₂ = zeros(Complex{Float64}, size(L))
    Z_scaler = 1 ./ (reshape(samp, size(samp)..., 1) .+ δ₁)

    cost_vec = Vector{Float64}(undef, N+1)
    cost_vec[1] = cost(L, S, d, scale_L*λ_L, scale_S*λ_S)

    for k in 1:N
        Z = Z_scaler .* (Ω' * d + δ₁*(Q * C * X - V₁))
        X = δ₁/(δ₁+δ₂) * C' * Q' * (Z + V₁) + δ₂/(δ₁+δ₂) * (L + S - V₂)
        L = SVT(X - S + V₂, scale_L * λ_L / δ₂)
        S = T' * Λ!(T * (X - L + V₂), scale_S * λ_S / δ₂)
        if k == 3
            V₁ += Z - Q * C * X
            V₂ += X - L - S
        end

        cost_vec[k+1] = cost(L, S, d, scale_L*λ_L, scale_S*λ_S)
    end

    L + S, cost_vec
end

function getCostFunc_recycle(E::FunOp, T::FunOp, d::Array{Complex{Float64},3})
    @recycle(arrays=[L,S,d], funops=[E,t], numbers=[λ_L,λ_S],
        (L,S,d,λ_L,λ_S) -> 0.5*norm₂(E*(L + S) - d)^2 + λ_L*normₙ(L) + λ_S*norm₁(T * S))
end
const cost_recycle = getCostFunc_recycle(E, T, d)

function AL_2_recycle(d::Array{Complex{Float64}, 3},  # measurement data
        Ω::FunOp,                             # sampling operator
        Q::FunOp,                             # Fourier operator
        C::FunOp,                             # coil sensitivity operator
        T::FunOp;                             # sparsifying operator
        scale_L::Float64 = 1.,
        scale_S::Float64 = 1.,
        λ_L::Float64 = 0.01,
        λ_S::Float64 = 0.05,
        δ₁::Complex{Float64} = 1im / 10.,
        δ₂::Float64 = 1. / 100,
        iterL::Int64 = 3,
        iterS::Int64 = iterL,
        N::Int64 = 10)

    #Initialize
    E = Ω * Q * C
    x₀ = E' * d
    L = copy(x₀)
    S = zeros(Complex{Float64}, size(L))
    X = L + S
    V₁ = zeros(Complex{Float64}, size(d))
    V₂ = zeros(Complex{Float64}, size(L))
    Z_scaler = 1 ./ (reshape(samp, size(samp)..., 1) .+ δ₁)

    cost_vec = Vector{Float64}(undef, N+1)
    cost_vec[1] = cost_recycle(L, S, d, scale_L*λ_L, scale_S*λ_S)

    @recycle for k in 1:N
        Z = Z_scaler .* (Ω' * d + δ₁*(Q * C * X - V₁))
        X = δ₁/(δ₁+δ₂) * C' * Q' * (Z + V₁) + δ₂/(δ₁+δ₂) * (L + S - V₂)
        L = SVT(X - S + V₂, scale_L * λ_L / δ₂)
        S = T' * Λ!(T * (X - L + V₂), scale_S * λ_S / δ₂)
        if k == 3
            V₁ += Z - Q * C * X
            V₂ += X - L - S
        end

        cost_vec[k+1] = cost_recycle(L, S, d, scale_L*λ_L, scale_S*λ_S)
    end

    L + S, cost_vec
end

function getBufferedOps()
    Op₁ = FunctionOperator{Float64}(name="Op₁",
        forw = (buffer, x) -> buffer .= x.^2,
        backw = (buffer, x) -> broadcast!(sqrt, buffer, x),
        inDims = (300, 300), outDims = (300, 300))
    weights = [sin((i-j)*k) + 1 for i=1:300, j=1:300, k=1:10]
    Op₂ = FunctionOperator{Float64}(name="Op₂",
        forw = (buffer,x) -> buffer .= reshape(x, 300, 300, 1) .* weights,
        backw = (buffer,x) -> dropdims(sum!(reshape(buffer, 300, 300, 1), x ./ weights), dims=3),
        inDims=(300, 300), outDims=(300, 300, 10))
    Op₁, Op₂
end
bOp₁, bOp₂ = getBufferedOps()
data = [sin(i+j)^2 for i=1:300, j=1:300]

function foo1(A, bOp₁, bOp₂)
    B = similar(A)
    for i in 1:10
        @timed C = (bOp₁ - 2*2.5*I) * bOp₁ * A * A
        B = bOp₁ * (C - 3A + 2I)
        B += A * B * C
        @timed A .= bOp₁ * (100C + B * 200I)
        A ./= maximum(bOp₂ * +A)
    end
end

function foo4(A, bOp₁, bOp₂)
    B = similar(A)
    @recycle for i in 1:10
        @timed C = (bOp₁ - 2*2.5*I) * bOp₁ * A * A
        B = bOp₁ * (C - 3A + 2I)
        B += A * B * C
        @timed A .= bOp₁ * (100C + B * 200I)
        A ./= maximum(bOp₂ * +A)
    end
end

function getCost(Op)
    (A,scaler) -> norm(Op' * (A / scaler), 1) + norm(A, 2)
end

function getCost_recycle(Op)
    @recycle(arrays=[A], funops=[Op], numbers=[scaler],
        (A,scaler) -> norm(Op' * (A / scaler), 1) + norm(A, 2))
end

@testset "recycle" begin
    cost = getCost(bOp₁)
    cost2 = getCost_recycle(bOp₁)
    @test foo1(copy(data), bOp₁, bOp₂) == foo4(copy(data), bOp₁, bOp₂)
    @test cost(data, 2) == cost2(data, 2)
    res, cost = AL_2(d, Ω, Q, C, T)
    res_recycle, cost_recycle = AL_2_recycle(d, Ω, Q, C, T)
    @test res == res_recycle
    @test cost == cost_recycle
    @test @belapsed(AL_2(d, Ω, Q, C, T)) / @belapsed(AL_2_recycle(d, Ω, Q, C, T)) > 2.
end


text:
module FixedEffectModels

# slows down tss
#if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@optlevel"))
#	@eval Base.Experimental.@optlevel 1
#end

using DataFrames
using FixedEffects
using LinearAlgebra
using Printf
using Reexport
using Statistics
using StatsBase
using StatsFuns
@reexport using StatsModels
using Tables
using Vcov

include("utils/fixedeffects.jl")
include("utils/basecol.jl")
include("utils/tss.jl")
include("utils/formula.jl")
include("FixedEffectModel.jl")
include("fit.jl")
include("partial_out.jl")

# Export from StatsBase
export coef, coefnames, coeftable, responsename, vcov, stderror, nobs, dof_residual, r2, adjr2, islinear, deviance, rss, mss, confint, predict, residuals

export reg,
partial_out,
fe,
FixedEffectModel,
has_iv,
has_fe,
Vcov

end


text:
module NormalWeightedMeanPrecisionTest

using Test
using ReactiveMP

@testset "NormalWeightedMeanPrecision" begin

    @testset "Constructor" begin
        @test NormalWeightedMeanPrecision <: NormalDistributionsFamily
        @test NormalWeightedMeanPrecision <: UnivariateNormalDistributionsFamily

        @test NormalWeightedMeanPrecision()         == NormalWeightedMeanPrecision{Float64}(0.0, 1.0)
        @test NormalWeightedMeanPrecision(1.0)      == NormalWeightedMeanPrecision{Float64}(1.0, 1.0)
        @test NormalWeightedMeanPrecision(1.0, 2.0) == NormalWeightedMeanPrecision{Float64}(1.0, 2.0)
        @test NormalWeightedMeanPrecision(1)        == NormalWeightedMeanPrecision{Float64}(1.0, 1.0)
        @test NormalWeightedMeanPrecision(1, 2)     == NormalWeightedMeanPrecision{Float64}(1.0, 2.0)
        @test NormalWeightedMeanPrecision(1.0, 2)   == NormalWeightedMeanPrecision{Float64}(1.0, 2.0)
        @test NormalWeightedMeanPrecision(1, 2.0)   == NormalWeightedMeanPrecision{Float64}(1.0, 2.0)
        @test NormalWeightedMeanPrecision(1f0)      == NormalWeightedMeanPrecision{Float32}(1f0, 1f0)
        @test NormalWeightedMeanPrecision(1f0, 2f0) == NormalWeightedMeanPrecision{Float32}(1f0, 2f0)
        @test NormalWeightedMeanPrecision(1f0, 2.0) == NormalWeightedMeanPrecision{Float64}(1.0, 2.0)

        @test eltype(NormalWeightedMeanPrecision())         === Float64
        @test eltype(NormalWeightedMeanPrecision(0.0))      === Float64
        @test eltype(NormalWeightedMeanPrecision(0.0, 1.0)) === Float64
        @test eltype(NormalWeightedMeanPrecision(0))        === Float64
        @test eltype(NormalWeightedMeanPrecision(0, 1))     === Float64
        @test eltype(NormalWeightedMeanPrecision(0.0, 1))   === Float64
        @test eltype(NormalWeightedMeanPrecision(0, 1.0))   === Float64
        @test eltype(NormalWeightedMeanPrecision(0f0))      === Float32
        @test eltype(NormalWeightedMeanPrecision(0f0, 1f0)) === Float32
        @test eltype(NormalWeightedMeanPrecision(0f0, 1.0)) === Float64
    end

    @testset "Stats methods" begin

        dist1 = NormalWeightedMeanPrecision(0.0, 1.0)

        @test mean(dist1)         === 0.0
        @test median(dist1)       === 0.0
        @test mode(dist1)         === 0.0
        @test weightedmean(dist1) === 0.0
        @test var(dist1)          === 1.0
        @test std(dist1)          === 1.0
        @test cov(dist1)          === 1.0
        @test invcov(dist1)       === 1.0
        @test precision(dist1)    === 1.0
        @test entropy(dist1)      ≈ 1.41893853320467
        @test pdf(dist1, 1.0)     ≈ 0.24197072451914337
        @test pdf(dist1, -1.0)    ≈ 0.24197072451914337
        @test pdf(dist1, 0.0)     ≈ 0.3989422804014327
        @test logpdf(dist1, 1.0)  ≈ -1.4189385332046727
        @test logpdf(dist1, -1.0) ≈ -1.4189385332046727
        @test logpdf(dist1, 0.0)  ≈ -0.9189385332046728

        dist2 = NormalWeightedMeanPrecision(1.0, 1.0)

        @test mean(dist2)         === 1.0
        @test median(dist2)       === 1.0
        @test mode(dist2)         === 1.0
        @test weightedmean(dist2) === 1.0
        @test var(dist2)          === 1.0
        @test std(dist2)          === 1.0
        @test cov(dist2)          === 1.0
        @test invcov(dist2)       === 1.0
        @test precision(dist2)    === 1.0
        @test entropy(dist2)      ≈ 1.41893853320467
        @test pdf(dist2, 1.0)     ≈ 0.3989422804014327
        @test pdf(dist2, -1.0)    ≈ 0.05399096651318806
        @test pdf(dist2, 0.0)     ≈ 0.24197072451914337
        @test logpdf(dist2, 1.0)  ≈ -0.9189385332046728
        @test logpdf(dist2, -1.0) ≈ -2.9189385332046727
        @test logpdf(dist2, 0.0)  ≈ -1.4189385332046727

        dist3 = NormalWeightedMeanPrecision(1.0, 0.5)

        @test mean(dist3)         === inv(0.5)
        @test median(dist3)       === inv(0.5)
        @test mode(dist3)         === inv(0.5)
        @test weightedmean(dist3) === 1.0
        @test var(dist3)          === 2.0
        @test std(dist3)          === sqrt(2.0)
        @test cov(dist3)          === 2.0
        @test invcov(dist3)       === inv(2.0)
        @test precision(dist3)    === inv(2.0)
        @test entropy(dist3)      ≈ 1.7655121234846454
        @test pdf(dist3, 1.0)     ≈ 0.21969564473386122
        @test pdf(dist3, -1.0)    ≈ 0.02973257230590734
        @test pdf(dist3, 0.0)     ≈ 0.1037768743551487
        @test logpdf(dist3, 1.0)  ≈ -1.5155121234846454
        @test logpdf(dist3, -1.0) ≈ -3.5155121234846454
        @test logpdf(dist3, 0.0)  ≈ -2.2655121234846454

    end

    @testset "Base methods" begin
        @test convert(NormalWeightedMeanPrecision{Float32}, NormalWeightedMeanPrecision()) == NormalWeightedMeanPrecision{Float32}(0f0, 1f0)
        @test convert(NormalWeightedMeanPrecision{Float64}, NormalWeightedMeanPrecision(0.0, 10.0)) == NormalWeightedMeanPrecision{Float64}(0.0, 10.0)
        @test convert(NormalWeightedMeanPrecision{Float64}, NormalWeightedMeanPrecision(0.0, 0.1)) == NormalWeightedMeanPrecision{Float64}(0.0, 0.1)
        @test convert(NormalWeightedMeanPrecision{Float64}, 0, 1) == NormalWeightedMeanPrecision{Float64}(0.0, 1.0)
        @test convert(NormalWeightedMeanPrecision{Float64}, 0, 10) == NormalWeightedMeanPrecision{Float64}(0.0, 10.0)
        @test convert(NormalWeightedMeanPrecision{Float64}, 0, 0.1) == NormalWeightedMeanPrecision{Float64}(0.0, 0.1)
        @test convert(NormalWeightedMeanPrecision, 0, 1) == NormalWeightedMeanPrecision{Float64}(0.0, 1.0)
        @test convert(NormalWeightedMeanPrecision, 0, 10) == NormalWeightedMeanPrecision{Float64}(0.0, 10.0)
        @test convert(NormalWeightedMeanPrecision, 0, 0.1) == NormalWeightedMeanPrecision{Float64}(0.0, 0.1)
    end

    @testset "vague" begin
        d1 = vague(NormalWeightedMeanPrecision)

        @test typeof(d1) <: NormalWeightedMeanPrecision
        @test mean(d1)      == 0.0
        @test precision(d1) == ReactiveMP.tiny
    end

    @testset "prod" begin

        @test prod(ProdAnalytical(), NormalWeightedMeanPrecision(-1, 1/1), NormalWeightedMeanPrecision(1, 1/1)) ≈ NormalWeightedMeanPrecision(0, 2)
        @test prod(ProdAnalytical(), NormalWeightedMeanPrecision(-1, 1/2), NormalWeightedMeanPrecision(1, 1/4)) ≈ NormalWeightedMeanPrecision(0, 3/4)
        @test prod(ProdAnalytical(), NormalWeightedMeanPrecision(2, 1/2), NormalWeightedMeanPrecision(0, 1/10)) ≈ NormalWeightedMeanPrecision(2, 3/5)

    end

end

end


text:
function TensorBoardLogger.preprocess(name, val::SampledObservables, data)
    for (key,val)=zip(val.ObsNames, val.ObsAve)
        TensorBoardLogger.preprocess(name*"/"*string(key), real(val), data)
    end
    data
end

#=function ValueHistoriesLogger.preprocess(name, val::SampledObservables, data)
    for (key,val)=zip(val.ObsNames, val.ObsAve)
        ValueHistoriesLogger.preprocess(name*"/"*string(key), real(val), data)
    end
    data
end=#

function TensorBoardLogger.preprocess(name, val::SREvaluation, data)
    TensorBoardLogger.preprocess(name*"/Loss", val.L, data)
    data
end

#=function ValueHistoriesLogger.preprocess(name, val::SREvaluation, data)
    ValueHistoriesLogger.preprocess(name*"/Loss", val.L, data)
    ValueHistoriesLogger.preprocess(name*"/Loss_Convergence", val.LVals, data)
    data
end=#

function TensorBoardLogger.preprocess(name, val::NeuralNetwork, data)
    data
end

#=function ValueHistoriesLogger.preprocess(name, val::NeuralNetwork, data)
    push!(data, name=>val)
    data
end=#


text:
# MIT license
# Copyright (c) Microsoft Corporation. All rights reserved.
# See LICENSE in the project root for full license information.

module AGFFileReader

using Polynomials
using Plots
using StringEncodings
using Unitful
using StaticArrays
using Base: @.
import Unitful: Length, Temperature, Quantity, Units
using Unitful.DefaultSymbols
using Pkg
using Pkg.Artifacts
using ForwardDiff

include("constants.jl")

#maybe can solve the literal/Intellisense problem by creating a file in the Artifacts directory which contains literals with the pathnames to the various glass files. Then include the created file here. Might work. Probably won't.

#Look up the location of the artifacts directory and load GlassTypes.jl
agf_hash = artifact_hash("AGF", artifact_toml)
catalog_path = artifact_path(agf_hash)
include(joinpath(catalog_path,"GlassTypes.jl"))
include(joinpath(catalog_path,"AGFGlassCat.jl")) # this needs to be literal for intellisense to work so you won't get Intellisense. Which is the whole point of having these jl files. If this doesn't work then might as well use file parsing.
include(jointpath(catalog_path,"OTHER.jl"))

export GlassID, info, glassid, glassname, glassforid
include("Air.jl")
export Air, isair

#TODO need to modify to use Artifacts.toml instead of constants
# # include built glass cat source files
# @assert AGFGLASSCAT_PATH === joinpath(@__DIR__, "data", "jl", "AGFGlassCat.jl")
# if !isfile(AGFGLASSCAT_PATH)
#     @warn "$(basename(AGFGLASSCAT_PATH)) not found! Running build steps."
#     Pkg.build("AGFFileReader"; verbose=true)
# end
# include("data/jl/AGFGlassCat.jl") # this needs to be literal for intellisense to work
# include("data/jl/OTHER.jl")

# include functionality for managing runtime (dynamic) glass cats: MIL_GLASSES and MODEL_GLASSES
include("runtime.jl")
export glassfromMIL, modelglass

# include functions for searching the glass cats
include("search.jl")
export glasscatalogs, glassnames, findglass

include("utilities.jl")
export plot_indices, index, polyfit_indices, absairindex, absorption, drawglassmap

# include utility functions for maintaining the AGF source list
#TODO figure out how to export this even though add_agf is defined in the artifacts directory.
# include("sources.jl")
# export add_agf

# include build utility scripts to make testing them a bit easier
include("generate.jl")

end # module
export AGFFileReader

max_stars_repo_name: rambunctiousapple/GlassCat

max_issues_repo_name: rambunctiousapple/GlassCat

max_forks_repo_name: rambunctiousapple/GlassCat


text:
struct Instruction
    mod::Symbol
    instr::Symbol
end
Instruction(instr::Symbol) = Instruction(:LoopVectorization, instr)
Base.convert(::Type{Instruction}, instr::Symbol) = Instruction(instr)
lower(instr::Instruction) = Expr(:(.), instr.mod, QuoteNode(instr.instr))
Base.Expr(instr::Instruction, args...) = Expr(:call, lower(instr), args...)::Expr
Base.hash(instr::Instruction, h::UInt64) = hash(instr.instr, hash(instr.mod, h))

const LOOPCONSTANT = Instruction(gensym())

struct InstructionCost
    scaling::Float64 # sentinel values: -3 == no scaling; -2 == offset_scaling, -1 == linear scaling, >0 ->  == latency == reciprical throughput
    scalar_reciprical_throughput::Float64
    scalar_latency::Int
    register_pressure::Int
end
InstructionCost(sl::Int, srt::Float64, scaling::Float64 = -3.0) = InstructionCost(scaling, srt, sl, 0)

nocost(c::InstructionCost) = c.scalar_reciprical_throughput == 0.0
flatcost(c::InstructionCost) = c.scaling == -3.0
offsetscaling(c::InstructionCost) = c.scaling == -2.0
linearscaling(c::InstructionCost) = c.scaling == -1.0

function scalar_cost(ic::InstructionCost)#, ::Type{T} = Float64) where {T}
    @unpack scalar_reciprical_throughput, scalar_latency, register_pressure = ic
    scalar_reciprical_throughput, scalar_latency, register_pressure
end
function vector_cost(ic::InstructionCost, Wshift, sizeof_T)
    srt, sl, srp = scalar_cost(ic)
    if flatcost(ic) || Wshift == 0 || nocost(ic) # No scaling
        return srt, sl, srp
    elseif offsetscaling(ic) # offset scaling
        srt *= 1 << (Wshift + VectorizationBase.intlog2(sizeof_T) - 4)
        if (sizeof_T << Wshift) == 64 # VectorizationBase.REGISTER_SIZE # These instructions experience double latency with zmm
            sl += sl
        end
    elseif linearscaling(ic) # linear scaling
        W = 1 << Wshift
        extra_latency = sl - srt
        srt *= W
        sl = round(Int, srt + extra_latency)
    else # we assume custom cost, and that latency == recip_throughput
        scaling = ic.scaling
        sl, srt = round(Int,scaling), scaling
    end
    srt, sl, srp
end
instruction_cost(instruction::Instruction) = get(COST, instruction, OPAQUE_INSTRUCTION)
instruction_cost(instruction::Symbol) = instruction_cost(Instruction(instruction))
scalar_cost(instr::Instruction) = scalar_cost(instruction_cost(instr))
vector_cost(instr::Instruction, Wshift, sizeof_T) = vector_cost(instruction_cost(instr), Wshift, sizeof_T)
function cost(instruction::InstructionCost, Wshift, sizeof_T)
    Wshift == 0 ? scalar_cost(instruction) : vector_cost(instruction, Wshift, sizeof_T)
end

function cost(instruction::Instruction, Wshift, sizeof_T)
    cost(
        instruction_cost(instruction), Wshift, sizeof_T
    )
end

# Just a semi-reasonable assumption; should not be that sensitive to anything other than loads
const OPAQUE_INSTRUCTION = InstructionCost(50, 50.0, -1.0, VectorizationBase.REGISTER_COUNT)

# Comments on setindex!
# 1. Not a part of dependency chains, so not really twice as expensive as getindex?
# 2. getindex loads a register, not setindex!, but we place cost on setindex!
#    as a heuristic means of approximating register pressure, since many loads can be
#    consolidated into a single register. The number of LICM-ed setindex!, on the other
#    hand, should indicate how many registers we're keeping live for the sake of eventually storing.
const COST = Dict{Instruction,InstructionCost}(
    Instruction(:getindex) => InstructionCost(-3.0,0.5,3,1),
    Instruction(:setindex!) => InstructionCost(-3.0,1.0,3,0),
    Instruction(:zero) => InstructionCost(1,0.5),
    Instruction(:one) => InstructionCost(3,0.5),
    Instruction(:+) => InstructionCost(4,0.5),
    Instruction(:-) => InstructionCost(4,0.5),
    Instruction(:*) => InstructionCost(4,0.5),
    Instruction(:/) => InstructionCost(13,4.0,-2.0),
    Instruction(:vadd) => InstructionCost(4,0.5),
    Instruction(:vsub) => InstructionCost(4,0.5),
    Instruction(:vmul) => InstructionCost(4,0.5),
    Instruction(:vdiv) => InstructionCost(13,4.0,-2.0),
    Instruction(:abs2) => InstructionCost(4,0.5),
    Instruction(:vabs2) => InstructionCost(4,0.5),
    Instruction(:(==)) => InstructionCost(1, 0.5),
    Instruction(:isequal) => InstructionCost(1, 0.5),
    Instruction(:(&)) => InstructionCost(1, 0.5),
    Instruction(:(|)) => InstructionCost(1, 0.5),
    Instruction(:(>)) => InstructionCost(1, 0.5),
    Instruction(:(<)) => InstructionCost(1, 0.5),
    Instruction(:(>=)) => InstructionCost(1, 0.5),
    Instruction(:(<=)) => InstructionCost(1, 0.5),
    Instruction(:inv) => InstructionCost(13,4.0,-2.0,1),
    Instruction(:vinv) => InstructionCost(13,4.0,-2.0,1),
    Instruction(:muladd) => InstructionCost(4,0.5), # + and * will fuse into this, so much of the time they're not twice as expensive
    Instruction(:fma) => InstructionCost(4,0.5), # + and * will fuse into this, so much of the time they're not twice as expensive
    Instruction(:vmuladd) => InstructionCost(4,0.5), # + and * will fuse into this, so much of the time they're not twice as expensive
    Instruction(:vfma) => InstructionCost(4,0.5), # + and * will fuse into this, so much of the time they're not twice as expensive
    Instruction(:vfmadd) => InstructionCost(4,0.5), # + and * will fuse into this, so much of the time they're not twice as expensive
    Instruction(:vfmsub) => InstructionCost(4,0.5), # - and * will fuse into this, so much of the time they're not twice as expensive
    Instruction(:vfnmadd) => InstructionCost(4,0.5), # + and -* will fuse into this, so much of the time they're not twice as expensive
    Instruction(:vfnmsub) => InstructionCost(4,0.5), # - and -* will fuse into this, so much of the time they're not twice as expensive
    Instruction(:vfmadd_fast) => InstructionCost(4,0.5), # + and * will fuse into this, so much of the time they're not twice as expensive
    Instruction(:vfmsub_fast) => InstructionCost(4,0.5), # - and * will fuse into this, so much of the time they're not twice as expensive
    Instruction(:vfnmadd_fast) => InstructionCost(4,0.5), # + and -* will fuse into this, so much of the time they're not twice as expensive
    Instruction(:vfnmsub_fast) => InstructionCost(4,0.5), # - and -* will fuse into this, so much of the time they're not twice as expensive
    Instruction(:sqrt) => InstructionCost(15,4.0,-2.0),
    Instruction(:log) => InstructionCost(20,20.0,40.0,20),
    Instruction(:exp) => InstructionCost(20,20.0,20.0,18),
    Instruction(:sin) => InstructionCost(18,15.0,68.0,23),
    Instruction(:cos) => InstructionCost(18,15.0,68.0,26),
    Instruction(:sincos) => InstructionCost(25,22.0,70.0,26),
    Instruction(:identity) => InstructionCost(0,0.0,0.0,0),
    Instruction(:adjoint) => InstructionCost(0,0.0,0.0,0),
    Instruction(:transpose) => InstructionCost(0,0.0,0.0,0),
    # Symbol("##CONSTANT##") => InstructionCost(0,0.0)
)
# for (k, v) ∈ COST # so we can look up Symbol(typeof(function))
#     COST[Symbol("typeof(", lower(k), ")")] = v
# end

const CORRESPONDING_REDUCTION = Dict{Instruction,Instruction}(
    Instruction(:+) => Instruction(:vsum),
    Instruction(:-) => Instruction(:vsum),
    Instruction(:*) => Instruction(:vprod),
    Instruction(:vadd) => Instruction(:vsum),
    Instruction(:vsub) => Instruction(:vsum),
    Instruction(:vmul) => Instruction(:vprod),
    Instruction(:&) => Instruction(:vall),
    Instruction(:|) => Instruction(:vany),
    Instruction(:muladd) => Instruction(:vsum),
    Instruction(:fma) => Instruction(:vsum),
    Instruction(:vmuladd) => Instruction(:vsum),
    Instruction(:vfma) => Instruction(:vsum),
    Instruction(:vfmadd) => Instruction(:vsum),
    Instruction(:vfmsub) => Instruction(:vsum),
    Instruction(:vfnmadd) => Instruction(:vsum),
    Instruction(:vfnmsub) => Instruction(:vsum)
)
const REDUCTION_TRANSLATION = Dict{Instruction,Instruction}(
    Instruction(:+) => Instruction(:evadd),
    Instruction(:vadd) => Instruction(:evadd),
    Instruction(:*) => Instruction(:evmul),
    Instruction(:vmul) => Instruction(:evmul),
    Instruction(:-) => Instruction(:evadd),
    Instruction(:vsub) => Instruction(:evadd),
    Instruction(:/) => Instruction(:evmul),
    Instruction(:vfdiv) => Instruction(:evmul),
    Instruction(:muladd) => Instruction(:evadd),
    Instruction(:fma) => Instruction(:evadd),
    Instruction(:vmuladd) => Instruction(:evadd),
    Instruction(:vfma) => Instruction(:evadd),
    Instruction(:vfmadd) => Instruction(:evadd),
    Instruction(:vfmsub) => Instruction(:evadd),
    Instruction(:vfnmadd) => Instruction(:evadd),
    Instruction(:vfnmsub) => Instruction(:evadd)
)
const REDUCTION_ZERO = Dict{Instruction,Symbol}(
    Instruction(:+) => :zero,
    Instruction(:vadd) => :zero,
    Instruction(:*) => :one,
    Instruction(:vmul) => :one,
    Instruction(:-) => :zero,
    Instruction(:vsub) => :zero,
    Instruction(:/) => :one,
    Instruction(:vfdiv) => :one,
    Instruction(:muladd) => :zero,
    Instruction(:fma) => :zero,
    Instruction(:vmuladd) => :zero,
    Instruction(:vfma) => :zero,
    Instruction(:vfmadd) => :zero,
    Instruction(:vfmsub) => :zero,
    Instruction(:vfnmadd) => :zero,
    Instruction(:vfnmsub) => :zero
)

lv(x) = GlobalRef(LoopVectorization, x)
# Fast functions, because common pattern is
const REDUCTION_SCALAR_COMBINE = Dict{Instruction,GlobalRef}(
    Instruction(:+) => lv(:reduced_add),
    Instruction(:vadd) => lv(:reduced_add),
    Instruction(:*) => lv(:reduced_prod),
    Instruction(:vmul) => lv(:reduced_prod),
    Instruction(:-) => lv(:reduced_add),
    Instruction(:vsub) => lv(:reduced_add),
    Instruction(:/) => lv(:reduced_prod),
    Instruction(:vfdiv) => lv(:reduced_prod),
    Instruction(:muladd) => lv(:reduced_add),
    Instruction(:fma) => lv(:reduced_add),
    Instruction(:vmuladd) => lv(:reduced_add),
    Instruction(:vfma) => lv(:reduced_add),
    Instruction(:vfmadd) => lv(:reduced_add),
    Instruction(:vfmsub) => lv(:reduced_add),
    Instruction(:vfnmadd) => lv(:reduced_add),
    Instruction(:vfnmsub) => lv(:reduced_add)
)

const FUNCTIONSYMBOLS = Dict{Type{<:Function},Instruction}(
    typeof(+) => :(+),
    typeof(SIMDPirates.vadd) => :(+),
    typeof(Base.FastMath.add_fast) => :(+),
    typeof(-) => :(-),
    typeof(SIMDPirates.vsub) => :(-),
    typeof(Base.FastMath.sub_fast) => :(-),
    typeof(*) => :(*),
    typeof(SIMDPirates.vmul) => :(*),
    typeof(Base.FastMath.mul_fast) => :(*),
    typeof(/) => :(/),
    typeof(SIMDPirates.vdiv) => :(/),
    typeof(Base.FastMath.div_fast) => :(/),
    typeof(==) => :(==),
    typeof(isequal) => :isequal,
    typeof(&) => :(&),
    typeof(|) => :(|),
    typeof(>) => :(>),
    typeof(<) => :(<),
    typeof(>=) => :(>=),
    typeof(<=) => :(<=),
    typeof(inv) => :inv,
    typeof(muladd) => :muladd,
    typeof(fma) => :fma,
    typeof(SIMDPirates.vmuladd) => :vmuladd,
    typeof(SIMDPirates.vfma) => :vfma,
    typeof(SIMDPirates.vfmadd) => :vfmadd,
    typeof(SIMDPirates.vfmsub) => :vfmsub,
    typeof(SIMDPirates.vfnmadd) => :vfnmadd,
    typeof(SIMDPirates.vfnmsub) => :vfnmsub,
    typeof(sqrt) => :sqrt,
    typeof(Base.FastMath.sqrt_fast) => :sqrt,
    typeof(SIMDPirates.vsqrt) => :sqrt,
    typeof(log) => :log,
    typeof(Base.FastMath.log_fast) => :log,
    typeof(SIMDPirates.vlog) => :log,
    typeof(SLEEFPirates.log) => :log,
    typeof(exp) => :exp,
    typeof(Base.FastMath.exp_fast) => :exp,
    typeof(SIMDPirates.vexp) => :exp,
    typeof(SLEEFPirates.exp) => :exp,
    typeof(sin) => :sin,
    typeof(Base.FastMath.sin_fast) => :sin,
    typeof(SLEEFPirates.sin) => :sin,
    typeof(cos) => :cos,
    typeof(Base.FastMath.cos_fast) => :cos,
    typeof(SLEEFPirates.cos) => :cos,
    typeof(sincos) => :sincos,
    typeof(Base.FastMath.sincos_fast) => :sincos,
    typeof(SLEEFPirates.sincos) => :sincos
)


text:
macro shared_fields_stanmodels()
  return esc(:(
    name::AbstractString;
    model::AbstractString;
    n_chains::Vector{Int64};
    seed::StanBase.RandomSeed;
    init::StanBase.Init;
    output::StanBase.Output;
    tmpdir::AbstractString;
    output_base::AbstractString;
    exec_path::AbstractString;
    data_file::Vector{String};
    init_file::Vector{String};
    cmds::Vector{Cmd};
    sample_file::Vector{String};
    log_file::Vector{String};
    diagnostic_file::Vector{String};
    summary::Bool;
    printsummary::Bool;
    sm::StanRun.StanModel;
  ))
end


text:
"""
    JointDistanceDistributionTest(; distance_metric = SqEuclidean(), B::Int = 10,
        D::Int = 2, τ::Int = 1)

The parameters for a joint distance distribution [1] analysis.

## Optional keyword arguments

- **`distance_metric`**: The distance metric used to compute distances. Has to be a instance of a
    valid distance metric from `Distances.jl`. Defaults to `SqEuclidean()`.

- **`B::Int`**: The number of equidistant subintervals to divide the interval `[0, 1]` into
    when comparing the normalised distances.

- **`D::Int`**: The dimension of the delay reconstructions.

- **`τ::Int`**: The delay of the delay reconstructions.

## References

[1] Amigó, José M., and Yoshito Hirata. "Detecting directional couplings from multivariate flows by
the joint distance distribution." Chaos: An Interdisciplinary Journal of Nonlinear
Science 28.7 (2018): 075302.

"""
Base.@kwdef mutable struct JointDistanceDistributionTest{N, M} <: JointDistancesCausalityTest{N} where M
    """ The distance metric. """
    distance_metric::M = SqEuclidean()

    """ The number of subintervals. """
    B::Int = 10

    """ The dimension of the delay reconstructions. """
    D::Int = 2

    """ The delay reconstruction lag. """
    τ::Int = 1

    function JointDistanceDistributionTest(distance_metric::M, B::Int, D::Int, τ::Int) where M
        # The number of returned elements. The test itself returns a distribution of
        # `B` different numbers, but we're applying the hypothesis test to that, so
        # only a single element is returned.
        N = B
        new{N, M}(distance_metric, B, D, τ)
    end
end

function causality(source::AbstractVector{T}, target::AbstractVector{T}, p::JointDistanceDistributionTest) where {T <: Real}
    joint_distance_distribution(source, target;
        distance_metric = p.distance_metric,
        B = p.B,
        D = p.D,
        τ = p.τ)
end

export JointDistanceDistributionTest


text:
using ..common
using Compat
using ProtoBuf
import ProtoBuf.meta
import Base: hash, isequal, ==

type __enum_SchedulerResourceTypes <: ProtoEnum
    MEMORY::Int32
    CPU::Int32
    __enum_SchedulerResourceTypes() = new(0,1)
end #type __enum_SchedulerResourceTypes
const SchedulerResourceTypes = __enum_SchedulerResourceTypes()

type __enum_ApplicationsRequestScopeProto <: ProtoEnum
    ALL::Int32
    VIEWABLE::Int32
    OWN::Int32
    __enum_ApplicationsRequestScopeProto() = new(0,1,2)
end #type __enum_ApplicationsRequestScopeProto
const ApplicationsRequestScopeProto = __enum_ApplicationsRequestScopeProto()

type RegisterApplicationMasterRequestProto
    host::AbstractString
    rpc_port::Int32
    tracking_url::AbstractString
    RegisterApplicationMasterRequestProto() = (o=new(); fillunset(o); o)
end #type RegisterApplicationMasterRequestProto
hash(v::RegisterApplicationMasterRequestProto) = ProtoBuf.protohash(v)
isequal(v1::RegisterApplicationMasterRequestProto, v2::RegisterApplicationMasterRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::RegisterApplicationMasterRequestProto, v2::RegisterApplicationMasterRequestProto) = ProtoBuf.protoeq(v1, v2)

type FinishApplicationMasterRequestProto
    diagnostics::AbstractString
    tracking_url::AbstractString
    final_application_status::Int32
    FinishApplicationMasterRequestProto() = (o=new(); fillunset(o); o)
end #type FinishApplicationMasterRequestProto
hash(v::FinishApplicationMasterRequestProto) = ProtoBuf.protohash(v)
isequal(v1::FinishApplicationMasterRequestProto, v2::FinishApplicationMasterRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::FinishApplicationMasterRequestProto, v2::FinishApplicationMasterRequestProto) = ProtoBuf.protoeq(v1, v2)

type FinishApplicationMasterResponseProto
    isUnregistered::Bool
    FinishApplicationMasterResponseProto() = (o=new(); fillunset(o); o)
end #type FinishApplicationMasterResponseProto
const __val_FinishApplicationMasterResponseProto = @compat Dict(:isUnregistered => false)
meta(t::Type{FinishApplicationMasterResponseProto}) = meta(t, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, __val_FinishApplicationMasterResponseProto, true, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES)
hash(v::FinishApplicationMasterResponseProto) = ProtoBuf.protohash(v)
isequal(v1::FinishApplicationMasterResponseProto, v2::FinishApplicationMasterResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::FinishApplicationMasterResponseProto, v2::FinishApplicationMasterResponseProto) = ProtoBuf.protoeq(v1, v2)

type AllocateRequestProto
    ask::Array{ResourceRequestProto,1}
    release::Array{ContainerIdProto,1}
    blacklist_request::ResourceBlacklistRequestProto
    response_id::Int32
    progress::Float32
    increase_request::Array{ContainerResourceIncreaseRequestProto,1}
    AllocateRequestProto() = (o=new(); fillunset(o); o)
end #type AllocateRequestProto
hash(v::AllocateRequestProto) = ProtoBuf.protohash(v)
isequal(v1::AllocateRequestProto, v2::AllocateRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::AllocateRequestProto, v2::AllocateRequestProto) = ProtoBuf.protoeq(v1, v2)

type NMTokenProto
    nodeId::NodeIdProto
    token::TokenProto
    NMTokenProto() = (o=new(); fillunset(o); o)
end #type NMTokenProto
hash(v::NMTokenProto) = ProtoBuf.protohash(v)
isequal(v1::NMTokenProto, v2::NMTokenProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::NMTokenProto, v2::NMTokenProto) = ProtoBuf.protoeq(v1, v2)

type RegisterApplicationMasterResponseProto
    maximumCapability::ResourceProto
    client_to_am_token_master_key::Array{UInt8,1}
    application_ACLs::Array{ApplicationACLMapProto,1}
    containers_from_previous_attempts::Array{ContainerProto,1}
    queue::AbstractString
    nm_tokens_from_previous_attempts::Array{NMTokenProto,1}
    scheduler_resource_types::Array{Int32,1}
    RegisterApplicationMasterResponseProto() = (o=new(); fillunset(o); o)
end #type RegisterApplicationMasterResponseProto
hash(v::RegisterApplicationMasterResponseProto) = ProtoBuf.protohash(v)
isequal(v1::RegisterApplicationMasterResponseProto, v2::RegisterApplicationMasterResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::RegisterApplicationMasterResponseProto, v2::RegisterApplicationMasterResponseProto) = ProtoBuf.protoeq(v1, v2)

type AllocateResponseProto
    a_m_command::Int32
    response_id::Int32
    allocated_containers::Array{ContainerProto,1}
    completed_container_statuses::Array{ContainerStatusProto,1}
    limit::ResourceProto
    updated_nodes::Array{NodeReportProto,1}
    num_cluster_nodes::Int32
    preempt::PreemptionMessageProto
    nm_tokens::Array{NMTokenProto,1}
    increased_containers::Array{ContainerResourceIncreaseProto,1}
    decreased_containers::Array{ContainerResourceDecreaseProto,1}
    am_rm_token::TokenProto
    AllocateResponseProto() = (o=new(); fillunset(o); o)
end #type AllocateResponseProto
hash(v::AllocateResponseProto) = ProtoBuf.protohash(v)
isequal(v1::AllocateResponseProto, v2::AllocateResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::AllocateResponseProto, v2::AllocateResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetNewApplicationRequestProto
    GetNewApplicationRequestProto() = (o=new(); fillunset(o); o)
end #type GetNewApplicationRequestProto
hash(v::GetNewApplicationRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetNewApplicationRequestProto, v2::GetNewApplicationRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetNewApplicationRequestProto, v2::GetNewApplicationRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetNewApplicationResponseProto
    application_id::ApplicationIdProto
    maximumCapability::ResourceProto
    GetNewApplicationResponseProto() = (o=new(); fillunset(o); o)
end #type GetNewApplicationResponseProto
hash(v::GetNewApplicationResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetNewApplicationResponseProto, v2::GetNewApplicationResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetNewApplicationResponseProto, v2::GetNewApplicationResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetApplicationReportRequestProto
    application_id::ApplicationIdProto
    GetApplicationReportRequestProto() = (o=new(); fillunset(o); o)
end #type GetApplicationReportRequestProto
hash(v::GetApplicationReportRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetApplicationReportRequestProto, v2::GetApplicationReportRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetApplicationReportRequestProto, v2::GetApplicationReportRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetApplicationReportResponseProto
    application_report::ApplicationReportProto
    GetApplicationReportResponseProto() = (o=new(); fillunset(o); o)
end #type GetApplicationReportResponseProto
hash(v::GetApplicationReportResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetApplicationReportResponseProto, v2::GetApplicationReportResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetApplicationReportResponseProto, v2::GetApplicationReportResponseProto) = ProtoBuf.protoeq(v1, v2)

type SubmitApplicationRequestProto
    application_submission_context::ApplicationSubmissionContextProto
    SubmitApplicationRequestProto() = (o=new(); fillunset(o); o)
end #type SubmitApplicationRequestProto
hash(v::SubmitApplicationRequestProto) = ProtoBuf.protohash(v)
isequal(v1::SubmitApplicationRequestProto, v2::SubmitApplicationRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::SubmitApplicationRequestProto, v2::SubmitApplicationRequestProto) = ProtoBuf.protoeq(v1, v2)

type SubmitApplicationResponseProto
    SubmitApplicationResponseProto() = (o=new(); fillunset(o); o)
end #type SubmitApplicationResponseProto
hash(v::SubmitApplicationResponseProto) = ProtoBuf.protohash(v)
isequal(v1::SubmitApplicationResponseProto, v2::SubmitApplicationResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::SubmitApplicationResponseProto, v2::SubmitApplicationResponseProto) = ProtoBuf.protoeq(v1, v2)

type KillApplicationRequestProto
    application_id::ApplicationIdProto
    KillApplicationRequestProto() = (o=new(); fillunset(o); o)
end #type KillApplicationRequestProto
hash(v::KillApplicationRequestProto) = ProtoBuf.protohash(v)
isequal(v1::KillApplicationRequestProto, v2::KillApplicationRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::KillApplicationRequestProto, v2::KillApplicationRequestProto) = ProtoBuf.protoeq(v1, v2)

type KillApplicationResponseProto
    is_kill_completed::Bool
    KillApplicationResponseProto() = (o=new(); fillunset(o); o)
end #type KillApplicationResponseProto
const __val_KillApplicationResponseProto = @compat Dict(:is_kill_completed => false)
meta(t::Type{KillApplicationResponseProto}) = meta(t, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, __val_KillApplicationResponseProto, true, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES)
hash(v::KillApplicationResponseProto) = ProtoBuf.protohash(v)
isequal(v1::KillApplicationResponseProto, v2::KillApplicationResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::KillApplicationResponseProto, v2::KillApplicationResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetClusterMetricsRequestProto
    GetClusterMetricsRequestProto() = (o=new(); fillunset(o); o)
end #type GetClusterMetricsRequestProto
hash(v::GetClusterMetricsRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetClusterMetricsRequestProto, v2::GetClusterMetricsRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetClusterMetricsRequestProto, v2::GetClusterMetricsRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetClusterMetricsResponseProto
    cluster_metrics::YarnClusterMetricsProto
    GetClusterMetricsResponseProto() = (o=new(); fillunset(o); o)
end #type GetClusterMetricsResponseProto
hash(v::GetClusterMetricsResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetClusterMetricsResponseProto, v2::GetClusterMetricsResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetClusterMetricsResponseProto, v2::GetClusterMetricsResponseProto) = ProtoBuf.protoeq(v1, v2)

type MoveApplicationAcrossQueuesRequestProto
    application_id::ApplicationIdProto
    target_queue::AbstractString
    MoveApplicationAcrossQueuesRequestProto() = (o=new(); fillunset(o); o)
end #type MoveApplicationAcrossQueuesRequestProto
const __req_MoveApplicationAcrossQueuesRequestProto = Symbol[:application_id,:target_queue]
meta(t::Type{MoveApplicationAcrossQueuesRequestProto}) = meta(t, __req_MoveApplicationAcrossQueuesRequestProto, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, true, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES)
hash(v::MoveApplicationAcrossQueuesRequestProto) = ProtoBuf.protohash(v)
isequal(v1::MoveApplicationAcrossQueuesRequestProto, v2::MoveApplicationAcrossQueuesRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::MoveApplicationAcrossQueuesRequestProto, v2::MoveApplicationAcrossQueuesRequestProto) = ProtoBuf.protoeq(v1, v2)

type MoveApplicationAcrossQueuesResponseProto
    MoveApplicationAcrossQueuesResponseProto() = (o=new(); fillunset(o); o)
end #type MoveApplicationAcrossQueuesResponseProto
hash(v::MoveApplicationAcrossQueuesResponseProto) = ProtoBuf.protohash(v)
isequal(v1::MoveApplicationAcrossQueuesResponseProto, v2::MoveApplicationAcrossQueuesResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::MoveApplicationAcrossQueuesResponseProto, v2::MoveApplicationAcrossQueuesResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetApplicationsRequestProto
    application_types::Array{AbstractString,1}
    application_states::Array{Int32,1}
    users::Array{AbstractString,1}
    queues::Array{AbstractString,1}
    limit::Int64
    start_begin::Int64
    start_end::Int64
    finish_begin::Int64
    finish_end::Int64
    applicationTags::Array{AbstractString,1}
    scope::Int32
    GetApplicationsRequestProto() = (o=new(); fillunset(o); o)
end #type GetApplicationsRequestProto
const __val_GetApplicationsRequestProto = @compat Dict(:scope => ApplicationsRequestScopeProto.ALL)
meta(t::Type{GetApplicationsRequestProto}) = meta(t, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, __val_GetApplicationsRequestProto, true, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES)
hash(v::GetApplicationsRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetApplicationsRequestProto, v2::GetApplicationsRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetApplicationsRequestProto, v2::GetApplicationsRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetApplicationsResponseProto
    applications::Array{ApplicationReportProto,1}
    GetApplicationsResponseProto() = (o=new(); fillunset(o); o)
end #type GetApplicationsResponseProto
hash(v::GetApplicationsResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetApplicationsResponseProto, v2::GetApplicationsResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetApplicationsResponseProto, v2::GetApplicationsResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetClusterNodesRequestProto
    nodeStates::Array{Int32,1}
    GetClusterNodesRequestProto() = (o=new(); fillunset(o); o)
end #type GetClusterNodesRequestProto
hash(v::GetClusterNodesRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetClusterNodesRequestProto, v2::GetClusterNodesRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetClusterNodesRequestProto, v2::GetClusterNodesRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetClusterNodesResponseProto
    nodeReports::Array{NodeReportProto,1}
    GetClusterNodesResponseProto() = (o=new(); fillunset(o); o)
end #type GetClusterNodesResponseProto
hash(v::GetClusterNodesResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetClusterNodesResponseProto, v2::GetClusterNodesResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetClusterNodesResponseProto, v2::GetClusterNodesResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetQueueInfoRequestProto
    queueName::AbstractString
    includeApplications::Bool
    includeChildQueues::Bool
    recursive::Bool
    GetQueueInfoRequestProto() = (o=new(); fillunset(o); o)
end #type GetQueueInfoRequestProto
hash(v::GetQueueInfoRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetQueueInfoRequestProto, v2::GetQueueInfoRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetQueueInfoRequestProto, v2::GetQueueInfoRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetQueueInfoResponseProto
    queueInfo::QueueInfoProto
    GetQueueInfoResponseProto() = (o=new(); fillunset(o); o)
end #type GetQueueInfoResponseProto
hash(v::GetQueueInfoResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetQueueInfoResponseProto, v2::GetQueueInfoResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetQueueInfoResponseProto, v2::GetQueueInfoResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetQueueUserAclsInfoRequestProto
    GetQueueUserAclsInfoRequestProto() = (o=new(); fillunset(o); o)
end #type GetQueueUserAclsInfoRequestProto
hash(v::GetQueueUserAclsInfoRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetQueueUserAclsInfoRequestProto, v2::GetQueueUserAclsInfoRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetQueueUserAclsInfoRequestProto, v2::GetQueueUserAclsInfoRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetQueueUserAclsInfoResponseProto
    queueUserAcls::Array{QueueUserACLInfoProto,1}
    GetQueueUserAclsInfoResponseProto() = (o=new(); fillunset(o); o)
end #type GetQueueUserAclsInfoResponseProto
hash(v::GetQueueUserAclsInfoResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetQueueUserAclsInfoResponseProto, v2::GetQueueUserAclsInfoResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetQueueUserAclsInfoResponseProto, v2::GetQueueUserAclsInfoResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetNodesToLabelsRequestProto
    GetNodesToLabelsRequestProto() = (o=new(); fillunset(o); o)
end #type GetNodesToLabelsRequestProto
hash(v::GetNodesToLabelsRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetNodesToLabelsRequestProto, v2::GetNodesToLabelsRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetNodesToLabelsRequestProto, v2::GetNodesToLabelsRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetNodesToLabelsResponseProto
    nodeToLabels::Array{NodeIdToLabelsProto,1}
    GetNodesToLabelsResponseProto() = (o=new(); fillunset(o); o)
end #type GetNodesToLabelsResponseProto
hash(v::GetNodesToLabelsResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetNodesToLabelsResponseProto, v2::GetNodesToLabelsResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetNodesToLabelsResponseProto, v2::GetNodesToLabelsResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetLabelsToNodesRequestProto
    nodeLabels::Array{AbstractString,1}
    GetLabelsToNodesRequestProto() = (o=new(); fillunset(o); o)
end #type GetLabelsToNodesRequestProto
hash(v::GetLabelsToNodesRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetLabelsToNodesRequestProto, v2::GetLabelsToNodesRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetLabelsToNodesRequestProto, v2::GetLabelsToNodesRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetLabelsToNodesResponseProto
    labelsToNodes::Array{LabelsToNodeIdsProto,1}
    GetLabelsToNodesResponseProto() = (o=new(); fillunset(o); o)
end #type GetLabelsToNodesResponseProto
hash(v::GetLabelsToNodesResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetLabelsToNodesResponseProto, v2::GetLabelsToNodesResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetLabelsToNodesResponseProto, v2::GetLabelsToNodesResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetClusterNodeLabelsRequestProto
    GetClusterNodeLabelsRequestProto() = (o=new(); fillunset(o); o)
end #type GetClusterNodeLabelsRequestProto
hash(v::GetClusterNodeLabelsRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetClusterNodeLabelsRequestProto, v2::GetClusterNodeLabelsRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetClusterNodeLabelsRequestProto, v2::GetClusterNodeLabelsRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetClusterNodeLabelsResponseProto
    nodeLabels::Array{AbstractString,1}
    GetClusterNodeLabelsResponseProto() = (o=new(); fillunset(o); o)
end #type GetClusterNodeLabelsResponseProto
hash(v::GetClusterNodeLabelsResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetClusterNodeLabelsResponseProto, v2::GetClusterNodeLabelsResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetClusterNodeLabelsResponseProto, v2::GetClusterNodeLabelsResponseProto) = ProtoBuf.protoeq(v1, v2)

type StartContainerRequestProto
    container_launch_context::ContainerLaunchContextProto
    container_token::TokenProto
    StartContainerRequestProto() = (o=new(); fillunset(o); o)
end #type StartContainerRequestProto
hash(v::StartContainerRequestProto) = ProtoBuf.protohash(v)
isequal(v1::StartContainerRequestProto, v2::StartContainerRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::StartContainerRequestProto, v2::StartContainerRequestProto) = ProtoBuf.protoeq(v1, v2)

type StartContainerResponseProto
    services_meta_data::Array{StringBytesMapProto,1}
    StartContainerResponseProto() = (o=new(); fillunset(o); o)
end #type StartContainerResponseProto
hash(v::StartContainerResponseProto) = ProtoBuf.protohash(v)
isequal(v1::StartContainerResponseProto, v2::StartContainerResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::StartContainerResponseProto, v2::StartContainerResponseProto) = ProtoBuf.protoeq(v1, v2)

type StopContainerRequestProto
    container_id::ContainerIdProto
    StopContainerRequestProto() = (o=new(); fillunset(o); o)
end #type StopContainerRequestProto
hash(v::StopContainerRequestProto) = ProtoBuf.protohash(v)
isequal(v1::StopContainerRequestProto, v2::StopContainerRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::StopContainerRequestProto, v2::StopContainerRequestProto) = ProtoBuf.protoeq(v1, v2)

type StopContainerResponseProto
    StopContainerResponseProto() = (o=new(); fillunset(o); o)
end #type StopContainerResponseProto
hash(v::StopContainerResponseProto) = ProtoBuf.protohash(v)
isequal(v1::StopContainerResponseProto, v2::StopContainerResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::StopContainerResponseProto, v2::StopContainerResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetContainerStatusRequestProto
    container_id::ContainerIdProto
    GetContainerStatusRequestProto() = (o=new(); fillunset(o); o)
end #type GetContainerStatusRequestProto
hash(v::GetContainerStatusRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetContainerStatusRequestProto, v2::GetContainerStatusRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetContainerStatusRequestProto, v2::GetContainerStatusRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetContainerStatusResponseProto
    status::ContainerStatusProto
    GetContainerStatusResponseProto() = (o=new(); fillunset(o); o)
end #type GetContainerStatusResponseProto
hash(v::GetContainerStatusResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetContainerStatusResponseProto, v2::GetContainerStatusResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetContainerStatusResponseProto, v2::GetContainerStatusResponseProto) = ProtoBuf.protoeq(v1, v2)

type StartContainersRequestProto
    start_container_request::Array{StartContainerRequestProto,1}
    StartContainersRequestProto() = (o=new(); fillunset(o); o)
end #type StartContainersRequestProto
hash(v::StartContainersRequestProto) = ProtoBuf.protohash(v)
isequal(v1::StartContainersRequestProto, v2::StartContainersRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::StartContainersRequestProto, v2::StartContainersRequestProto) = ProtoBuf.protoeq(v1, v2)

type ContainerExceptionMapProto
    container_id::ContainerIdProto
    exception::SerializedExceptionProto
    ContainerExceptionMapProto() = (o=new(); fillunset(o); o)
end #type ContainerExceptionMapProto
hash(v::ContainerExceptionMapProto) = ProtoBuf.protohash(v)
isequal(v1::ContainerExceptionMapProto, v2::ContainerExceptionMapProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::ContainerExceptionMapProto, v2::ContainerExceptionMapProto) = ProtoBuf.protoeq(v1, v2)

type StartContainersResponseProto
    services_meta_data::Array{StringBytesMapProto,1}
    succeeded_requests::Array{ContainerIdProto,1}
    failed_requests::Array{ContainerExceptionMapProto,1}
    StartContainersResponseProto() = (o=new(); fillunset(o); o)
end #type StartContainersResponseProto
hash(v::StartContainersResponseProto) = ProtoBuf.protohash(v)
isequal(v1::StartContainersResponseProto, v2::StartContainersResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::StartContainersResponseProto, v2::StartContainersResponseProto) = ProtoBuf.protoeq(v1, v2)

type StopContainersRequestProto
    container_id::Array{ContainerIdProto,1}
    StopContainersRequestProto() = (o=new(); fillunset(o); o)
end #type StopContainersRequestProto
hash(v::StopContainersRequestProto) = ProtoBuf.protohash(v)
isequal(v1::StopContainersRequestProto, v2::StopContainersRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::StopContainersRequestProto, v2::StopContainersRequestProto) = ProtoBuf.protoeq(v1, v2)

type StopContainersResponseProto
    succeeded_requests::Array{ContainerIdProto,1}
    failed_requests::Array{ContainerExceptionMapProto,1}
    StopContainersResponseProto() = (o=new(); fillunset(o); o)
end #type StopContainersResponseProto
hash(v::StopContainersResponseProto) = ProtoBuf.protohash(v)
isequal(v1::StopContainersResponseProto, v2::StopContainersResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::StopContainersResponseProto, v2::StopContainersResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetContainerStatusesRequestProto
    container_id::Array{ContainerIdProto,1}
    GetContainerStatusesRequestProto() = (o=new(); fillunset(o); o)
end #type GetContainerStatusesRequestProto
hash(v::GetContainerStatusesRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetContainerStatusesRequestProto, v2::GetContainerStatusesRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetContainerStatusesRequestProto, v2::GetContainerStatusesRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetContainerStatusesResponseProto
    status::Array{ContainerStatusProto,1}
    failed_requests::Array{ContainerExceptionMapProto,1}
    GetContainerStatusesResponseProto() = (o=new(); fillunset(o); o)
end #type GetContainerStatusesResponseProto
hash(v::GetContainerStatusesResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetContainerStatusesResponseProto, v2::GetContainerStatusesResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetContainerStatusesResponseProto, v2::GetContainerStatusesResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetApplicationAttemptReportRequestProto
    application_attempt_id::ApplicationAttemptIdProto
    GetApplicationAttemptReportRequestProto() = (o=new(); fillunset(o); o)
end #type GetApplicationAttemptReportRequestProto
hash(v::GetApplicationAttemptReportRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetApplicationAttemptReportRequestProto, v2::GetApplicationAttemptReportRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetApplicationAttemptReportRequestProto, v2::GetApplicationAttemptReportRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetApplicationAttemptReportResponseProto
    application_attempt_report::ApplicationAttemptReportProto
    GetApplicationAttemptReportResponseProto() = (o=new(); fillunset(o); o)
end #type GetApplicationAttemptReportResponseProto
hash(v::GetApplicationAttemptReportResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetApplicationAttemptReportResponseProto, v2::GetApplicationAttemptReportResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetApplicationAttemptReportResponseProto, v2::GetApplicationAttemptReportResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetApplicationAttemptsRequestProto
    application_id::ApplicationIdProto
    GetApplicationAttemptsRequestProto() = (o=new(); fillunset(o); o)
end #type GetApplicationAttemptsRequestProto
hash(v::GetApplicationAttemptsRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetApplicationAttemptsRequestProto, v2::GetApplicationAttemptsRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetApplicationAttemptsRequestProto, v2::GetApplicationAttemptsRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetApplicationAttemptsResponseProto
    application_attempts::Array{ApplicationAttemptReportProto,1}
    GetApplicationAttemptsResponseProto() = (o=new(); fillunset(o); o)
end #type GetApplicationAttemptsResponseProto
hash(v::GetApplicationAttemptsResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetApplicationAttemptsResponseProto, v2::GetApplicationAttemptsResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetApplicationAttemptsResponseProto, v2::GetApplicationAttemptsResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetContainerReportRequestProto
    container_id::ContainerIdProto
    GetContainerReportRequestProto() = (o=new(); fillunset(o); o)
end #type GetContainerReportRequestProto
hash(v::GetContainerReportRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetContainerReportRequestProto, v2::GetContainerReportRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetContainerReportRequestProto, v2::GetContainerReportRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetContainerReportResponseProto
    container_report::ContainerReportProto
    GetContainerReportResponseProto() = (o=new(); fillunset(o); o)
end #type GetContainerReportResponseProto
hash(v::GetContainerReportResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetContainerReportResponseProto, v2::GetContainerReportResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetContainerReportResponseProto, v2::GetContainerReportResponseProto) = ProtoBuf.protoeq(v1, v2)

type GetContainersRequestProto
    application_attempt_id::ApplicationAttemptIdProto
    GetContainersRequestProto() = (o=new(); fillunset(o); o)
end #type GetContainersRequestProto
hash(v::GetContainersRequestProto) = ProtoBuf.protohash(v)
isequal(v1::GetContainersRequestProto, v2::GetContainersRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetContainersRequestProto, v2::GetContainersRequestProto) = ProtoBuf.protoeq(v1, v2)

type GetContainersResponseProto
    containers::Array{ContainerReportProto,1}
    GetContainersResponseProto() = (o=new(); fillunset(o); o)
end #type GetContainersResponseProto
hash(v::GetContainersResponseProto) = ProtoBuf.protohash(v)
isequal(v1::GetContainersResponseProto, v2::GetContainersResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::GetContainersResponseProto, v2::GetContainersResponseProto) = ProtoBuf.protoeq(v1, v2)

type UseSharedCacheResourceRequestProto
    applicationId::ApplicationIdProto
    resourceKey::AbstractString
    UseSharedCacheResourceRequestProto() = (o=new(); fillunset(o); o)
end #type UseSharedCacheResourceRequestProto
hash(v::UseSharedCacheResourceRequestProto) = ProtoBuf.protohash(v)
isequal(v1::UseSharedCacheResourceRequestProto, v2::UseSharedCacheResourceRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::UseSharedCacheResourceRequestProto, v2::UseSharedCacheResourceRequestProto) = ProtoBuf.protoeq(v1, v2)

type UseSharedCacheResourceResponseProto
    path::AbstractString
    UseSharedCacheResourceResponseProto() = (o=new(); fillunset(o); o)
end #type UseSharedCacheResourceResponseProto
hash(v::UseSharedCacheResourceResponseProto) = ProtoBuf.protohash(v)
isequal(v1::UseSharedCacheResourceResponseProto, v2::UseSharedCacheResourceResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::UseSharedCacheResourceResponseProto, v2::UseSharedCacheResourceResponseProto) = ProtoBuf.protoeq(v1, v2)

type ReleaseSharedCacheResourceRequestProto
    applicationId::ApplicationIdProto
    resourceKey::AbstractString
    ReleaseSharedCacheResourceRequestProto() = (o=new(); fillunset(o); o)
end #type ReleaseSharedCacheResourceRequestProto
hash(v::ReleaseSharedCacheResourceRequestProto) = ProtoBuf.protohash(v)
isequal(v1::ReleaseSharedCacheResourceRequestProto, v2::ReleaseSharedCacheResourceRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::ReleaseSharedCacheResourceRequestProto, v2::ReleaseSharedCacheResourceRequestProto) = ProtoBuf.protoeq(v1, v2)

type ReleaseSharedCacheResourceResponseProto
    ReleaseSharedCacheResourceResponseProto() = (o=new(); fillunset(o); o)
end #type ReleaseSharedCacheResourceResponseProto
hash(v::ReleaseSharedCacheResourceResponseProto) = ProtoBuf.protohash(v)
isequal(v1::ReleaseSharedCacheResourceResponseProto, v2::ReleaseSharedCacheResourceResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::ReleaseSharedCacheResourceResponseProto, v2::ReleaseSharedCacheResourceResponseProto) = ProtoBuf.protoeq(v1, v2)

type ReservationSubmissionRequestProto
    queue::AbstractString
    reservation_definition::ReservationDefinitionProto
    ReservationSubmissionRequestProto() = (o=new(); fillunset(o); o)
end #type ReservationSubmissionRequestProto
hash(v::ReservationSubmissionRequestProto) = ProtoBuf.protohash(v)
isequal(v1::ReservationSubmissionRequestProto, v2::ReservationSubmissionRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::ReservationSubmissionRequestProto, v2::ReservationSubmissionRequestProto) = ProtoBuf.protoeq(v1, v2)

type ReservationSubmissionResponseProto
    reservation_id::ReservationIdProto
    ReservationSubmissionResponseProto() = (o=new(); fillunset(o); o)
end #type ReservationSubmissionResponseProto
hash(v::ReservationSubmissionResponseProto) = ProtoBuf.protohash(v)
isequal(v1::ReservationSubmissionResponseProto, v2::ReservationSubmissionResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::ReservationSubmissionResponseProto, v2::ReservationSubmissionResponseProto) = ProtoBuf.protoeq(v1, v2)

type ReservationUpdateRequestProto
    reservation_definition::ReservationDefinitionProto
    reservation_id::ReservationIdProto
    ReservationUpdateRequestProto() = (o=new(); fillunset(o); o)
end #type ReservationUpdateRequestProto
hash(v::ReservationUpdateRequestProto) = ProtoBuf.protohash(v)
isequal(v1::ReservationUpdateRequestProto, v2::ReservationUpdateRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::ReservationUpdateRequestProto, v2::ReservationUpdateRequestProto) = ProtoBuf.protoeq(v1, v2)

type ReservationUpdateResponseProto
    ReservationUpdateResponseProto() = (o=new(); fillunset(o); o)
end #type ReservationUpdateResponseProto
hash(v::ReservationUpdateResponseProto) = ProtoBuf.protohash(v)
isequal(v1::ReservationUpdateResponseProto, v2::ReservationUpdateResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::ReservationUpdateResponseProto, v2::ReservationUpdateResponseProto) = ProtoBuf.protoeq(v1, v2)

type ReservationDeleteRequestProto
    reservation_id::ReservationIdProto
    ReservationDeleteRequestProto() = (o=new(); fillunset(o); o)
end #type ReservationDeleteRequestProto
hash(v::ReservationDeleteRequestProto) = ProtoBuf.protohash(v)
isequal(v1::ReservationDeleteRequestProto, v2::ReservationDeleteRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::ReservationDeleteRequestProto, v2::ReservationDeleteRequestProto) = ProtoBuf.protoeq(v1, v2)

type ReservationDeleteResponseProto
    ReservationDeleteResponseProto() = (o=new(); fillunset(o); o)
end #type ReservationDeleteResponseProto
hash(v::ReservationDeleteResponseProto) = ProtoBuf.protohash(v)
isequal(v1::ReservationDeleteResponseProto, v2::ReservationDeleteResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::ReservationDeleteResponseProto, v2::ReservationDeleteResponseProto) = ProtoBuf.protoeq(v1, v2)

type RunSharedCacheCleanerTaskRequestProto
    RunSharedCacheCleanerTaskRequestProto() = (o=new(); fillunset(o); o)
end #type RunSharedCacheCleanerTaskRequestProto
hash(v::RunSharedCacheCleanerTaskRequestProto) = ProtoBuf.protohash(v)
isequal(v1::RunSharedCacheCleanerTaskRequestProto, v2::RunSharedCacheCleanerTaskRequestProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::RunSharedCacheCleanerTaskRequestProto, v2::RunSharedCacheCleanerTaskRequestProto) = ProtoBuf.protoeq(v1, v2)

type RunSharedCacheCleanerTaskResponseProto
    accepted::Bool
    RunSharedCacheCleanerTaskResponseProto() = (o=new(); fillunset(o); o)
end #type RunSharedCacheCleanerTaskResponseProto
hash(v::RunSharedCacheCleanerTaskResponseProto) = ProtoBuf.protohash(v)
isequal(v1::RunSharedCacheCleanerTaskResponseProto, v2::RunSharedCacheCleanerTaskResponseProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::RunSharedCacheCleanerTaskResponseProto, v2::RunSharedCacheCleanerTaskResponseProto) = ProtoBuf.protoeq(v1, v2)

export SchedulerResourceTypes, ApplicationsRequestScopeProto, RegisterApplicationMasterRequestProto, RegisterApplicationMasterResponseProto, FinishApplicationMasterRequestProto, FinishApplicationMasterResponseProto, AllocateRequestProto, NMTokenProto, AllocateResponseProto, GetNewApplicationRequestProto, GetNewApplicationResponseProto, GetApplicationReportRequestProto, GetApplicationReportResponseProto, SubmitApplicationRequestProto, SubmitApplicationResponseProto, KillApplicationRequestProto, KillApplicationResponseProto, GetClusterMetricsRequestProto, GetClusterMetricsResponseProto, MoveApplicationAcrossQueuesRequestProto, MoveApplicationAcrossQueuesResponseProto, GetApplicationsRequestProto, GetApplicationsResponseProto, GetClusterNodesRequestProto, GetClusterNodesResponseProto, GetQueueInfoRequestProto, GetQueueInfoResponseProto, GetQueueUserAclsInfoRequestProto, GetQueueUserAclsInfoResponseProto, GetNodesToLabelsRequestProto, GetNodesToLabelsResponseProto, GetLabelsToNodesRequestProto, GetLabelsToNodesResponseProto, GetClusterNodeLabelsRequestProto, GetClusterNodeLabelsResponseProto, StartContainerRequestProto, StartContainerResponseProto, StopContainerRequestProto, StopContainerResponseProto, GetContainerStatusRequestProto, GetContainerStatusResponseProto, StartContainersRequestProto, ContainerExceptionMapProto, StartContainersResponseProto, StopContainersRequestProto, StopContainersResponseProto, GetContainerStatusesRequestProto, GetContainerStatusesResponseProto, GetApplicationAttemptReportRequestProto, GetApplicationAttemptReportResponseProto, GetApplicationAttemptsRequestProto, GetApplicationAttemptsResponseProto, GetContainerReportRequestProto, GetContainerReportResponseProto, GetContainersRequestProto, GetContainersResponseProto, UseSharedCacheResourceRequestProto, UseSharedCacheResourceResponseProto, ReleaseSharedCacheResourceRequestProto, ReleaseSharedCacheResourceResponseProto, ReservationSubmissionRequestProto, ReservationSubmissionResponseProto, ReservationUpdateRequestProto, ReservationUpdateResponseProto, ReservationDeleteRequestProto, ReservationDeleteResponseProto, RunSharedCacheCleanerTaskRequestProto, RunSharedCacheCleanerTaskResponseProto