|
|
@ -11,39 +11,33 @@ mutable struct ReverseManufacturingModel
|
|
|
|
process_nodes
|
|
|
|
process_nodes
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
mutable struct Node
|
|
|
|
abstract type Node
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mutable struct ProcessNode <: Node
|
|
|
|
product_name::String
|
|
|
|
product_name::String
|
|
|
|
plant_name::String
|
|
|
|
plant_name::String
|
|
|
|
location_name::String
|
|
|
|
location_name::String
|
|
|
|
balance::Float64
|
|
|
|
|
|
|
|
incoming_arcs::Array
|
|
|
|
incoming_arcs::Array
|
|
|
|
outgoing_arcs::Array
|
|
|
|
outgoing_arcs::Array
|
|
|
|
cost::Float64
|
|
|
|
fixed_cost::Float64
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Node(product_name::String,
|
|
|
|
mutable struct ShippingNode <: Node
|
|
|
|
plant_name::String,
|
|
|
|
product_name::String
|
|
|
|
location_name::String;
|
|
|
|
plant_name::String
|
|
|
|
balance::Float64 = 0.0,
|
|
|
|
location_name::String
|
|
|
|
incoming_arcs::Array = [],
|
|
|
|
incoming_arcs::Array
|
|
|
|
outgoing_arcs::Array = [],
|
|
|
|
outgoing_arcs::Array
|
|
|
|
cost::Float64 = 0.0,
|
|
|
|
balance::Float64
|
|
|
|
) :: Node
|
|
|
|
|
|
|
|
return Node(product_name,
|
|
|
|
|
|
|
|
plant_name,
|
|
|
|
|
|
|
|
location_name,
|
|
|
|
|
|
|
|
balance,
|
|
|
|
|
|
|
|
incoming_arcs,
|
|
|
|
|
|
|
|
outgoing_arcs,
|
|
|
|
|
|
|
|
cost)
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Base.show(io::IO, node::Node)
|
|
|
|
function Base.show(io::IO, node::ProcessNode)
|
|
|
|
print(io, "Node($(node.product_name), $(node.plant_name), $(node.location_name)")
|
|
|
|
print(io, "ProcessNode($(node.product_name), $(node.plant_name), $(node.location_name), $(node.fixed_cost))")
|
|
|
|
if node.balance != 0.0
|
|
|
|
|
|
|
|
print(io, ", $(node.balance)")
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
print(io, ")")
|
|
|
|
|
|
|
|
|
|
|
|
function Base.show(io::IO, node::ShippingNode)
|
|
|
|
|
|
|
|
print(io, "ShippingNode($(node.product_name), $(node.plant_name), $(node.location_name), $(node.balance))")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
mutable struct Arc
|
|
|
|
mutable struct Arc
|
|
|
@ -92,7 +86,7 @@ function build_model(instance::ReverseManufacturingInstance,
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
for n in tqdm(values(process_nodes))
|
|
|
|
for n in tqdm(values(process_nodes))
|
|
|
|
add_to_expression!(obj, n.cost, vars.node[n])
|
|
|
|
add_to_expression!(obj, n.fixed_cost, vars.node[n])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
@objective(mip, Min, obj)
|
|
|
|
@objective(mip, Min, obj)
|
|
|
|
|
|
|
|
|
|
|
@ -138,7 +132,7 @@ function create_nodes_and_arcs(instance)
|
|
|
|
if haskey(product, "initial amounts")
|
|
|
|
if haskey(product, "initial amounts")
|
|
|
|
for location_name in keys(product["initial amounts"])
|
|
|
|
for location_name in keys(product["initial amounts"])
|
|
|
|
amount = product["initial amounts"][location_name]["amount"]
|
|
|
|
amount = product["initial amounts"][location_name]["amount"]
|
|
|
|
n = Node(product_name, "Origin", location_name, balance=amount)
|
|
|
|
n = ShippingNode(product_name, "Origin", location_name, [], [], amount)
|
|
|
|
shipping_nodes[n.product_name, n.plant_name, n.location_name] = n
|
|
|
|
shipping_nodes[n.product_name, n.plant_name, n.location_name] = n
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
@ -147,7 +141,7 @@ function create_nodes_and_arcs(instance)
|
|
|
|
for plant in product["input plants"]
|
|
|
|
for plant in product["input plants"]
|
|
|
|
for (location_name, location) in plant["locations"]
|
|
|
|
for (location_name, location) in plant["locations"]
|
|
|
|
cost = location["opening cost"] + location["fixed operating cost"]
|
|
|
|
cost = location["opening cost"] + location["fixed operating cost"]
|
|
|
|
n = Node(product_name, plant["name"], location_name, cost=cost)
|
|
|
|
n = ProcessNode(product_name, plant["name"], location_name, [], [], cost)
|
|
|
|
process_nodes[n.product_name, n.plant_name, n.location_name] = n
|
|
|
|
process_nodes[n.product_name, n.plant_name, n.location_name] = n
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
@ -155,7 +149,7 @@ function create_nodes_and_arcs(instance)
|
|
|
|
# Shipping nodes for each plant
|
|
|
|
# Shipping nodes for each plant
|
|
|
|
for plant in product["output plants"]
|
|
|
|
for plant in product["output plants"]
|
|
|
|
for location_name in keys(plant["locations"])
|
|
|
|
for location_name in keys(plant["locations"])
|
|
|
|
n = Node(product_name, plant["name"], location_name)
|
|
|
|
n = ShippingNode(product_name, plant["name"], location_name, [], [], 0)
|
|
|
|
shipping_nodes[n.product_name, n.plant_name, n.location_name] = n
|
|
|
|
shipping_nodes[n.product_name, n.plant_name, n.location_name] = n
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
@ -288,7 +282,7 @@ function get_solution(instance::ReverseManufacturingInstance,
|
|
|
|
"longitude" => location["longitude"],
|
|
|
|
"longitude" => location["longitude"],
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
plant_loc_dict["fixed cost"] = round(vals[process_node] * process_node.cost, digits=5)
|
|
|
|
plant_loc_dict["fixed cost"] = round(vals[process_node] * process_node.fixed_cost, digits=5)
|
|
|
|
output["costs"]["fixed"] += plant_loc_dict["fixed cost"]
|
|
|
|
output["costs"]["fixed"] += plant_loc_dict["fixed cost"]
|
|
|
|
|
|
|
|
|
|
|
|
# Inputs
|
|
|
|
# Inputs
|
|
|
|