#!/usr/bin/env julia
using JSON
using Glob
using Suppressor
using Dates
using Statistics
using Random
using LinearAlgebra

runners = filter(x -> strip(x) != "", split(read(ignorestatus(pipeline(
    `ps -U $(ENV["USER"]) -ux`, `grep '[0-9]*:[0-9]*\s*julia\s*.*population.jl'`)), String), "\n"))

if length(runners) == 0
    error("cannot detect self, the programe must be wrong!")
elseif length(runners) > 1
    println(join(runners, "\n"))
    warn("population already running, exiting...")
    exit()
end

if length(ARGS) != 1
    @error "please specify config file"
end

CONFIG_FILE = ARGS[1]
CONFIG = JSON.parse(read(CONFIG_FILE, String))
const TOTAL_STAGE = ceil(Int, CONFIG["total_steps"] / CONFIG["step_interval"])

const populationroot = expanduser("./jobs/population")
const jobdeploy = expanduser("~/jobs/queue")
const jobdone = expanduser("~/jobs/done")
const jobs = expanduser("~/jobs")
const jobroot = joinpath(populationroot, CONFIG["name"])
const jobscript = joinpath(jobroot, "script")
const jobresult = joinpath(jobroot, "result") # results
const jobhistory = joinpath(jobroot, "history")
const logfile = joinpath(jobroot, "population.log")
mkpath.([populationroot, jobroot, jobscript, jobresult, jobhistory])

stage_history_path(id) = joinpath(jobhistory, "stage$(lpad(id, 4, "0")).json")
save_stage(stage) = open(f -> println(f, json(stage, 4)), stage_history_path(stage["id"]), "w")
vec_str(v) = "[$(join(v, ", "))]"
weighted_mean(r) = round(dot(r, normalize([0.95^i for i in length(r):-1:1], 1)), digits=4)

@suppress Base.println(xs...) = open(f -> (println(f, "[$(now())] ", xs...);
    println(stdout, "[$(now())] ", xs...)), logfile, "a")

function next_stage(config)
    # check history folder, which contais info of each stage
    id = 1
    vip = config["vip"]
    weight_dir = ""
    historyfiles = glob(joinpath(jobhistory, "stage????.json"))
    if length(historyfiles) > 0
        id = maximum(parse.(Int, getindex.(basename.(historyfiles), [6:9])))
    end

    if isfile(stage_history_path(id))
        # check if finished
        stage = JSON.parse(read(stage_history_path(id), String))
        @assert(length(stage["population"]) > 0)
        @assert(stage["id"] == id)
        @assert(length(stage["vip"]) == length(config["vip"]))
        if all([p["status"] == "done" for p in stage["population"]])
            rewards = [p["reward"] for p in stage["population"]]
            println("all population done in stage $id, rewards $rewards")
            vip_id = argmax(rewards)
            stage["best_person"] = vip_id
            stage["best_reward"] = stage["population"][vip_id]["reward"]
            stage["next_vip"] = stage["population"][vip_id]["config"]
            stage["next_weight_dir"] = stage["population"][vip_id]["weight_dir"]
            save_stage(stage)

            vip = stage["next_vip"]
            weight_dir = stage["next_weight_dir"]
            println("VIP person $(vip_id) $(vec_str(vip)) selected for its average reward $(maximum(rewards))")
            id += 1
        else
            println("stage $id unfinished, continuing...")
            println("stage $id current status:\n",
                    join(["$(p["runname"]): $(p["status"]), config $(vec_str(p["config"]))" *
                          (p["status"] == "done" ? ", reward $(p["reward"])" : "")
                          for p in stage["population"]], "\n"))
            return stage
        end
    end

    # end?
    if id > TOTAL_STAGE
        println("all $TOTAL_STAGE stages done")
        return nothing
    end

    # need create a new stage
    stage = Dict(
        "id" => id,
        "vip" => vip,
        "max_update" => config["step_interval"] * id,
        "weight_dir" => weight_dir
    )

    # generate population
    population = filter(p -> all(p .<= config["upper_bound"]) && all(p .>= config["lower_bound"]),
                        [vip] .+ config["variations"])
    if length(population) < config["pool"]
        popul2 = filter(p -> all(p .<= config["upper_bound"]) && all(p .>= config["lower_bound"]),
                        [vip] .+ config["additional_variations"])
        population = vcat(population, popul2[randperm(length(popul2))], repeat([vip], config["pool"]))[1:config["pool"]]
    end
    @assert length(population) == config["pool"]

    if length(population) == 0
        println("no population candidate, exiting")
        return nothing
    end

    stage["population"] = Dict.(Pair.("i", 1:length(population)), ["status" => "start"], Pair.("config", population))

    # save
    save_stage(stage)

    println("stage $id history file generated")
    return stage
end

"""
    population status: start | deployed | runover | done
    call this function to go to next state, return the result state
"""
function process_population(stage, i, config)
    id = stage["id"]
    p = stage["population"][i]
    if p["status"] == "done"
        return true
    elseif p["status"] == "start"
        # gen script and deploy
        p["runname"] = "$(config["name"])-stage$(lpad(id, 4, "0"))-person$(lpad(i, 3, "0"))"
        template = read(config["template"], String)
        if length(template) > 2 && template[1] == '"' && template[end] == '"'
            template = strip(template[2:end-1])
        elseif template == ""
            template = "exit 1\necho Empty template!"
        end
        lines = strip.(split(template, "\n", keepempty=false))
        lines[end] *= " --maps '{$(join(["\"$m\": $n" for (m, n) in zip(config["envs"], p["config"])], ", "))}'"
        lines[end] *= " --max_update $(stage["max_update"])"
        lines[end] *= " --run_id $(p["runname"])"
        lines[end] *= " --save_interval $(min(250, ceil(Int, config["step_interval"] / 4)))"
        lines[end] *= " --num_snapshot 1"
        id > 1 && (lines[end] *= " --remote_restore $(stage["weight_dir"])")
        script = join(lines, "\n")

        scriptfilename = joinpath(jobscript, "$(p["runname"]).sh")
        open(f -> println(f, script), scriptfilename, "w")
        cp(scriptfilename, joinpath(jobdeploy, "$(p["runname"]).sh"), force=true)

        p["status"] = "deployed"
    elseif p["status"] == "deployed"
        # check if done, if not, whether in queue or in jobroot, else print a warn
        doneshfile = glob("\\[DONE*\\]$(p["runname"]).sh", jobdone)
        if length(doneshfile) >= 1
            p["status"] = "runover"
        else
            return false
        end
    elseif p["status"] == "runover"
        # summaryise
        # find log files
        logfiles = unique(vcat(glob("\\[DONE*\\]$(p["runname"]).sh.log", jobdone),
                               glob("\\[STOP*\\]$(p["runname"]).sh.log", jobs),
                               glob("\\[?-ORZ*\\]$(p["runname"]).sh.log", jobs),
                               glob("\\[?-ERR*\\]$(p["runname"]).sh.log", jobs)))

        @assert length(logfiles) >= 1
        p["weight_dir"] = strip(split(read(pipeline(`cat $(logfiles[1])`, `grep 'weights are saved at'`, `cut -b 22-`), String), "\n")[1])
        rewards = []
        for f in logfiles
            try
                r = read(pipeline(`cat $f`, `grep $(config["envs"][1] * "_rew_mean")`, `cut -d'|' -f3`), String)
                append!(rewards, parse.(Float32, split(r, "\n", keepempty=false)))
            catch y
                println(y)
            end
        end
        @assert length(rewards) > 0
        p["rewards"] = join(rewards, ",")
        p["reward"] = weighted_mean(rewards)
        for f in logfiles
            for g in [f, f[1:end-4], f[1:end-4] * ".bk"]
                isfile(g) && mv(g, joinpath(jobresult, basename(g)))
            end
        end
        println("stage $id population $i config $(vec_str(p["config"])), weighted mean reward $(p["reward"])",
                "mean reward $(mean(rewards)), std $(std(rewards)), max $(maximum(rewards)), min $(minimum(rewards)), count $(length(rewards))")
        p["status"] = "done"
    else
        println("warn: stage $id population $i in unknown state")
    end

    println("stage $id population $i config $(vec_str(p["config"])) goto state $(p["status"])")
    return false
end

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

function main(config)
    println("whaaa! a new day!")
    println("config file $CONFIG_FILE loaded\n", json(config))
    # get where we are
    stage = next_stage(config)
    while stage != nothing
        println("now on stage $(stage["id"]) / $TOTAL_STAGE, updates from $(stage["max_update"] - config["step_interval"]) to $(stage["max_update"])")
        n = length(stage["population"])
        while true
            n_done = 0
            for i in 1:n
                n_done += process_population(stage, i, config)
                save_stage(stage)
                sleep(0.5)
            end
            n_done == length(stage["population"]) && break
        end
        stage = next_stage(config)
    end
end

main(CONFIG)


"""
`module  JAC.RayleighCompton`
    ... a submodel of JAC that contains all methods for computing elastic Rayleigh and inelastic Compton photon scattering cross sections.
"""
module RayleighCompton

    using ..Basics, ..ManyElectron, ..Radial, ..TableStrings

    """
    `struct  RayleighCompton.Settings`  ... defines a type for the settings in estimating lastic Rayleigh and inelastic Compton
                                            photon scattering cross sections

        + multipoles              ::Array{EmMultipole}           ... Specifies the multipoles of the radiation field that are to be included.
        + gauges                  ::Array{UseGauge}              ... Specifies the gauges to be included into the computations.
        + photonEnergies          ::Array{Float64,1}             ... List of photon energies.
        + printBeforeComputation  ::Bool                         ... True, if all energies and lines are printed before their evaluation.
        + selectLines             ::Bool                         ... True, if lines are selected individually for the computations.
        + selectedLines           ::Array{Tuple{Int64,Int64},1}  ... List of lines, given by tupels (inital-level, final-level).

    """
    struct Settings
        multipoles                ::Array{EmMultipole}
        gauges                    ::Array{UseGauge}
        photonEnergies            ::Array{Float64,1}
        printBeforeComputation    ::Bool
        selectLines               ::Bool
        selectedLines             ::Array{Tuple{Int64,Int64},1}
    end

    """
    `RayleighCompton.Settings()`  ... constructor for the default values of Rayleigh-Compton photon-scattering estimates.
    """
    function Settings()
        Settings(EmMultipole[], UseGauge[], Float64[], false, false, Tuple{Int64,Int64}[])
    end

    # `Base.show(io::IO, settings::RayleighCompton.Settings)`  ... prepares a proper printout of the variable settings::RayleighCompton.Settings.
    function Base.show(io::IO, settings::RayleighCompton.Settings)
        println(io, "multipoles:               $(settings.multipoles)  ")
        println(io, "gauges:                   $(settings.gauges)  ")
        println(io, "photonEnergies:           $(settings.photonEnergies)  ")
        println(io, "printBeforeComputation:   $(settings.printBeforeComputation)  ")
        println(io, "selectLines:              $(settings.selectLines)  ")
        println(io, "selectedLines:            $(settings.selectedLines)  ")
    end

    """
    `struct  RayleighCompton.Channel`
        ... defines a type for a Rayleigh-Compton channel to help characterize the scattering of a single photon with well-defined multipolarities.

        + inMultipole    ::EmMultipole          ... Multipole of the incoming photon.
        + outMultipole   ::EmMultipole          ... Multipole of the outgoing, scattered photon.
        + gauge          ::EmGauge              ... Gauge for dealing with the (coupled) radiation field.
        + amplitude      ::Complex{Float64}     ... Photoionization amplitude associated with the given channel.
   """
    struct  Channel
        inMultipole      ::EmMultipole
        outMultipole     ::EmMultipole
        gauge            ::EmGauge
        amplitude        ::Complex{Float64}
    end

    """
    `struct  RayleighCompton.Line`  ... defines a type for a Rayleigh-Compton scattering line that may include the definition of channels.

        + initialLevel     ::Level           ... initial-(state) level
        + finalLevel       ::Level           ... final-(state) level
        + inPhotonEnergy   ::Float64         ... Energy of the incoming photon.
        + outPhotonEnergy  ::Float64         ... Energy of the outgoing, scattered photon.
        + crossSection     ::EmProperty      ... Cross section for this photoionization.
        + hasChannels      ::Bool            ... Determines whether the individual (sub-) channels are defined in terms
                                                 of their multipolarities, etc., or not.
        + channels         ::Array{RayleighCompton.Channel,1}  ... List of RayleighCompton.Channels of this line.
    """
    struct  Line
        initialLevel       ::Level
        finalLevel         ::Level
        inPhotonEnergy     ::Float64
        outPhotonEnergy    ::Float64
        crossSection       ::EmProperty
        hasChannels        ::Bool
        channels           ::Array{RayleighCompton.Channel,1}
    end

    # `Base.show(io::IO, line::RayleighCompton.Line)`  ... prepares a proper printout of the variable line::RayleighCompton.Line.
    function Base.show(io::IO, line::RayleighCompton.Line)
        println(io, "initialLevel:      $(line.initialLevel)  ")
        println(io, "finalLevel:        $(line.finalLevel)  ")
        println(io, "inPhotonEnergy:    $(line.inPhotonEnergy)  ")
        println(io, "outPhotonEnergy:   $(line.outPhotonEnergy)  ")
        println(io, "crossSection:      $(line.crossSection)  ")
        println(io, "hasChannels:       $(line.hasChannels)  ")
        println(io, "channels:          $(line.channels)  ")
    end

    """
    `RayleighCompton.computeLines(finalMultiplet::Multiplet, initialMultiplet::Multiplet, grid::Radial.Grid, settings::RayleighCompton.Settings; output=true)`
        ... to compute the Rayleigh-Compton transition amplitudes and all properties as requested by the given settings. A list of
            lines::Array{RayleighCompton.Lines} is returned.
    """
    function  computeLines(finalMultiplet::Multiplet, initialMultiplet::Multiplet, grid::Radial.Grid, settings::RayleighCompton.Settings; output=true)
        println("")
        printstyled("RayleighCompton.computeLines(): The computation of Rayleigh-ComptonAuger cross sections starts now ... \n", color=:light_green)
        printstyled("------------------------------------------------------------------------------------------------------ \n", color=:light_green)
        println("")
        #
        println("Not yet implemented: Data structures and properties still need to be worked out.")
        #
        lines = "Not yet implemented !"
        if    output    return( lines )
        else            return( nothing )
        end
    end

end # module


function get_ndcc12persp()
m = Model()

# ----- Variables ----- #
@variable(m, objvar)
x_Idx = Any[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691]
@variable(m, x[x_Idx])
b_Idx = Any[553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598]
@variable(m, b[b_Idx], Bin)
JuMP.set_lower_bound(x[146], 0.0)
JuMP.set_lower_bound(x[62], 0.0)
JuMP.set_lower_bound(x[114], 0.0)
JuMP.set_lower_bound(x[154], 0.0)
JuMP.set_lower_bound(x[287], 0.0)
JuMP.set_lower_bound(x[143], 0.0)
JuMP.set_lower_bound(x[91], 0.0)
JuMP.set_lower_bound(x[59], 0.0)
JuMP.set_lower_bound(x[623], 0.0)
JuMP.set_lower_bound(x[299], 0.0)
JuMP.set_lower_bound(x[241], 0.0)
JuMP.set_lower_bound(x[638], 0.0)
JuMP.set_lower_bound(x[494], 0.0)
JuMP.set_lower_bound(x[631], 0.0)
JuMP.set_lower_bound(x[374], 0.0)
JuMP.set_lower_bound(x[250], 0.0)
JuMP.set_lower_bound(x[474], 0.0)
JuMP.set_lower_bound(x[289], 0.0)
JuMP.set_lower_bound(x[88], 0.0)
JuMP.set_lower_bound(x[141], 0.0)
JuMP.set_lower_bound(x[421], 0.0)
JuMP.set_lower_bound(x[145], 0.0)
JuMP.set_lower_bound(x[172], 0.0)
JuMP.set_lower_bound(x[226], 0.0)
JuMP.set_lower_bound(x[531], 0.0)
JuMP.set_lower_bound(x[298], 0.0)
JuMP.set_lower_bound(x[651], 0.0)
JuMP.set_lower_bound(x[80], 0.0)
JuMP.set_lower_bound(x[75], 0.0)
JuMP.set_lower_bound(x[614], 0.0)
JuMP.set_lower_bound(x[434], 0.0)
JuMP.set_lower_bound(x[253], 0.0)
JuMP.set_lower_bound(x[351], 0.0)
JuMP.set_lower_bound(x[169], 0.0)
JuMP.set_lower_bound(x[6], 0.0)
JuMP.set_lower_bound(x[84], 0.0)
JuMP.set_lower_bound(x[225], 0.0)
JuMP.set_lower_bound(x[34], 0.0)
JuMP.set_lower_bound(x[318], 0.0)
JuMP.set_lower_bound(x[691], 0.0)
JuMP.set_lower_bound(x[386], 0.0)
JuMP.set_lower_bound(x[440], 0.0)
JuMP.set_lower_bound(x[259], 0.0)
JuMP.set_lower_bound(x[101], 0.0)
JuMP.set_lower_bound(x[190], 0.0)
JuMP.set_lower_bound(x[147], 0.0)
JuMP.set_lower_bound(x[138], 0.0)
JuMP.set_lower_bound(x[632], 0.0)
JuMP.set_lower_bound(x[649], 0.0)
JuMP.set_lower_bound(x[360], 0.0)
JuMP.set_lower_bound(x[92], 0.0)
JuMP.set_lower_bound(x[652], 0.0)
JuMP.set_lower_bound(x[54], 0.0)
JuMP.set_lower_bound(x[87], 0.0)
JuMP.set_lower_bound(x[330], 0.0)
JuMP.set_lower_bound(x[209], 0.0)
JuMP.set_lower_bound(x[282], 0.0)
JuMP.set_lower_bound(x[547], 0.0)
JuMP.set_lower_bound(x[618], 0.0)
JuMP.set_lower_bound(x[442], 0.0)
JuMP.set_lower_bound(x[24], 0.0)
JuMP.set_lower_bound(x[161], 0.0)
JuMP.set_lower_bound(x[7], 0.0)
JuMP.set_lower_bound(x[540], 0.0)
JuMP.set_lower_bound(x[661], 0.0)
JuMP.set_lower_bound(x[366], 0.0)
JuMP.set_lower_bound(x[412], 0.0)
JuMP.set_lower_bound(x[371], 0.0)
JuMP.set_lower_bound(x[390], 0.0)
JuMP.set_lower_bound(x[449], 0.0)
JuMP.set_lower_bound(x[176], 0.0)
JuMP.set_lower_bound(x[240], 0.0)
JuMP.set_lower_bound(x[345], 0.0)
JuMP.set_lower_bound(x[378], 0.0)
JuMP.set_lower_bound(x[112], 0.0)
JuMP.set_lower_bound(x[676], 0.0)
JuMP.set_lower_bound(x[503], 0.0)
JuMP.set_lower_bound(x[642], 0.0)
JuMP.set_lower_bound(x[119], 0.0)
JuMP.set_lower_bound(x[280], 0.0)
JuMP.set_lower_bound(x[613], 0.0)
JuMP.set_lower_bound(x[19], 0.0)
JuMP.set_lower_bound(x[338], 0.0)
JuMP.set_lower_bound(x[230], 0.0)
JuMP.set_lower_bound(x[476], 0.0)
JuMP.set_lower_bound(x[404], 0.0)
JuMP.set_lower_bound(x[343], 0.0)
JuMP.set_lower_bound(x[543], 0.0)
JuMP.set_lower_bound(x[76], 0.0)
JuMP.set_lower_bound(x[89], 0.0)
JuMP.set_lower_bound(x[14], 0.0)
JuMP.set_lower_bound(x[181], 0.0)
JuMP.set_lower_bound(x[201], 0.0)
JuMP.set_lower_bound(x[639], 0.0)
JuMP.set_lower_bound(x[348], 0.0)
JuMP.set_lower_bound(x[612], 0.0)
JuMP.set_lower_bound(x[335], 0.0)
JuMP.set_lower_bound(x[393], 0.0)
JuMP.set_lower_bound(x[208], 0.0)
JuMP.set_lower_bound(x[36], 0.0)
JuMP.set_lower_bound(x[270], 0.0)
JuMP.set_lower_bound(x[296], 0.0)
JuMP.set_lower_bound(x[267], 0.0)
JuMP.set_lower_bound(x[25], 0.0)
JuMP.set_lower_bound(x[606], 0.0)
JuMP.set_lower_bound(x[29], 0.0)
JuMP.set_lower_bound(x[82], 0.0)
JuMP.set_lower_bound(x[647], 0.0)
JuMP.set_lower_bound(x[268], 0.0)
JuMP.set_lower_bound(x[663], 0.0)
JuMP.set_lower_bound(x[276], 0.0)
JuMP.set_lower_bound(x[627], 0.0)
JuMP.set_lower_bound(x[511], 0.0)
JuMP.set_lower_bound(x[637], 0.0)
JuMP.set_lower_bound(x[403], 0.0)
JuMP.set_lower_bound(x[517], 0.0)
JuMP.set_lower_bound(x[254], 0.0)
JuMP.set_lower_bound(x[633], 0.0)
JuMP.set_lower_bound(x[521], 0.0)
JuMP.set_lower_bound(x[681], 0.0)
JuMP.set_lower_bound(x[388], 0.0)
JuMP.set_lower_bound(x[477], 0.0)
JuMP.set_lower_bound(x[369], 0.0)
JuMP.set_lower_bound(x[70], 0.0)
JuMP.set_lower_bound(x[83], 0.0)
JuMP.set_lower_bound(x[528], 0.0)
JuMP.set_lower_bound(x[368], 0.0)
JuMP.set_lower_bound(x[352], 0.0)
JuMP.set_lower_bound(x[546], 0.0)
JuMP.set_lower_bound(x[373], 0.0)
JuMP.set_lower_bound(x[415], 0.0)
JuMP.set_lower_bound(x[78], 0.0)
JuMP.set_lower_bound(x[660], 0.0)
JuMP.set_lower_bound(x[478], 0.0)
JuMP.set_lower_bound(x[620], 0.0)
JuMP.set_lower_bound(x[320], 0.0)
JuMP.set_lower_bound(x[293], 0.0)
JuMP.set_lower_bound(x[81], 0.0)
JuMP.set_lower_bound(x[377], 0.0)
JuMP.set_lower_bound(x[32], 0.0)
JuMP.set_lower_bound(x[193], 0.0)
JuMP.set_lower_bound(x[418], 0.0)
JuMP.set_lower_bound(x[657], 0.0)
JuMP.set_lower_bound(x[674], 0.0)
JuMP.set_lower_bound(x[451], 0.0)
JuMP.set_lower_bound(x[417], 0.0)
JuMP.set_lower_bound(x[539], 0.0)
JuMP.set_lower_bound(x[247], 0.0)
JuMP.set_lower_bound(x[10], 0.0)
JuMP.set_lower_bound(x[126], 0.0)
JuMP.set_lower_bound(x[286], 0.0)
JuMP.set_lower_bound(x[235], 0.0)
JuMP.set_lower_bound(x[31], 0.0)
JuMP.set_lower_bound(x[626], 0.0)
JuMP.set_lower_bound(x[622], 0.0)
JuMP.set_lower_bound(x[262], 0.0)
JuMP.set_lower_bound(x[135], 0.0)
JuMP.set_lower_bound(x[437], 0.0)
JuMP.set_lower_bound(x[624], 0.0)
JuMP.set_lower_bound(x[616], 0.0)
JuMP.set_lower_bound(x[460], 0.0)
JuMP.set_lower_bound(x[487], 0.0)
JuMP.set_lower_bound(x[328], 0.0)
JuMP.set_lower_bound(x[630], 0.0)
JuMP.set_lower_bound(x[251], 0.0)
JuMP.set_lower_bound(x[165], 0.0)
JuMP.set_lower_bound(x[659], 0.0)
JuMP.set_lower_bound(x[522], 0.0)
JuMP.set_lower_bound(x[248], 0.0)
JuMP.set_lower_bound(x[604], 0.0)
JuMP.set_lower_bound(x[273], 0.0)
JuMP.set_lower_bound(x[635], 0.0)
JuMP.set_lower_bound(x[55], 0.0)
JuMP.set_lower_bound(x[260], 0.0)
JuMP.set_lower_bound(x[120], 0.0)
JuMP.set_lower_bound(x[383], 0.0)
JuMP.set_lower_bound(x[72], 0.0)
JuMP.set_lower_bound(x[473], 0.0)
JuMP.set_lower_bound(x[551], 0.0)
JuMP.set_lower_bound(x[162], 0.0)
JuMP.set_lower_bound(x[116], 0.0)
JuMP.set_lower_bound(x[200], 0.0)
JuMP.set_lower_bound(x[215], 0.0)
JuMP.set_lower_bound(x[349], 0.0)
JuMP.set_lower_bound(x[499], 0.0)
JuMP.set_lower_bound(x[174], 0.0)
JuMP.set_lower_bound(x[438], 0.0)
JuMP.set_lower_bound(x[361], 0.0)
JuMP.set_lower_bound(x[150], 0.0)
JuMP.set_lower_bound(x[683], 0.0)
JuMP.set_lower_bound(x[407], 0.0)
JuMP.set_lower_bound(x[362], 0.0)
JuMP.set_lower_bound(x[471], 0.0)
JuMP.set_lower_bound(x[136], 0.0)
JuMP.set_lower_bound(x[420], 0.0)
JuMP.set_lower_bound(x[42], 0.0)
JuMP.set_lower_bound(x[151], 0.0)
JuMP.set_lower_bound(x[77], 0.0)
JuMP.set_lower_bound(x[423], 0.0)
JuMP.set_lower_bound(x[397], 0.0)
JuMP.set_lower_bound(x[234], 0.0)
JuMP.set_lower_bound(x[329], 0.0)
JuMP.set_lower_bound(x[406], 0.0)
JuMP.set_lower_bound(x[444], 0.0)
JuMP.set_lower_bound(x[111], 0.0)
JuMP.set_lower_bound(x[524], 0.0)
JuMP.set_lower_bound(x[545], 0.0)
JuMP.set_lower_bound(x[258], 0.0)
JuMP.set_lower_bound(x[295], 0.0)
JuMP.set_lower_bound(x[512], 0.0)
JuMP.set_lower_bound(x[288], 0.0)
JuMP.set_lower_bound(x[488], 0.0)
JuMP.set_lower_bound(x[199], 0.0)
JuMP.set_lower_bound(x[26], 0.0)
JuMP.set_lower_bound(x[599], 0.0)
JuMP.set_lower_bound(x[12], 0.0)
JuMP.set_lower_bound(x[441], 0.0)
JuMP.set_lower_bound(x[173], 0.0)
JuMP.set_lower_bound(x[685], 0.0)
JuMP.set_lower_bound(x[47], 0.0)
JuMP.set_lower_bound(x[123], 0.0)
JuMP.set_lower_bound(x[227], 0.0)
JuMP.set_lower_bound(x[495], 0.0)
JuMP.set_lower_bound(x[413], 0.0)
JuMP.set_lower_bound(x[279], 0.0)
JuMP.set_lower_bound(x[46], 0.0)
JuMP.set_lower_bound(x[609], 0.0)
JuMP.set_lower_bound(x[305], 0.0)
JuMP.set_lower_bound(x[39], 0.0)
JuMP.set_lower_bound(x[350], 0.0)
JuMP.set_lower_bound(x[163], 0.0)
JuMP.set_lower_bound(x[216], 0.0)
JuMP.set_lower_bound(x[133], 0.0)
JuMP.set_lower_bound(x[65], 0.0)
JuMP.set_lower_bound(x[385], 0.0)
JuMP.set_lower_bound(x[466], 0.0)
JuMP.set_lower_bound(x[153], 0.0)
JuMP.set_lower_bound(x[257], 0.0)
JuMP.set_lower_bound(x[504], 0.0)
JuMP.set_lower_bound(x[680], 0.0)
JuMP.set_lower_bound(x[510], 0.0)
JuMP.set_lower_bound(x[491], 0.0)
JuMP.set_lower_bound(x[538], 0.0)
JuMP.set_lower_bound(x[272], 0.0)
JuMP.set_lower_bound(x[496], 0.0)
JuMP.set_lower_bound(x[274], 0.0)
JuMP.set_lower_bound(x[4], 0.0)
JuMP.set_lower_bound(x[297], 0.0)
JuMP.set_lower_bound(x[191], 0.0)
JuMP.set_lower_bound(x[439], 0.0)
JuMP.set_lower_bound(x[37], 0.0)
JuMP.set_lower_bound(x[249], 0.0)
JuMP.set_lower_bound(x[457], 0.0)
JuMP.set_lower_bound(x[177], 0.0)
JuMP.set_lower_bound(x[435], 0.0)
JuMP.set_lower_bound(x[497], 0.0)
JuMP.set_lower_bound(x[688], 0.0)
JuMP.set_lower_bound(x[275], 0.0)
JuMP.set_lower_bound(x[464], 0.0)
JuMP.set_lower_bound(x[486], 0.0)
JuMP.set_lower_bound(x[86], 0.0)
JuMP.set_lower_bound(x[401], 0.0)
JuMP.set_lower_bound(x[33], 0.0)
JuMP.set_lower_bound(x[90], 0.0)
JuMP.set_lower_bound(x[507], 0.0)
JuMP.set_lower_bound(x[665], 0.0)
JuMP.set_lower_bound(x[20], 0.0)
JuMP.set_lower_bound(x[485], 0.0)
JuMP.set_lower_bound(x[529], 0.0)
JuMP.set_lower_bound(x[662], 0.0)
JuMP.set_lower_bound(x[550], 0.0)
JuMP.set_lower_bound(x[93], 0.0)
JuMP.set_lower_bound(x[222], 0.0)
JuMP.set_lower_bound(x[469], 0.0)
JuMP.set_lower_bound(x[355], 0.0)
JuMP.set_lower_bound(x[447], 0.0)
JuMP.set_lower_bound(x[670], 0.0)
JuMP.set_lower_bound(x[245], 0.0)
JuMP.set_lower_bound(x[106], 0.0)
JuMP.set_lower_bound(x[537], 0.0)
JuMP.set_lower_bound(x[640], 0.0)
JuMP.set_lower_bound(x[483], 0.0)
JuMP.set_lower_bound(x[514], 0.0)
JuMP.set_lower_bound(x[134], 0.0)
JuMP.set_lower_bound(x[122], 0.0)
JuMP.set_lower_bound(x[304], 0.0)
JuMP.set_lower_bound(x[21], 0.0)
JuMP.set_lower_bound(x[523], 0.0)
JuMP.set_lower_bound(x[107], 0.0)
JuMP.set_lower_bound(x[300], 0.0)
JuMP.set_lower_bound(x[610], 0.0)
JuMP.set_lower_bound(x[398], 0.0)
JuMP.set_lower_bound(x[246], 0.0)
JuMP.set_lower_bound(x[354], 0.0)
JuMP.set_lower_bound(x[61], 0.0)
JuMP.set_lower_bound(x[462], 0.0)
JuMP.set_lower_bound(x[242], 0.0)
JuMP.set_lower_bound(x[432], 0.0)
JuMP.set_lower_bound(x[64], 0.0)
JuMP.set_lower_bound(x[519], 0.0)
JuMP.set_lower_bound(x[159], 0.0)
JuMP.set_lower_bound(x[301], 0.0)
JuMP.set_lower_bound(x[211], 0.0)
JuMP.set_lower_bound(x[667], 0.0)
JuMP.set_lower_bound(x[446], 0.0)
JuMP.set_lower_bound(x[346], 0.0)
JuMP.set_lower_bound(x[74], 0.0)
JuMP.set_lower_bound(x[376], 0.0)
JuMP.set_lower_bound(x[312], 0.0)
JuMP.set_lower_bound(x[243], 0.0)
JuMP.set_lower_bound(x[532], 0.0)
JuMP.set_lower_bound(x[202], 0.0)
JuMP.set_lower_bound(x[391], 0.0)
JuMP.set_lower_bound(x[625], 0.0)
JuMP.set_lower_bound(x[319], 0.0)
JuMP.set_lower_bound(x[684], 0.0)
JuMP.set_lower_bound(x[425], 0.0)
JuMP.set_lower_bound(x[332], 0.0)
JuMP.set_lower_bound(x[63], 0.0)
JuMP.set_lower_bound(x[608], 0.0)
JuMP.set_lower_bound(x[505], 0.0)
JuMP.set_lower_bound(x[160], 0.0)
JuMP.set_lower_bound(x[321], 0.0)
JuMP.set_lower_bound(x[617], 0.0)
JuMP.set_lower_bound(x[656], 0.0)
JuMP.set_lower_bound(x[500], 0.0)
JuMP.set_lower_bound(x[650], 0.0)
JuMP.set_lower_bound(x[103], 0.0)
JuMP.set_lower_bound(x[475], 0.0)
JuMP.set_lower_bound(x[515], 0.0)
JuMP.set_lower_bound(x[465], 0.0)
JuMP.set_lower_bound(x[292], 0.0)
JuMP.set_lower_bound(x[95], 0.0)
JuMP.set_lower_bound(x[671], 0.0)
JuMP.set_lower_bound(x[206], 0.0)
JuMP.set_lower_bound(x[277], 0.0)
JuMP.set_lower_bound(x[278], 0.0)
JuMP.set_lower_bound(x[244], 0.0)
JuMP.set_lower_bound(x[673], 0.0)
JuMP.set_lower_bound(x[414], 0.0)
JuMP.set_lower_bound(x[60], 0.0)
JuMP.set_lower_bound(x[506], 0.0)
JuMP.set_lower_bound(x[198], 0.0)
JuMP.set_lower_bound(x[148], 0.0)
JuMP.set_lower_bound(x[291], 0.0)
JuMP.set_lower_bound(x[23], 0.0)
JuMP.set_lower_bound(x[218], 0.0)
JuMP.set_lower_bound(x[679], 0.0)
JuMP.set_lower_bound(x[677], 0.0)
JuMP.set_lower_bound(x[600], 0.0)
JuMP.set_lower_bound(x[347], 0.0)
JuMP.set_lower_bound(x[196], 0.0)
JuMP.set_lower_bound(x[38], 0.0)
JuMP.set_lower_bound(x[171], 0.0)
JuMP.set_lower_bound(x[290], 0.0)
JuMP.set_lower_bound(x[9], 0.0)
JuMP.set_lower_bound(x[311], 0.0)
JuMP.set_lower_bound(x[542], 0.0)
JuMP.set_lower_bound(x[452], 0.0)
JuMP.set_lower_bound(x[219], 0.0)
JuMP.set_lower_bound(x[400], 0.0)
JuMP.set_lower_bound(x[185], 0.0)
JuMP.set_lower_bound(x[326], 0.0)
JuMP.set_lower_bound(x[27], 0.0)
JuMP.set_lower_bound(x[324], 0.0)
JuMP.set_lower_bound(x[179], 0.0)
JuMP.set_lower_bound(x[30], 0.0)
JuMP.set_lower_bound(x[508], 0.0)
JuMP.set_lower_bound(x[142], 0.0)
JuMP.set_lower_bound(x[53], 0.0)
JuMP.set_lower_bound(x[655], 0.0)
JuMP.set_lower_bound(x[128], 0.0)
JuMP.set_lower_bound(x[313], 0.0)
JuMP.set_lower_bound(x[281], 0.0)
JuMP.set_lower_bound(x[426], 0.0)
JuMP.set_lower_bound(x[443], 0.0)
JuMP.set_lower_bound(x[629], 0.0)
JuMP.set_lower_bound(x[213], 0.0)
JuMP.set_lower_bound(x[44], 0.0)
JuMP.set_lower_bound(x[252], 0.0)
JuMP.set_lower_bound(x[445], 0.0)
JuMP.set_lower_bound(x[284], 0.0)
JuMP.set_lower_bound(x[189], 0.0)
JuMP.set_lower_bound(x[436], 0.0)
JuMP.set_lower_bound(x[166], 0.0)
JuMP.set_lower_bound(x[157], 0.0)
JuMP.set_lower_bound(x[513], 0.0)
JuMP.set_lower_bound(x[314], 0.0)
JuMP.set_lower_bound(x[358], 0.0)
JuMP.set_lower_bound(x[382], 0.0)
JuMP.set_lower_bound(x[192], 0.0)
JuMP.set_lower_bound(x[205], 0.0)
JuMP.set_lower_bound(x[207], 0.0)
JuMP.set_lower_bound(x[372], 0.0)
JuMP.set_lower_bound(x[195], 0.0)
JuMP.set_lower_bound(x[117], 0.0)
JuMP.set_lower_bound(x[658], 0.0)
JuMP.set_lower_bound(x[16], 0.0)
JuMP.set_lower_bound(x[410], 0.0)
JuMP.set_lower_bound(x[105], 0.0)
JuMP.set_lower_bound(x[22], 0.0)
JuMP.set_lower_bound(x[223], 0.0)
JuMP.set_lower_bound(x[113], 0.0)
JuMP.set_lower_bound(x[130], 0.0)
JuMP.set_lower_bound(x[359], 0.0)
JuMP.set_lower_bound(x[100], 0.0)
JuMP.set_lower_bound(x[8], 0.0)
JuMP.set_lower_bound(x[536], 0.0)
JuMP.set_lower_bound(x[527], 0.0)
JuMP.set_lower_bound(x[69], 0.0)
JuMP.set_lower_bound(x[302], 0.0)
JuMP.set_lower_bound(x[182], 0.0)
JuMP.set_lower_bound(x[664], 0.0)
JuMP.set_lower_bound(x[678], 0.0)
JuMP.set_lower_bound(x[396], 0.0)
JuMP.set_lower_bound(x[18], 0.0)
JuMP.set_lower_bound(x[52], 0.0)
JuMP.set_lower_bound(x[1], 0.0)
JuMP.set_lower_bound(x[49], 0.0)
JuMP.set_lower_bound(x[121], 0.0)
JuMP.set_lower_bound(x[152], 0.0)
JuMP.set_lower_bound(x[502], 0.0)
JuMP.set_lower_bound(x[79], 0.0)
JuMP.set_lower_bound(x[336], 0.0)
JuMP.set_lower_bound(x[45], 0.0)
JuMP.set_lower_bound(x[357], 0.0)
JuMP.set_lower_bound(x[605], 0.0)
JuMP.set_lower_bound(x[672], 0.0)
JuMP.set_lower_bound(x[607], 0.0)
JuMP.set_lower_bound(x[549], 0.0)
JuMP.set_lower_bound(x[98], 0.0)
JuMP.set_lower_bound(x[666], 0.0)
JuMP.set_lower_bound(x[456], 0.0)
JuMP.set_lower_bound(x[203], 0.0)
JuMP.set_lower_bound(x[429], 0.0)
JuMP.set_lower_bound(x[370], 0.0)
JuMP.set_lower_bound(x[35], 0.0)
JuMP.set_lower_bound(x[170], 0.0)
JuMP.set_lower_bound(x[149], 0.0)
JuMP.set_lower_bound(x[381], 0.0)
JuMP.set_lower_bound(x[675], 0.0)
JuMP.set_lower_bound(x[221], 0.0)
JuMP.set_lower_bound(x[459], 0.0)
JuMP.set_lower_bound(x[212], 0.0)
JuMP.set_lower_bound(x[51], 0.0)
JuMP.set_lower_bound(x[271], 0.0)
JuMP.set_lower_bound(x[541], 0.0)
JuMP.set_lower_bound(x[125], 0.0)
JuMP.set_lower_bound(x[520], 0.0)
JuMP.set_lower_bound(x[183], 0.0)
JuMP.set_lower_bound(x[526], 0.0)
JuMP.set_lower_bound(x[239], 0.0)
JuMP.set_lower_bound(x[294], 0.0)
JuMP.set_lower_bound(x[118], 0.0)
JuMP.set_lower_bound(x[455], 0.0)
JuMP.set_lower_bound(x[364], 0.0)
JuMP.set_lower_bound(x[110], 0.0)
JuMP.set_lower_bound(x[628], 0.0)
JuMP.set_lower_bound(x[611], 0.0)
JuMP.set_lower_bound(x[2], 0.0)
JuMP.set_lower_bound(x[269], 0.0)
JuMP.set_lower_bound(x[333], 0.0)
JuMP.set_lower_bound(x[204], 0.0)
JuMP.set_lower_bound(x[43], 0.0)
JuMP.set_lower_bound(x[337], 0.0)
JuMP.set_lower_bound(x[468], 0.0)
JuMP.set_lower_bound(x[516], 0.0)
JuMP.set_lower_bound(x[498], 0.0)
JuMP.set_lower_bound(x[57], 0.0)
JuMP.set_lower_bound(x[237], 0.0)
JuMP.set_lower_bound(x[129], 0.0)
JuMP.set_lower_bound(x[41], 0.0)
JuMP.set_lower_bound(x[104], 0.0)
JuMP.set_lower_bound(x[178], 0.0)
JuMP.set_lower_bound(x[427], 0.0)
JuMP.set_lower_bound(x[450], 0.0)
JuMP.set_lower_bound(x[411], 0.0)
JuMP.set_lower_bound(x[127], 0.0)
JuMP.set_lower_bound(x[342], 0.0)
JuMP.set_lower_bound(x[463], 0.0)
JuMP.set_lower_bound(x[601], 0.0)
JuMP.set_lower_bound(x[132], 0.0)
JuMP.set_lower_bound(x[164], 0.0)
JuMP.set_lower_bound(x[363], 0.0)
JuMP.set_lower_bound(x[308], 0.0)
JuMP.set_lower_bound(x[303], 0.0)
JuMP.set_lower_bound(x[265], 0.0)
JuMP.set_lower_bound(x[186], 0.0)
JuMP.set_lower_bound(x[327], 0.0)
JuMP.set_lower_bound(x[428], 0.0)
JuMP.set_lower_bound(x[634], 0.0)
JuMP.set_lower_bound(x[220], 0.0)
JuMP.set_lower_bound(x[430], 0.0)
JuMP.set_lower_bound(x[3], 0.0)
JuMP.set_lower_bound(x[405], 0.0)
JuMP.set_lower_bound(x[384], 0.0)
JuMP.set_lower_bound(x[518], 0.0)
JuMP.set_lower_bound(x[94], 0.0)
JuMP.set_lower_bound(x[144], 0.0)
JuMP.set_lower_bound(x[365], 0.0)
JuMP.set_lower_bound(x[188], 0.0)
JuMP.set_lower_bound(x[307], 0.0)
JuMP.set_lower_bound(x[238], 0.0)
JuMP.set_lower_bound(x[375], 0.0)
JuMP.set_lower_bound(x[489], 0.0)
JuMP.set_lower_bound(x[615], 0.0)
JuMP.set_lower_bound(x[402], 0.0)
JuMP.set_lower_bound(x[380], 0.0)
JuMP.set_lower_bound(x[533], 0.0)
JuMP.set_lower_bound(x[50], 0.0)
JuMP.set_lower_bound(x[467], 0.0)
JuMP.set_lower_bound(x[99], 0.0)
JuMP.set_lower_bound(x[602], 0.0)
JuMP.set_lower_bound(x[387], 0.0)
JuMP.set_lower_bound(x[197], 0.0)
JuMP.set_lower_bound(x[264], 0.0)
JuMP.set_lower_bound(x[552], 0.0)
JuMP.set_lower_bound(x[689], 0.0)
JuMP.set_lower_bound(x[472], 0.0)
JuMP.set_lower_bound(x[73], 0.0)
JuMP.set_lower_bound(x[479], 0.0)
JuMP.set_lower_bound(x[643], 0.0)
JuMP.set_lower_bound(x[231], 0.0)
JuMP.set_lower_bound(x[261], 0.0)
JuMP.set_lower_bound(x[392], 0.0)
JuMP.set_lower_bound(x[232], 0.0)
JuMP.set_lower_bound(x[285], 0.0)
JuMP.set_lower_bound(x[306], 0.0)
JuMP.set_lower_bound(x[137], 0.0)
JuMP.set_lower_bound(x[224], 0.0)
JuMP.set_lower_bound(x[175], 0.0)
JuMP.set_lower_bound(x[58], 0.0)
JuMP.set_lower_bound(x[394], 0.0)
JuMP.set_lower_bound(x[5], 0.0)
JuMP.set_lower_bound(x[448], 0.0)
JuMP.set_lower_bound(x[482], 0.0)
JuMP.set_lower_bound(x[344], 0.0)
JuMP.set_lower_bound(x[13], 0.0)
JuMP.set_lower_bound(x[263], 0.0)
JuMP.set_lower_bound(x[309], 0.0)
JuMP.set_lower_bound(x[67], 0.0)
JuMP.set_lower_bound(x[156], 0.0)
JuMP.set_lower_bound(x[353], 0.0)
JuMP.set_lower_bound(x[331], 0.0)
JuMP.set_lower_bound(x[399], 0.0)
JuMP.set_lower_bound(x[653], 0.0)
JuMP.set_lower_bound(x[492], 0.0)
JuMP.set_lower_bound(x[544], 0.0)
JuMP.set_lower_bound(x[493], 0.0)
JuMP.set_lower_bound(x[28], 0.0)
JuMP.set_lower_bound(x[317], 0.0)
JuMP.set_lower_bound(x[115], 0.0)
JuMP.set_lower_bound(x[187], 0.0)
JuMP.set_lower_bound(x[409], 0.0)
JuMP.set_lower_bound(x[325], 0.0)
JuMP.set_lower_bound(x[431], 0.0)
JuMP.set_lower_bound(x[316], 0.0)
JuMP.set_lower_bound(x[481], 0.0)
JuMP.set_lower_bound(x[15], 0.0)
JuMP.set_lower_bound(x[636], 0.0)
JuMP.set_lower_bound(x[424], 0.0)
JuMP.set_lower_bound(x[458], 0.0)
JuMP.set_lower_bound(x[85], 0.0)
JuMP.set_lower_bound(x[140], 0.0)
JuMP.set_lower_bound(x[416], 0.0)
JuMP.set_lower_bound(x[686], 0.0)
JuMP.set_lower_bound(x[501], 0.0)
JuMP.set_lower_bound(x[71], 0.0)
JuMP.set_lower_bound(x[334], 0.0)
JuMP.set_lower_bound(x[131], 0.0)
JuMP.set_lower_bound(x[96], 0.0)
JuMP.set_lower_bound(x[454], 0.0)
JuMP.set_lower_bound(x[210], 0.0)
JuMP.set_lower_bound(x[453], 0.0)
JuMP.set_lower_bound(x[480], 0.0)
JuMP.set_lower_bound(x[509], 0.0)
JuMP.set_lower_bound(x[422], 0.0)
JuMP.set_lower_bound(x[682], 0.0)
JuMP.set_lower_bound(x[310], 0.0)
JuMP.set_lower_bound(x[356], 0.0)
JuMP.set_lower_bound(x[484], 0.0)
JuMP.set_lower_bound(x[233], 0.0)
JuMP.set_lower_bound(x[534], 0.0)
JuMP.set_lower_bound(x[461], 0.0)
JuMP.set_lower_bound(x[419], 0.0)
JuMP.set_lower_bound(x[184], 0.0)
JuMP.set_lower_bound(x[548], 0.0)
JuMP.set_lower_bound(x[236], 0.0)
JuMP.set_lower_bound(x[158], 0.0)
JuMP.set_lower_bound(x[68], 0.0)
JuMP.set_lower_bound(x[339], 0.0)
JuMP.set_lower_bound(x[217], 0.0)
JuMP.set_lower_bound(x[619], 0.0)
JuMP.set_lower_bound(x[323], 0.0)
JuMP.set_lower_bound(x[167], 0.0)
JuMP.set_lower_bound(x[102], 0.0)
JuMP.set_lower_bound(x[228], 0.0)
JuMP.set_lower_bound(x[690], 0.0)
JuMP.set_lower_bound(x[367], 0.0)
JuMP.set_lower_bound(x[389], 0.0)
JuMP.set_lower_bound(x[56], 0.0)
JuMP.set_lower_bound(x[395], 0.0)
JuMP.set_lower_bound(x[340], 0.0)
JuMP.set_lower_bound(x[256], 0.0)
JuMP.set_lower_bound(x[266], 0.0)
JuMP.set_lower_bound(x[155], 0.0)
JuMP.set_lower_bound(x[283], 0.0)
JuMP.set_lower_bound(x[525], 0.0)
JuMP.set_lower_bound(x[322], 0.0)
JuMP.set_lower_bound(x[603], 0.0)
JuMP.set_lower_bound(x[644], 0.0)
JuMP.set_lower_bound(x[11], 0.0)
JuMP.set_lower_bound(x[687], 0.0)
JuMP.set_lower_bound(x[490], 0.0)
JuMP.set_lower_bound(x[530], 0.0)
JuMP.set_lower_bound(x[180], 0.0)
JuMP.set_lower_bound(x[194], 0.0)
JuMP.set_lower_bound(x[214], 0.0)
JuMP.set_lower_bound(x[470], 0.0)
JuMP.set_lower_bound(x[408], 0.0)
JuMP.set_lower_bound(x[341], 0.0)
JuMP.set_lower_bound(x[139], 0.0)
JuMP.set_lower_bound(x[433], 0.0)
JuMP.set_lower_bound(x[648], 0.0)
JuMP.set_lower_bound(x[535], 0.0)
JuMP.set_lower_bound(x[66], 0.0)
JuMP.set_lower_bound(x[168], 0.0)
JuMP.set_lower_bound(x[669], 0.0)
JuMP.set_lower_bound(x[40], 0.0)
JuMP.set_lower_bound(x[315], 0.0)
JuMP.set_lower_bound(x[668], 0.0)
JuMP.set_lower_bound(x[641], 0.0)
JuMP.set_lower_bound(x[97], 0.0)
JuMP.set_lower_bound(x[621], 0.0)
JuMP.set_lower_bound(x[124], 0.0)
JuMP.set_lower_bound(x[17], 0.0)
JuMP.set_lower_bound(x[654], 0.0)
JuMP.set_lower_bound(x[255], 0.0)
JuMP.set_lower_bound(x[109], 0.0)
JuMP.set_lower_bound(x[646], 0.0)
JuMP.set_lower_bound(x[48], 0.0)
JuMP.set_lower_bound(x[379], 0.0)
JuMP.set_lower_bound(x[229], 0.0)
JuMP.set_lower_bound(x[108], 0.0)

# ----- Constraints ----- #
@constraint(m, e1, -1.235768455*b[553]-1.754882812*b[554]-3.159455914*b[555]-3.980618566*b[556]-2.905401043*b[557]-2.524310515*b[558]-3.289509208*b[559]-1.235768455*b[560]-2.516549044*b[561]-2.174517481*b[562]-2.402340784*b[563]-1.754882812*b[564]-3.153941476*b[565]-2.649872155*b[566]-2.46690751*b[567]-3.159455914*b[568]-2.46690751*b[569]-1.583424277*b[570]-3.980618566*b[571]-3.153941476*b[572]-1.572334903*b[573]-2.905401043*b[574]-2.516549044*b[575]-1.572334903*b[576]-1.097733808*b[577]-2.174517481*b[578]-1.097733808*b[579]-2.95175038*b[580]-2.477930353*b[581]-1.425428344*b[582]-2.95175038*b[583]-1.694724004*b[584]-2.524310515*b[585]-1.694724004*b[586]-3.787543429*b[587]-1.759730596*b[588]-2.402340784*b[589]-1.583424277*b[590]-2.477930353*b[591]-3.787543429*b[592]-1.492267639*b[593]-3.289509208*b[594]-2.649872155*b[595]-1.425428344*b[596]-1.759730596*b[597]-1.492267639*b[598]+objvar == 0.0)
@constraint(m, e2, -x[1]-x[13]-x[25]-x[37]-x[49]-x[61]-x[73]+x[85]+x[133]+x[181]+x[217]+x[253]+x[385]+x[493] == -149.0)
@constraint(m, e3, -x[2]-x[14]-x[26]-x[38]-x[50]-x[62]-x[74]+x[86]+x[134]+x[182]+x[218]+x[254]+x[386]+x[494] == 20.0)
@constraint(m, e4, -x[3]-x[15]-x[27]-x[39]-x[51]-x[63]-x[75]+x[87]+x[135]+x[183]+x[219]+x[255]+x[387]+x[495] == 13.0)
@constraint(m, e5, -x[4]-x[16]-x[28]-x[40]-x[52]-x[64]-x[76]+x[88]+x[136]+x[184]+x[220]+x[256]+x[388]+x[496] == 11.0)
@constraint(m, e6, -x[5]-x[17]-x[29]-x[41]-x[53]-x[65]-x[77]+x[89]+x[137]+x[185]+x[221]+x[257]+x[389]+x[497] == 13.0)
@constraint(m, e7, -x[6]-x[18]-x[30]-x[42]-x[54]-x[66]-x[78]+x[90]+x[138]+x[186]+x[222]+x[258]+x[390]+x[498] == 11.0)
@constraint(m, e8, -x[7]-x[19]-x[31]-x[43]-x[55]-x[67]-x[79]+x[91]+x[139]+x[187]+x[223]+x[259]+x[391]+x[499] == 18.0)
@constraint(m, e9, -x[8]-x[20]-x[32]-x[44]-x[56]-x[68]-x[80]+x[92]+x[140]+x[188]+x[224]+x[260]+x[392]+x[500] == 19.0)
@constraint(m, e10, -x[9]-x[21]-x[33]-x[45]-x[57]-x[69]-x[81]+x[93]+x[141]+x[189]+x[225]+x[261]+x[393]+x[501] == 14.0)
@constraint(m, e11, -x[10]-x[22]-x[34]-x[46]-x[58]-x[70]-x[82]+x[94]+x[142]+x[190]+x[226]+x[262]+x[394]+x[502] == 15.0)
@constraint(m, e12, -x[11]-x[23]-x[35]-x[47]-x[59]-x[71]-x[83]+x[95]+x[143]+x[191]+x[227]+x[263]+x[395]+x[503] == 20.0)
@constraint(m, e13, -x[12]-x[24]-x[36]-x[48]-x[60]-x[72]-x[84]+x[96]+x[144]+x[192]+x[228]+x[264]+x[396]+x[504] == 22.0)
@constraint(m, e14, x[1]-x[85]-x[97]-x[109]-x[121]+x[265]+x[301]+x[433] == 12.0)
@constraint(m, e15, x[2]-x[86]-x[98]-x[110]-x[122]+x[266]+x[302]+x[434] == -178.0)
@constraint(m, e16, x[3]-x[87]-x[99]-x[111]-x[123]+x[267]+x[303]+x[435] == 7.0)
@constraint(m, e17, x[4]-x[88]-x[100]-x[112]-x[124]+x[268]+x[304]+x[436] == 6.0)
@constraint(m, e18, x[5]-x[89]-x[101]-x[113]-x[125]+x[269]+x[305]+x[437] == 25.0)
@constraint(m, e19, x[6]-x[90]-x[102]-x[114]-x[126]+x[270]+x[306]+x[438] == 25.0)
@constraint(m, e20, x[7]-x[91]-x[103]-x[115]-x[127]+x[271]+x[307]+x[439] == 25.0)
@constraint(m, e21, x[8]-x[92]-x[104]-x[116]-x[128]+x[272]+x[308]+x[440] == 23.0)
@constraint(m, e22, x[9]-x[93]-x[105]-x[117]-x[129]+x[273]+x[309]+x[441] == 8.0)
@constraint(m, e23, x[10]-x[94]-x[106]-x[118]-x[130]+x[274]+x[310]+x[442] == 7.0)
@constraint(m, e24, x[11]-x[95]-x[107]-x[119]-x[131]+x[275]+x[311]+x[443] == 20.0)
@constraint(m, e25, x[12]-x[96]-x[108]-x[120]-x[132]+x[276]+x[312]+x[444] == 14.0)
@constraint(m, e26, x[13]-x[133]-x[145]-x[157]+x[229]+x[505] == 6.0)
@constraint(m, e27, x[14]-x[134]-x[146]-x[158]+x[230]+x[506] == 21.0)
@constraint(m, e28, x[15]-x[135]-x[147]-x[159]+x[231]+x[507] == -157.0)
@constraint(m, e29, x[16]-x[136]-x[148]-x[160]+x[232]+x[508] == 25.0)
@constraint(m, e30, x[17]-x[137]-x[149]-x[161]+x[233]+x[509] == 18.0)
@constraint(m, e31, x[18]-x[138]-x[150]-x[162]+x[234]+x[510] == 23.0)
@constraint(m, e32, x[19]-x[139]-x[151]-x[163]+x[235]+x[511] == 22.0)
@constraint(m, e33, x[20]-x[140]-x[152]-x[164]+x[236]+x[512] == 19.0)
@constraint(m, e34, x[21]-x[141]-x[153]-x[165]+x[237]+x[513] == 18.0)
@constraint(m, e35, x[22]-x[142]-x[154]-x[166]+x[238]+x[514] == 21.0)
@constraint(m, e36, x[23]-x[143]-x[155]-x[167]+x[239]+x[515] == 24.0)
@constraint(m, e37, x[24]-x[144]-x[156]-x[168]+x[240]+x[516] == 16.0)
@constraint(m, e38, -x[169]+x[193] == 18.0)
@constraint(m, e39, -x[170]+x[194] == 24.0)
@constraint(m, e40, -x[171]+x[195] == 9.0)
@constraint(m, e41, -x[172]+x[196] == -183.0)
@constraint(m, e42, -x[173]+x[197] == 12.0)
@constraint(m, e43, -x[174]+x[198] == 16.0)
@constraint(m, e44, -x[175]+x[199] == 6.0)
@constraint(m, e45, -x[176]+x[200] == 14.0)
@constraint(m, e46, -x[177]+x[201] == 23.0)
@constraint(m, e47, -x[178]+x[202] == 14.0)
@constraint(m, e48, -x[179]+x[203] == 18.0)
@constraint(m, e49, -x[180]+x[204] == 24.0)
@constraint(m, e50, x[25]+x[169]-x[181]-x[193]-x[205]+x[445] == 5.0)
@constraint(m, e51, x[26]+x[170]-x[182]-x[194]-x[206]+x[446] == 12.0)
@constraint(m, e52, x[27]+x[171]-x[183]-x[195]-x[207]+x[447] == 19.0)
@constraint(m, e53, x[28]+x[172]-x[184]-x[196]-x[208]+x[448] == 22.0)
@constraint(m, e54, x[29]+x[173]-x[185]-x[197]-x[209]+x[449] == -179.0)
@constraint(m, e55, x[30]+x[174]-x[186]-x[198]-x[210]+x[450] == 22.0)
@constraint(m, e56, x[31]+x[175]-x[187]-x[199]-x[211]+x[451] == 9.0)
@constraint(m, e57, x[32]+x[176]-x[188]-x[200]-x[212]+x[452] == 6.0)
@constraint(m, e58, x[33]+x[177]-x[189]-x[201]-x[213]+x[453] == 6.0)
@constraint(m, e59, x[34]+x[178]-x[190]-x[202]-x[214]+x[454] == 21.0)
@constraint(m, e60, x[35]+x[179]-x[191]-x[203]-x[215]+x[455] == 6.0)
@constraint(m, e61, x[36]+x[180]-x[192]-x[204]-x[216]+x[456] == 22.0)
@constraint(m, e62, x[37]+x[145]-x[217]-x[229]-x[241]+x[277] == 13.0)
@constraint(m, e63, x[38]+x[146]-x[218]-x[230]-x[242]+x[278] == 12.0)
@constraint(m, e64, x[39]+x[147]-x[219]-x[231]-x[243]+x[279] == 23.0)
@constraint(m, e65, x[40]+x[148]-x[220]-x[232]-x[244]+x[280] == 16.0)
@constraint(m, e66, x[41]+x[149]-x[221]-x[233]-x[245]+x[281] == 7.0)
@constraint(m, e67, x[42]+x[150]-x[222]-x[234]-x[246]+x[282] == -178.0)
@constraint(m, e68, x[43]+x[151]-x[223]-x[235]-x[247]+x[283] == 19.0)
@constraint(m, e69, x[44]+x[152]-x[224]-x[236]-x[248]+x[284] == 25.0)
@constraint(m, e70, x[45]+x[153]-x[225]-x[237]-x[249]+x[285] == 13.0)
@constraint(m, e71, x[46]+x[154]-x[226]-x[238]-x[250]+x[286] == 17.0)
@constraint(m, e72, x[47]+x[155]-x[227]-x[239]-x[251]+x[287] == 24.0)
@constraint(m, e73, x[48]+x[156]-x[228]-x[240]-x[252]+x[288] == 8.0)
@constraint(m, e74, x[49]+x[97]+x[241]-x[253]-x[265]-x[277]-x[289]+x[313] == 9.0)
@constraint(m, e75, x[50]+x[98]+x[242]-x[254]-x[266]-x[278]-x[290]+x[314] == 20.0)
@constraint(m, e76, x[51]+x[99]+x[243]-x[255]-x[267]-x[279]-x[291]+x[315] == 21.0)
@constraint(m, e77, x[52]+x[100]+x[244]-x[256]-x[268]-x[280]-x[292]+x[316] == 22.0)
@constraint(m, e78, x[53]+x[101]+x[245]-x[257]-x[269]-x[281]-x[293]+x[317] == 6.0)
@constraint(m, e79, x[54]+x[102]+x[246]-x[258]-x[270]-x[282]-x[294]+x[318] == 8.0)
@constraint(m, e80, x[55]+x[103]+x[247]-x[259]-x[271]-x[283]-x[295]+x[319] == -162.0)
@constraint(m, e81, x[56]+x[104]+x[248]-x[260]-x[272]-x[284]-x[296]+x[320] == 22.0)
@constraint(m, e82, x[57]+x[105]+x[249]-x[261]-x[273]-x[285]-x[297]+x[321] == 19.0)
@constraint(m, e83, x[58]+x[106]+x[250]-x[262]-x[274]-x[286]-x[298]+x[322] == 17.0)
@constraint(m, e84, x[59]+x[107]+x[251]-x[263]-x[275]-x[287]-x[299]+x[323] == 11.0)
@constraint(m, e85, x[60]+x[108]+x[252]-x[264]-x[276]-x[288]-x[300]+x[324] == 16.0)
@constraint(m, e86, x[109]+x[289]-x[301]-x[313]-x[325]-x[337]-x[349]+x[361]+x[457]+x[517] == 23.0)
@constraint(m, e87, x[110]+x[290]-x[302]-x[314]-x[326]-x[338]-x[350]+x[362]+x[458]+x[518] == 11.0)
@constraint(m, e88, x[111]+x[291]-x[303]-x[315]-x[327]-x[339]-x[351]+x[363]+x[459]+x[519] == 21.0)
@constraint(m, e89, x[112]+x[292]-x[304]-x[316]-x[328]-x[340]-x[352]+x[364]+x[460]+x[520] == 23.0)
@constraint(m, e90, x[113]+x[293]-x[305]-x[317]-x[329]-x[341]-x[353]+x[365]+x[461]+x[521] == 13.0)
@constraint(m, e91, x[114]+x[294]-x[306]-x[318]-x[330]-x[342]-x[354]+x[366]+x[462]+x[522] == 18.0)
@constraint(m, e92, x[115]+x[295]-x[307]-x[319]-x[331]-x[343]-x[355]+x[367]+x[463]+x[523] == 8.0)
@constraint(m, e93, x[116]+x[296]-x[308]-x[320]-x[332]-x[344]-x[356]+x[368]+x[464]+x[524] == -176.0)
@constraint(m, e94, x[117]+x[297]-x[309]-x[321]-x[333]-x[345]-x[357]+x[369]+x[465]+x[525] == 12.0)
@constraint(m, e95, x[118]+x[298]-x[310]-x[322]-x[334]-x[346]-x[358]+x[370]+x[466]+x[526] == 15.0)
@constraint(m, e96, x[119]+x[299]-x[311]-x[323]-x[335]-x[347]-x[359]+x[371]+x[467]+x[527] == 7.0)
@constraint(m, e97, x[120]+x[300]-x[312]-x[324]-x[336]-x[348]-x[360]+x[372]+x[468]+x[528] == 22.0)
@constraint(m, e98, x[325]-x[361]-x[373]+x[397] == 21.0)
@constraint(m, e99, x[326]-x[362]-x[374]+x[398] == 10.0)
@constraint(m, e100, x[327]-x[363]-x[375]+x[399] == 7.0)
@constraint(m, e101, x[328]-x[364]-x[376]+x[400] == 14.0)
@constraint(m, e102, x[329]-x[365]-x[377]+x[401] == 14.0)
@constraint(m, e103, x[330]-x[366]-x[378]+x[402] == 11.0)
@constraint(m, e104, x[331]-x[367]-x[379]+x[403] == 15.0)
@constraint(m, e105, x[332]-x[368]-x[380]+x[404] == 16.0)
@constraint(m, e106, x[333]-x[369]-x[381]+x[405] == -139.0)
@constraint(m, e107, x[334]-x[370]-x[382]+x[406] == 25.0)
@constraint(m, e108, x[335]-x[371]-x[383]+x[407] == 23.0)
@constraint(m, e109, x[336]-x[372]-x[384]+x[408] == 14.0)
@constraint(m, e110, x[61]+x[373]-x[385]-x[397]-x[409]-x[421]+x[469]+x[529] == 12.0)
@constraint(m, e111, x[62]+x[374]-x[386]-x[398]-x[410]-x[422]+x[470]+x[530] == 21.0)
@constraint(m, e112, x[63]+x[375]-x[387]-x[399]-x[411]-x[423]+x[471]+x[531] == 10.0)
@constraint(m, e113, x[64]+x[376]-x[388]-x[400]-x[412]-x[424]+x[472]+x[532] == 19.0)
@constraint(m, e114, x[65]+x[377]-x[389]-x[401]-x[413]-x[425]+x[473]+x[533] == 23.0)
@constraint(m, e115, x[66]+x[378]-x[390]-x[402]-x[414]-x[426]+x[474]+x[534] == 17.0)
@constraint(m, e116, x[67]+x[379]-x[391]-x[403]-x[415]-x[427]+x[475]+x[535] == 11.0)
@constraint(m, e117, x[68]+x[380]-x[392]-x[404]-x[416]-x[428]+x[476]+x[536] == 13.0)
@constraint(m, e118, x[69]+x[381]-x[393]-x[405]-x[417]-x[429]+x[477]+x[537] == 11.0)
@constraint(m, e119, x[70]+x[382]-x[394]-x[406]-x[418]-x[430]+x[478]+x[538] == -191.0)
@constraint(m, e120, x[71]+x[383]-x[395]-x[407]-x[419]-x[431]+x[479]+x[539] == 18.0)
@constraint(m, e121, x[72]+x[384]-x[396]-x[408]-x[420]-x[432]+x[480]+x[540] == 15.0)
@constraint(m, e122, x[121]+x[205]+x[337]+x[409]-x[433]-x[445]-x[457]-x[469]-x[481]+x[541] == 15.0)
@constraint(m, e123, x[122]+x[206]+x[338]+x[410]-x[434]-x[446]-x[458]-x[470]-x[482]+x[542] == 13.0)
@constraint(m, e124, x[123]+x[207]+x[339]+x[411]-x[435]-x[447]-x[459]-x[471]-x[483]+x[543] == 6.0)
@constraint(m, e125, x[124]+x[208]+x[340]+x[412]-x[436]-x[448]-x[460]-x[472]-x[484]+x[544] == 13.0)
@constraint(m, e126, x[125]+x[209]+x[341]+x[413]-x[437]-x[449]-x[461]-x[473]-x[485]+x[545] == 25.0)
@constraint(m, e127, x[126]+x[210]+x[342]+x[414]-x[438]-x[450]-x[462]-x[474]-x[486]+x[546] == 13.0)
@constraint(m, e128, x[127]+x[211]+x[343]+x[415]-x[439]-x[451]-x[463]-x[475]-x[487]+x[547] == 14.0)
@constraint(m, e129, x[128]+x[212]+x[344]+x[416]-x[440]-x[452]-x[464]-x[476]-x[488]+x[548] == 14.0)
@constraint(m, e130, x[129]+x[213]+x[345]+x[417]-x[441]-x[453]-x[465]-x[477]-x[489]+x[549] == 9.0)
@constraint(m, e131, x[130]+x[214]+x[346]+x[418]-x[442]-x[454]-x[466]-x[478]-x[490]+x[550] == 19.0)
@constraint(m, e132, x[131]+x[215]+x[347]+x[419]-x[443]-x[455]-x[467]-x[479]-x[491]+x[551] == -193.0)
@constraint(m, e133, x[132]+x[216]+x[348]+x[420]-x[444]-x[456]-x[468]-x[480]-x[492]+x[552] == 17.0)
@constraint(m, e134, x[73]+x[157]+x[349]+x[421]+x[481]-x[493]-x[505]-x[517]-x[529]-x[541] == 15.0)
@constraint(m, e135, x[74]+x[158]+x[350]+x[422]+x[482]-x[494]-x[506]-x[518]-x[530]-x[542] == 14.0)
@constraint(m, e136, x[75]+x[159]+x[351]+x[423]+x[483]-x[495]-x[507]-x[519]-x[531]-x[543] == 21.0)
@constraint(m, e137, x[76]+x[160]+x[352]+x[424]+x[484]-x[496]-x[508]-x[520]-x[532]-x[544] == 12.0)
@constraint(m, e138, x[77]+x[161]+x[353]+x[425]+x[485]-x[497]-x[509]-x[521]-x[533]-x[545] == 23.0)
@constraint(m, e139, x[78]+x[162]+x[354]+x[426]+x[486]-x[498]-x[510]-x[522]-x[534]-x[546] == 14.0)
@constraint(m, e140, x[79]+x[163]+x[355]+x[427]+x[487]-x[499]-x[511]-x[523]-x[535]-x[547] == 15.0)
@constraint(m, e141, x[80]+x[164]+x[356]+x[428]+x[488]-x[500]-x[512]-x[524]-x[536]-x[548] == 5.0)
@constraint(m, e142, x[81]+x[165]+x[357]+x[429]+x[489]-x[501]-x[513]-x[525]-x[537]-x[549] == 6.0)
@constraint(m, e143, x[82]+x[166]+x[358]+x[430]+x[490]-x[502]-x[514]-x[526]-x[538]-x[550] == 20.0)
@constraint(m, e144, x[83]+x[167]+x[359]+x[431]+x[491]-x[503]-x[515]-x[527]-x[539]-x[551] == 22.0)
@constraint(m, e145, x[84]+x[168]+x[360]+x[432]+x[492]-x[504]-x[516]-x[528]-x[540]-x[552] == -190.0)
@constraint(m, e146, -x[1]-x[2]-x[3]-x[4]-x[5]-x[6]-x[7]-x[8]-x[9]-x[10]-x[11]-x[12]+x[646] >= 0.0)
@constraint(m, e147, -x[13]-x[14]-x[15]-x[16]-x[17]-x[18]-x[19]-x[20]-x[21]-x[22]-x[23]-x[24]+x[647] >= 0.0)
@constraint(m, e148, -x[25]-x[26]-x[27]-x[28]-x[29]-x[30]-x[31]-x[32]-x[33]-x[34]-x[35]-x[36]+x[648] >= 0.0)
@constraint(m, e149, -x[37]-x[38]-x[39]-x[40]-x[41]-x[42]-x[43]-x[44]-x[45]-x[46]-x[47]-x[48]+x[649] >= 0.0)
@constraint(m, e150, -x[49]-x[50]-x[51]-x[52]-x[53]-x[54]-x[55]-x[56]-x[57]-x[58]-x[59]-x[60]+x[650] >= 0.0)
@constraint(m, e151, -x[61]-x[62]-x[63]-x[64]-x[65]-x[66]-x[67]-x[68]-x[69]-x[70]-x[71]-x[72]+x[651] >= 0.0)
@constraint(m, e152, -x[73]-x[74]-x[75]-x[76]-x[77]-x[78]-x[79]-x[80]-x[81]-x[82]-x[83]-x[84]+x[652] >= 0.0)
@constraint(m, e153, -x[85]-x[86]-x[87]-x[88]-x[89]-x[90]-x[91]-x[92]-x[93]-x[94]-x[95]-x[96]+x[653] >= 0.0)
@constraint(m, e154, -x[97]-x[98]-x[99]-x[100]-x[101]-x[102]-x[103]-x[104]-x[105]-x[106]-x[107]-x[108]+x[654] >= 0.0)
@constraint(m, e155, -x[109]-x[110]-x[111]-x[112]-x[113]-x[114]-x[115]-x[116]-x[117]-x[118]-x[119]-x[120]+x[655] >= 0.0)
@constraint(m, e156, -x[121]-x[122]-x[123]-x[124]-x[125]-x[126]-x[127]-x[128]-x[129]-x[130]-x[131]-x[132]+x[656] >= 0.0)
@constraint(m, e157, -x[133]-x[134]-x[135]-x[136]-x[137]-x[138]-x[139]-x[140]-x[141]-x[142]-x[143]-x[144]+x[657] >= 0.0)
@constraint(m, e158, -x[145]-x[146]-x[147]-x[148]-x[149]-x[150]-x[151]-x[152]-x[153]-x[154]-x[155]-x[156]+x[658] >= 0.0)
@constraint(m, e159, -x[157]-x[158]-x[159]-x[160]-x[161]-x[162]-x[163]-x[164]-x[165]-x[166]-x[167]-x[168]+x[659] >= 0.0)
@constraint(m, e160, -x[169]-x[170]-x[171]-x[172]-x[173]-x[174]-x[175]-x[176]-x[177]-x[178]-x[179]-x[180]+x[660] >= 0.0)
@constraint(m, e161, -x[181]-x[182]-x[183]-x[184]-x[185]-x[186]-x[187]-x[188]-x[189]-x[190]-x[191]-x[192]+x[661] >= 0.0)
@constraint(m, e162, -x[193]-x[194]-x[195]-x[196]-x[197]-x[198]-x[199]-x[200]-x[201]-x[202]-x[203]-x[204]+x[662] >= 0.0)
@constraint(m, e163, -x[205]-x[206]-x[207]-x[208]-x[209]-x[210]-x[211]-x[212]-x[213]-x[214]-x[215]-x[216]+x[663] >= 0.0)
@constraint(m, e164, -x[217]-x[218]-x[219]-x[220]-x[221]-x[222]-x[223]-x[224]-x[225]-x[226]-x[227]-x[228]+x[664] >= 0.0)
@constraint(m, e165, -x[229]-x[230]-x[231]-x[232]-x[233]-x[234]-x[235]-x[236]-x[237]-x[238]-x[239]-x[240]+x[665] >= 0.0)
@constraint(m, e166, -x[241]-x[242]-x[243]-x[244]-x[245]-x[246]-x[247]-x[248]-x[249]-x[250]-x[251]-x[252]+x[666] >= 0.0)
@constraint(m, e167, -x[253]-x[254]-x[255]-x[256]-x[257]-x[258]-x[259]-x[260]-x[261]-x[262]-x[263]-x[264]+x[667] >= 0.0)
@constraint(m, e168, -x[265]-x[266]-x[267]-x[268]-x[269]-x[270]-x[271]-x[272]-x[273]-x[274]-x[275]-x[276]+x[668] >= 0.0)
@constraint(m, e169, -x[277]-x[278]-x[279]-x[280]-x[281]-x[282]-x[283]-x[284]-x[285]-x[286]-x[287]-x[288]+x[669] >= 0.0)
@constraint(m, e170, -x[289]-x[290]-x[291]-x[292]-x[293]-x[294]-x[295]-x[296]-x[297]-x[298]-x[299]-x[300]+x[670] >= 0.0)
@constraint(m, e171, -x[301]-x[302]-x[303]-x[304]-x[305]-x[306]-x[307]-x[308]-x[309]-x[310]-x[311]-x[312]+x[671] >= 0.0)
@constraint(m, e172, -x[313]-x[314]-x[315]-x[316]-x[317]-x[318]-x[319]-x[320]-x[321]-x[322]-x[323]-x[324]+x[672] >= 0.0)
@constraint(m, e173, -x[325]-x[326]-x[327]-x[328]-x[329]-x[330]-x[331]-x[332]-x[333]-x[334]-x[335]-x[336]+x[673] >= 0.0)
@constraint(m, e174, -x[337]-x[338]-x[339]-x[340]-x[341]-x[342]-x[343]-x[344]-x[345]-x[346]-x[347]-x[348]+x[674] >= 0.0)
@constraint(m, e175, -x[349]-x[350]-x[351]-x[352]-x[353]-x[354]-x[355]-x[356]-x[357]-x[358]-x[359]-x[360]+x[675] >= 0.0)
@constraint(m, e176, -x[361]-x[362]-x[363]-x[364]-x[365]-x[366]-x[367]-x[368]-x[369]-x[370]-x[371]-x[372]+x[676] >= 0.0)
@constraint(m, e177, -x[373]-x[374]-x[375]-x[376]-x[377]-x[378]-x[379]-x[380]-x[381]-x[382]-x[383]-x[384]+x[677] >= 0.0)
@constraint(m, e178, -x[385]-x[386]-x[387]-x[388]-x[389]-x[390]-x[391]-x[392]-x[393]-x[394]-x[395]-x[396]+x[678] >= 0.0)
@constraint(m, e179, -x[397]-x[398]-x[399]-x[400]-x[401]-x[402]-x[403]-x[404]-x[405]-x[406]-x[407]-x[408]+x[679] >= 0.0)
@constraint(m, e180, -x[409]-x[410]-x[411]-x[412]-x[413]-x[414]-x[415]-x[416]-x[417]-x[418]-x[419]-x[420]+x[680] >= 0.0)
@constraint(m, e181, -x[421]-x[422]-x[423]-x[424]-x[425]-x[426]-x[427]-x[428]-x[429]-x[430]-x[431]-x[432]+x[681] >= 0.0)
@constraint(m, e182, -x[433]-x[434]-x[435]-x[436]-x[437]-x[438]-x[439]-x[440]-x[441]-x[442]-x[443]-x[444]+x[682] >= 0.0)
@constraint(m, e183, -x[445]-x[446]-x[447]-x[448]-x[449]-x[450]-x[451]-x[452]-x[453]-x[454]-x[455]-x[456]+x[683] >= 0.0)
@constraint(m, e184, -x[457]-x[458]-x[459]-x[460]-x[461]-x[462]-x[463]-x[464]-x[465]-x[466]-x[467]-x[468]+x[684] >= 0.0)
@constraint(m, e185, -x[469]-x[470]-x[471]-x[472]-x[473]-x[474]-x[475]-x[476]-x[477]-x[478]-x[479]-x[480]+x[685] >= 0.0)
@constraint(m, e186, -x[481]-x[482]-x[483]-x[484]-x[485]-x[486]-x[487]-x[488]-x[489]-x[490]-x[491]-x[492]+x[686] >= 0.0)
@constraint(m, e187, -x[493]-x[494]-x[495]-x[496]-x[497]-x[498]-x[499]-x[500]-x[501]-x[502]-x[503]-x[504]+x[687] >= 0.0)
@constraint(m, e188, -x[505]-x[506]-x[507]-x[508]-x[509]-x[510]-x[511]-x[512]-x[513]-x[514]-x[515]-x[516]+x[688] >= 0.0)
@constraint(m, e189, -x[517]-x[518]-x[519]-x[520]-x[521]-x[522]-x[523]-x[524]-x[525]-x[526]-x[527]-x[528]+x[689] >= 0.0)
@constraint(m, e190, -x[529]-x[530]-x[531]-x[532]-x[533]-x[534]-x[535]-x[536]-x[537]-x[538]-x[539]-x[540]+x[690] >= 0.0)
@constraint(m, e191, -x[541]-x[542]-x[543]-x[544]-x[545]-x[546]-x[547]-x[548]-x[549]-x[550]-x[551]-x[552]+x[691] >= 0.0)
@NLconstraint(m, e192, 293*x[646]*b[553]-293*b[553]*x[599]+x[646]*x[599] <= 0.0)
@NLconstraint(m, e193, 192*x[647]*b[554]-192*b[554]*x[600]+x[647]*x[600] <= 0.0)
@NLconstraint(m, e194, 417*x[648]*b[555]-417*b[555]*x[601]+x[648]*x[601] <= 0.0)
@NLconstraint(m, e195, 427*x[649]*b[556]-427*b[556]*x[602]+x[649]*x[602] <= 0.0)
@NLconstraint(m, e196, 295*x[650]*b[557]-295*b[557]*x[603]+x[650]*x[603] <= 0.0)
@NLconstraint(m, e197, 280*x[651]*b[558]-280*b[558]*x[604]+x[651]*x[604] <= 0.0)
@NLconstraint(m, e198, 337*x[652]*b[559]-337*b[559]*x[605]+x[652]*x[605] <= 0.0)
@NLconstraint(m, e199, 293*x[653]*b[560]-293*b[560]*x[606]+x[653]*x[606] <= 0.0)
@NLconstraint(m, e200, 341*x[654]*b[561]-341*b[561]*x[607]+x[654]*x[607] <= 0.0)
@NLconstraint(m, e201, 276*x[655]*b[562]-276*b[562]*x[608]+x[655]*x[608] <= 0.0)
@NLconstraint(m, e202, 119*x[656]*b[563]-119*b[563]*x[609]+x[656]*x[609] <= 0.0)
@NLconstraint(m, e203, 192*x[657]*b[564]-192*b[564]*x[610]+x[657]*x[610] <= 0.0)
@NLconstraint(m, e204, 347*x[658]*b[565]-347*b[565]*x[611]+x[658]*x[611] <= 0.0)
@NLconstraint(m, e205, 398*x[659]*b[566]-398*b[566]*x[612]+x[659]*x[612] <= 0.0)
@NLconstraint(m, e206, 359*x[660]*b[567]-359*b[567]*x[613]+x[660]*x[613] <= 0.0)
@NLconstraint(m, e207, 417*x[661]*b[568]-417*b[568]*x[614]+x[661]*x[614] <= 0.0)
@NLconstraint(m, e208, 359*x[662]*b[569]-359*b[569]*x[615]+x[662]*x[615] <= 0.0)
@NLconstraint(m, e209, 193*x[663]*b[570]-193*b[570]*x[616]+x[663]*x[616] <= 0.0)
@NLconstraint(m, e210, 427*x[664]*b[571]-427*b[571]*x[617]+x[664]*x[617] <= 0.0)
@NLconstraint(m, e211, 347*x[665]*b[572]-347*b[572]*x[618]+x[665]*x[618] <= 0.0)
@NLconstraint(m, e212, 218*x[666]*b[573]-218*b[573]*x[619]+x[666]*x[619] <= 0.0)
@NLconstraint(m, e213, 295*x[667]*b[574]-295*b[574]*x[620]+x[667]*x[620] <= 0.0)
@NLconstraint(m, e214, 341*x[668]*b[575]-341*b[575]*x[621]+x[668]*x[621] <= 0.0)
@NLconstraint(m, e215, 218*x[669]*b[576]-218*b[576]*x[622]+x[669]*x[622] <= 0.0)
@NLconstraint(m, e216, 134*x[670]*b[577]-134*b[577]*x[623]+x[670]*x[623] <= 0.0)
@NLconstraint(m, e217, 276*x[671]*b[578]-276*b[578]*x[624]+x[671]*x[624] <= 0.0)
@NLconstraint(m, e218, 134*x[672]*b[579]-134*b[579]*x[625]+x[672]*x[625] <= 0.0)
@NLconstraint(m, e219, 200*x[673]*b[580]-200*b[580]*x[626]+x[673]*x[626] <= 0.0)
@NLconstraint(m, e220, 222*x[674]*b[581]-222*b[581]*x[627]+x[674]*x[627] <= 0.0)
@NLconstraint(m, e221, 196*x[675]*b[582]-196*b[582]*x[628]+x[675]*x[628] <= 0.0)
@NLconstraint(m, e222, 200*x[676]*b[583]-200*b[583]*x[629]+x[676]*x[629] <= 0.0)
@NLconstraint(m, e223, 129*x[677]*b[584]-129*b[584]*x[630]+x[677]*x[630] <= 0.0)
@NLconstraint(m, e224, 280*x[678]*b[585]-280*b[585]*x[631]+x[678]*x[631] <= 0.0)
@NLconstraint(m, e225, 129*x[679]*b[586]-129*b[586]*x[632]+x[679]*x[632] <= 0.0)
@NLconstraint(m, e226, 382*x[680]*b[587]-382*b[587]*x[633]+x[680]*x[633] <= 0.0)
@NLconstraint(m, e227, 424*x[681]*b[588]-424*b[588]*x[634]+x[681]*x[634] <= 0.0)
@NLconstraint(m, e228, 119*x[682]*b[589]-119*b[589]*x[635]+x[682]*x[635] <= 0.0)
@NLconstraint(m, e229, 193*x[683]*b[590]-193*b[590]*x[636]+x[683]*x[636] <= 0.0)
@NLconstraint(m, e230, 222*x[684]*b[591]-222*b[591]*x[637]+x[684]*x[637] <= 0.0)
@NLconstraint(m, e231, 382*x[685]*b[592]-382*b[592]*x[638]+x[685]*x[638] <= 0.0)
@NLconstraint(m, e232, 275*x[686]*b[593]-275*b[593]*x[639]+x[686]*x[639] <= 0.0)
@NLconstraint(m, e233, 337*x[687]*b[594]-337*b[594]*x[640]+x[687]*x[640] <= 0.0)
@NLconstraint(m, e234, 398*x[688]*b[595]-398*b[595]*x[641]+x[688]*x[641] <= 0.0)
@NLconstraint(m, e235, 196*x[689]*b[596]-196*b[596]*x[642]+x[689]*x[642] <= 0.0)
@NLconstraint(m, e236, 424*x[690]*b[597]-424*b[597]*x[643]+x[690]*x[643] <= 0.0)
@NLconstraint(m, e237, 275*x[691]*b[598]-275*b[598]*x[644]+x[691]*x[644] <= 0.0)
@constraint(m, e238, x[599]+x[600]+x[601]+x[602]+x[603]+x[604]+x[605]+x[606]+x[607]+x[608]+x[609]+x[610]+x[611]+x[612]+x[613]+x[614]+x[615]+x[616]+x[617]+x[618]+x[619]+x[620]+x[621]+x[622]+x[623]+x[624]+x[625]+x[626]+x[627]+x[628]+x[629]+x[630]+x[631]+x[632]+x[633]+x[634]+x[635]+x[636]+x[637]+x[638]+x[639]+x[640]+x[641]+x[642]+x[643]+x[644] <= 6225.0)
@constraint(m, e239, x[1]+x[2]+x[3]+x[4]+x[5]+x[6]+x[7]+x[8]+x[9]+x[10]+x[11]+x[12]-293*b[553] <= 0.0)
@constraint(m, e240, x[13]+x[14]+x[15]+x[16]+x[17]+x[18]+x[19]+x[20]+x[21]+x[22]+x[23]+x[24]-192*b[554] <= 0.0)
@constraint(m, e241, x[25]+x[26]+x[27]+x[28]+x[29]+x[30]+x[31]+x[32]+x[33]+x[34]+x[35]+x[36]-417*b[555] <= 0.0)
@constraint(m, e242, x[37]+x[38]+x[39]+x[40]+x[41]+x[42]+x[43]+x[44]+x[45]+x[46]+x[47]+x[48]-427*b[556] <= 0.0)
@constraint(m, e243, x[49]+x[50]+x[51]+x[52]+x[53]+x[54]+x[55]+x[56]+x[57]+x[58]+x[59]+x[60]-295*b[557] <= 0.0)
@constraint(m, e244, x[61]+x[62]+x[63]+x[64]+x[65]+x[66]+x[67]+x[68]+x[69]+x[70]+x[71]+x[72]-280*b[558] <= 0.0)
@constraint(m, e245, x[73]+x[74]+x[75]+x[76]+x[77]+x[78]+x[79]+x[80]+x[81]+x[82]+x[83]+x[84]-337*b[559] <= 0.0)
@constraint(m, e246, x[85]+x[86]+x[87]+x[88]+x[89]+x[90]+x[91]+x[92]+x[93]+x[94]+x[95]+x[96]-293*b[560] <= 0.0)
@constraint(m, e247, x[97]+x[98]+x[99]+x[100]+x[101]+x[102]+x[103]+x[104]+x[105]+x[106]+x[107]+x[108]-341*b[561] <= 0.0)
@constraint(m, e248, x[109]+x[110]+x[111]+x[112]+x[113]+x[114]+x[115]+x[116]+x[117]+x[118]+x[119]+x[120]-276*b[562] <= 0.0)
@constraint(m, e249, x[121]+x[122]+x[123]+x[124]+x[125]+x[126]+x[127]+x[128]+x[129]+x[130]+x[131]+x[132]-119*b[563] <= 0.0)
@constraint(m, e250, x[133]+x[134]+x[135]+x[136]+x[137]+x[138]+x[139]+x[140]+x[141]+x[142]+x[143]+x[144]-192*b[564] <= 0.0)
@constraint(m, e251, x[145]+x[146]+x[147]+x[148]+x[149]+x[150]+x[151]+x[152]+x[153]+x[154]+x[155]+x[156]-347*b[565] <= 0.0)
@constraint(m, e252, x[157]+x[158]+x[159]+x[160]+x[161]+x[162]+x[163]+x[164]+x[165]+x[166]+x[167]+x[168]-398*b[566] <= 0.0)
@constraint(m, e253, x[169]+x[170]+x[171]+x[172]+x[173]+x[174]+x[175]+x[176]+x[177]+x[178]+x[179]+x[180]-359*b[567] <= 0.0)
@constraint(m, e254, x[181]+x[182]+x[183]+x[184]+x[185]+x[186]+x[187]+x[188]+x[189]+x[190]+x[191]+x[192]-417*b[568] <= 0.0)
@constraint(m, e255, x[193]+x[194]+x[195]+x[196]+x[197]+x[198]+x[199]+x[200]+x[201]+x[202]+x[203]+x[204]-359*b[569] <= 0.0)
@constraint(m, e256, x[205]+x[206]+x[207]+x[208]+x[209]+x[210]+x[211]+x[212]+x[213]+x[214]+x[215]+x[216]-193*b[570] <= 0.0)
@constraint(m, e257, x[217]+x[218]+x[219]+x[220]+x[221]+x[222]+x[223]+x[224]+x[225]+x[226]+x[227]+x[228]-427*b[571] <= 0.0)
@constraint(m, e258, x[229]+x[230]+x[231]+x[232]+x[233]+x[234]+x[235]+x[236]+x[237]+x[238]+x[239]+x[240]-347*b[572] <= 0.0)
@constraint(m, e259, x[241]+x[242]+x[243]+x[244]+x[245]+x[246]+x[247]+x[248]+x[249]+x[250]+x[251]+x[252]-218*b[573] <= 0.0)
@constraint(m, e260, x[253]+x[254]+x[255]+x[256]+x[257]+x[258]+x[259]+x[260]+x[261]+x[262]+x[263]+x[264]-295*b[574] <= 0.0)
@constraint(m, e261, x[265]+x[266]+x[267]+x[268]+x[269]+x[270]+x[271]+x[272]+x[273]+x[274]+x[275]+x[276]-341*b[575] <= 0.0)
@constraint(m, e262, x[277]+x[278]+x[279]+x[280]+x[281]+x[282]+x[283]+x[284]+x[285]+x[286]+x[287]+x[288]-218*b[576] <= 0.0)
@constraint(m, e263, x[289]+x[290]+x[291]+x[292]+x[293]+x[294]+x[295]+x[296]+x[297]+x[298]+x[299]+x[300]-134*b[577] <= 0.0)
@constraint(m, e264, x[301]+x[302]+x[303]+x[304]+x[305]+x[306]+x[307]+x[308]+x[309]+x[310]+x[311]+x[312]-276*b[578] <= 0.0)
@constraint(m, e265, x[313]+x[314]+x[315]+x[316]+x[317]+x[318]+x[319]+x[320]+x[321]+x[322]+x[323]+x[324]-134*b[579] <= 0.0)
@constraint(m, e266, x[325]+x[326]+x[327]+x[328]+x[329]+x[330]+x[331]+x[332]+x[333]+x[334]+x[335]+x[336]-200*b[580] <= 0.0)
@constraint(m, e267, x[337]+x[338]+x[339]+x[340]+x[341]+x[342]+x[343]+x[344]+x[345]+x[346]+x[347]+x[348]-222*b[581] <= 0.0)
@constraint(m, e268, x[349]+x[350]+x[351]+x[352]+x[353]+x[354]+x[355]+x[356]+x[357]+x[358]+x[359]+x[360]-196*b[582] <= 0.0)
@constraint(m, e269, x[361]+x[362]+x[363]+x[364]+x[365]+x[366]+x[367]+x[368]+x[369]+x[370]+x[371]+x[372]-200*b[583] <= 0.0)
@constraint(m, e270, x[373]+x[374]+x[375]+x[376]+x[377]+x[378]+x[379]+x[380]+x[381]+x[382]+x[383]+x[384]-129*b[584] <= 0.0)
@constraint(m, e271, x[385]+x[386]+x[387]+x[388]+x[389]+x[390]+x[391]+x[392]+x[393]+x[394]+x[395]+x[396]-280*b[585] <= 0.0)
@constraint(m, e272, x[397]+x[398]+x[399]+x[400]+x[401]+x[402]+x[403]+x[404]+x[405]+x[406]+x[407]+x[408]-129*b[586] <= 0.0)
@constraint(m, e273, x[409]+x[410]+x[411]+x[412]+x[413]+x[414]+x[415]+x[416]+x[417]+x[418]+x[419]+x[420]-382*b[587] <= 0.0)
@constraint(m, e274, x[421]+x[422]+x[423]+x[424]+x[425]+x[426]+x[427]+x[428]+x[429]+x[430]+x[431]+x[432]-424*b[588] <= 0.0)
@constraint(m, e275, x[433]+x[434]+x[435]+x[436]+x[437]+x[438]+x[439]+x[440]+x[441]+x[442]+x[443]+x[444]-119*b[589] <= 0.0)
@constraint(m, e276, x[445]+x[446]+x[447]+x[448]+x[449]+x[450]+x[451]+x[452]+x[453]+x[454]+x[455]+x[456]-193*b[590] <= 0.0)
@constraint(m, e277, x[457]+x[458]+x[459]+x[460]+x[461]+x[462]+x[463]+x[464]+x[465]+x[466]+x[467]+x[468]-222*b[591] <= 0.0)
@constraint(m, e278, x[469]+x[470]+x[471]+x[472]+x[473]+x[474]+x[475]+x[476]+x[477]+x[478]+x[479]+x[480]-382*b[592] <= 0.0)
@constraint(m, e279, x[481]+x[482]+x[483]+x[484]+x[485]+x[486]+x[487]+x[488]+x[489]+x[490]+x[491]+x[492]-275*b[593] <= 0.0)
@constraint(m, e280, x[493]+x[494]+x[495]+x[496]+x[497]+x[498]+x[499]+x[500]+x[501]+x[502]+x[503]+x[504]-337*b[594] <= 0.0)
@constraint(m, e281, x[505]+x[506]+x[507]+x[508]+x[509]+x[510]+x[511]+x[512]+x[513]+x[514]+x[515]+x[516]-398*b[595] <= 0.0)
@constraint(m, e282, x[517]+x[518]+x[519]+x[520]+x[521]+x[522]+x[523]+x[524]+x[525]+x[526]+x[527]+x[528]-196*b[596] <= 0.0)
@constraint(m, e283, x[529]+x[530]+x[531]+x[532]+x[533]+x[534]+x[535]+x[536]+x[537]+x[538]+x[539]+x[540]-424*b[597] <= 0.0)
@constraint(m, e284, x[541]+x[542]+x[543]+x[544]+x[545]+x[546]+x[547]+x[548]+x[549]+x[550]+x[551]+x[552]-275*b[598] <= 0.0)

# ----- Objective ----- #
@objective(m, Min, objvar)

return m
end


using ALifeBenchmark
import SharedArrays.SharedArray
using Plots
using Random
using Serialization
import Base.Threads.@threads
using StringDistances: Levenshtein
using Measures
using LightGraphs

function plot_result(times, values, name, trial_id)
    plot(times, values,
            title = "",
            label = "",
            xguide = "Time",
            yguide = name,
            seriestype = :scatter,
            markersize = 1.5,
            markerstrokewidth = 0,
            size = (900, 600),
            margin = 10mm,
            dpi = 1000)
    savefig("$name$trial_id.svg")
end

function plot_result(times_1, times_2, values, name, trial_id)
    plot(times_1, times_2,
            marker_z  = values,
            title = "",
            label = "",
            xguide = "Time",
            yguide = name,
            seriestype = :scatter,
            markersize = 3,
            markerstrokewidth = 0,
            size = (900, 600),
            margin = 10mm,
            dpi = 1000)
    savefig("$name$trial_id")
end

function save_result(data, name, trial_id)
    serialize("$name$trial_id", data)
end

function collect_basic_statistic(abbrevation, trial_id, get_statistic)
    collect_compare_to_end_statistic(abbrevation, trial_id, (x, _) -> get_statistic(x), identity)
end

function collect_compare_to_end_statistic(abbrevation, trial_id, get_statistic, prepare)
    @info "Start $abbrevation"

    snapshot_ids = get_snapshot_ids(trial_id)
    num_snapshots = length(snapshot_ids)

    prepared_last = last(snapshot_ids) |> get_snapshot |> prepare

    values = SharedArray{Float64}(num_snapshots)
    times = SharedArray{UInt64}(num_snapshots)

    done = Threads.Atomic{Int}(0)

    @threads for (i, snapshot_id) in (shuffle(snapshot_ids) |> enumerate |> unique)
        snapshot = get_snapshot(snapshot_id)
        prepared = prepare(snapshot)

        current_value = get_statistic(prepared, prepared_last)
        current_time = get_time(snapshot)

        values[i] = current_value
        times[i] = current_time

        Threads.atomic_add!(done, 1)
        @info "$abbrevation \t $(done[] / num_snapshots) \t $current_time \t $current_value"

        if done[] % 100 == 0
            # plot_result(Array(times), Array(values), abbrevation, trial_id)
            # save_result((Array(times), Array(values)), abbrevation, trial_id)
        end
    end

    return (Array(times), Array(values))
end

function collect_cross_statistic(abbrevation, trial_id, get_statistic, prepare)
    @info "Start $abbrevation"

    snapshot_ids = get_snapshot_ids(trial_id)
    num_snapshots = length(snapshot_ids)

    values = SharedArray{Float64}(num_snapshots^2)
    times_1 = SharedArray{UInt64}(num_snapshots^2)
    times_2 = SharedArray{UInt64}(num_snapshots^2)

    done = Threads.Atomic{Int}(0)

    @threads for (i, snapshot_id_1) in (shuffle(snapshot_ids[1:5:end]) |> enumerate |> unique)
        snapshot_1 = get_snapshot(snapshot_id_1)
        prepared_1 = prepare(snapshot_1)
        time_1 = get_time(snapshot_1)

        for (j, snapshot_id_2) in (shuffle(snapshot_ids[1:5:end]) |> enumerate |> unique)
            snapshot_2 = get_snapshot(snapshot_id_2)
            prepared_2 = prepare(snapshot_2)
            time_2 = get_time(snapshot_2)

            current_value = get_statistic(prepared_1, prepared_2)

            index = (i-1)*num_snapshots + j

            values[index] = current_value
            times_1[index] = time_1
            times_2[index] = time_2

            Threads.atomic_add!(done, 1)

            if done[] % 1000 == 0
                @info "$abbrevation \t $(done[] / num_snapshots / num_snapshots) \t $time_1 \t $time_2 \t $current_value"
            end

            if done[] % 100_000 == 0
                plot_result(Array(times_1), Array(times_2), Array(values), abbrevation, trial_id)
                save_result((Array(times_1), Array(times_2), Array(values)), abbrevation, trial_id)
            end
        end
    end

    return (Array(times_1), Array(times_2), Array(values))
end

"""
Build Cache
"""
phenotype_cache = Dict()
graph_data = load_graph_data()

for edge in edges(graph_data.phenotype_graph)
    u, v = src(edge), dst(edge)
    genotype_u, genotype_v = graph_data.genotype_vertex_mapping(u), graph_data.genotype_vertex_mapping(v)

    phenotype_similarity = edge.weight
    phenotype_cache[(genotype_u, genotype_v)] = phenotype_similarity
    phenotype_cache[(genotype_v, genotype_u)] = phenotype_similarity
end

"""
COLLECT STATISTIC
"""

if length(ARGS) == 2
    trial_id, type_of_analysis = ARGS
    threshold = 0.001
    min_samples, max_samples = 50, 500
elseif length(ARGS) == 5
    trial_id, type_of_analysis, threshold, min_samples, max_samples = ARGS
    threshold = parse(Float64, threshold)
    min_samples = parse(Int, min_samples)
    max_samples = parse(Int, max_samples)
else
    trial_id = "12433992799852588"
    type_of_analysis = "LA"
    threshold = 0.001
    min_samples, max_samples = 50, 500
end

@info ARGS

if type_of_analysis == "LA"
    result = collect_compare_to_end_statistic(
        type_of_analysis,
        trial_id,
        (snapshot, last_snapshot) -> get_adaption_of_snapshot(last_snapshot, snapshot, threshold, min_samples, max_samples),
        identity
    )

elseif type_of_analysis == "RF"
    result = collect_basic_statistic(type_of_analysis, trial_id, snapshot -> get_reachable_fitness(snapshot, threshold, min_samples, max_samples))

elseif type_of_analysis == "RD"
    result = collect_basic_statistic(type_of_analysis, trial_id, snapshot -> get_reachable_diversity(snapshot, threshold, min_samples, max_samples))

elseif type_of_analysis == "PD"
    result = collect_compare_to_end_statistic(
        type_of_analysis,
        trial_id,
        (distribution, last_distribution) -> _wasserstein(last_distribution, distribution, Levenshtein()),
        get_genotype_distribution
    )

elseif type_of_analysis == "EP"
    result = collect_basic_statistic(type_of_analysis, trial_id, snapshot -> get_evolutionary_potential(snapshot, 600_000, threshold, min_samples, max_samples))

elseif type_of_analysis == "CPD"
    result = collect_cross_statistic(
        type_of_analysis,
        trial_id,
        (distribution_1, distribution_2) -> _wasserstein(distribution_1, distribution_2, Levenshtein()),
        get_genotype_distribution
    )

elseif type_of_analysis == "CLA"
    result = collect_cross_statistic(
        type_of_analysis,
        trial_id,
        (snapshot_1, snapshot_2) -> get_adaption_of_snapshot(snapshot_1, snapshot_2, threshold, min_samples, max_samples),
        identity
    )

elseif type_of_analysis == "ENT"
    result = collect_basic_statistic(type_of_analysis, trial_id, get_entropy)

elseif type_of_analysis == "GD"
    result = collect_basic_statistic(type_of_analysis, trial_id, snapshot -> get_genotype_diversity(snapshot, Levenshtein(), threshold, min_samples, max_samples))

elseif type_of_analysis == "PHD"
    result = collect_basic_statistic(type_of_analysis, trial_id, snapshot -> get_phenotype_diversity(snapshot, threshold, min_samples, max_samples))

elseif type_of_analysis == "NN"
    result = collect_basic_statistic(type_of_analysis, trial_id, snapshot -> get_neutrality(snapshot, 1e-5, phenotype_cache))

elseif type_of_analysis == "NullNN"
    result = collect_basic_statistic(type_of_analysis, trial_id, snapshot -> get_neutrality_null_model(snapshot, 1e-5, phenotype_cache))

end

plot_result(result..., type_of_analysis, trial_id)
save_result(result, type_of_analysis, trial_id)