mirror of https://github.com/ANL-CEEESA/RELOG.git
parent
4947ad1a8a
commit
0da66b571a
@ -1,7 +1,8 @@
|
||||
module RELOG
|
||||
|
||||
include("instance/structs.jl")
|
||||
|
||||
include("instance/parse.jl")
|
||||
include("model/jumpext.jl")
|
||||
include("model/build.jl")
|
||||
|
||||
end # module RELOG
|
||||
|
@ -0,0 +1,95 @@
|
||||
using JuMP
|
||||
|
||||
function build_model(instance::Instance; optimizer, variable_names::Bool = false)
|
||||
model = JuMP.Model(optimizer)
|
||||
centers = instance.centers
|
||||
products = instance.products
|
||||
plants = instance.plants
|
||||
T = 1:instance.time_horizon
|
||||
|
||||
# Transportation edges
|
||||
# -------------------------------------------------------------------------
|
||||
E = []
|
||||
for m in products
|
||||
for p1 in plants
|
||||
m ∉ keys(p1.output) || continue
|
||||
|
||||
# Plant to plant
|
||||
for p2 in plants
|
||||
p1 != p2 || continue
|
||||
m ∉ keys(p2.input_mix) || continue
|
||||
push!(E, (p1, p2, m))
|
||||
end
|
||||
|
||||
# Plant to center
|
||||
for c in centers
|
||||
m == c.input || continue
|
||||
push!(E, (p1, c, m))
|
||||
end
|
||||
end
|
||||
|
||||
for c1 in centers
|
||||
m ∈ c1.outputs || continue
|
||||
|
||||
# Center to plant
|
||||
for p in plants
|
||||
m ∈ keys(p.input_mix) || continue
|
||||
push!(E, (c1, p, m))
|
||||
end
|
||||
|
||||
# Center to center
|
||||
for c2 in centers
|
||||
m == c2.input || continue
|
||||
push!(E, (c1, c2, m))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Decision variables
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# Plant p is operational at time t
|
||||
x = _init(model, :x)
|
||||
for p in plants, t in T
|
||||
x[p.name, t] = @variable(model, binary = true)
|
||||
end
|
||||
|
||||
# Amount of product m sent from center/plant u to center/plant v at time T
|
||||
y = _init(model, :y)
|
||||
for (p1, p2, m) in E, t in T
|
||||
y[p1.name, p2.name, m.name, t] = @variable(model, lower_bound=0)
|
||||
end
|
||||
|
||||
# Amount of product m produced by plant/center at time T
|
||||
z_prod = _init(model, :z_prod)
|
||||
for p in plants, m in keys(p.output), t in T
|
||||
z_prod[p.name, m.name, t] = @variable(model, lower_bound=0)
|
||||
end
|
||||
for c in centers, m in c.outputs, t in T
|
||||
z_prod[c.name, m.name, t] = @variable(model, lower_bound=0)
|
||||
end
|
||||
|
||||
# Amount of product m disposed at plant/center p at time T
|
||||
z_disp = _init(model, :z_disp)
|
||||
for p in plants, m in keys(p.output), t in T
|
||||
z_disp[p.name, m.name, t] = @variable(model, lower_bound=0)
|
||||
end
|
||||
for c in centers, m in c.outputs, t in T
|
||||
z_disp[c.name, m.name, t] = @variable(model, lower_bound=0)
|
||||
end
|
||||
|
||||
|
||||
# Objective function
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Constraints
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
|
||||
if variable_names
|
||||
_set_names!(model)
|
||||
end
|
||||
return model
|
||||
end
|
@ -0,0 +1,47 @@
|
||||
# This file extends some JuMP functions so that decision variables can be safely
|
||||
# replaced by (constant) floating point numbers.
|
||||
|
||||
using Printf
|
||||
using JuMP
|
||||
|
||||
import JuMP: value, fix, set_name
|
||||
|
||||
function value(x::Float64)
|
||||
return x
|
||||
end
|
||||
|
||||
function fix(x::Float64, v::Float64; force)
|
||||
return abs(x - v) < 1e-6 || error("Value mismatch: $x != $v")
|
||||
end
|
||||
|
||||
function set_name(x::Float64, n::String)
|
||||
# nop
|
||||
end
|
||||
|
||||
function _init(model::JuMP.Model, key::Symbol)::OrderedDict
|
||||
if !(key in keys(object_dictionary(model)))
|
||||
model[key] = OrderedDict()
|
||||
end
|
||||
return model[key]
|
||||
end
|
||||
|
||||
function _set_names!(model::JuMP.Model)
|
||||
@info "Setting variable and constraint names..."
|
||||
time_varnames = @elapsed begin
|
||||
_set_names!(object_dictionary(model))
|
||||
end
|
||||
@info @sprintf("Set names in %.2f seconds", time_varnames)
|
||||
end
|
||||
|
||||
function _set_names!(dict::Dict)
|
||||
for name in keys(dict)
|
||||
dict[name] isa AbstractDict || continue
|
||||
for idx in keys(dict[name])
|
||||
if dict[name][idx] isa AffExpr
|
||||
continue
|
||||
end
|
||||
idx_str = join(map(string, idx), ",")
|
||||
set_name(dict[name][idx], "$name[$idx_str]")
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,10 @@
|
||||
using RELOG
|
||||
using Test
|
||||
using HiGHS
|
||||
using JuMP
|
||||
|
||||
function model_build_test()
|
||||
instance = RELOG.parsefile(fixture("simple.json"))
|
||||
model = RELOG.build_model(instance, optimizer=HiGHS.Optimizer, variable_names=true)
|
||||
print(model)
|
||||
end
|
Loading…
Reference in new issue