diff --git a/Manifest.toml b/Manifest.toml index ac742b0..32e8807 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -10,10 +10,10 @@ uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" version = "0.5.0" [[BinaryProvider]] -deps = ["Libdl", "SHA"] -git-tree-sha1 = "5b08ed6036d9d3f0ee6369410b830f8873d4024c" +deps = ["Libdl", "Logging", "SHA"] +git-tree-sha1 = "428e9106b1ff27593cbd979afac9b45b82372b8c" uuid = "b99e7846-7c00-51b0-8f62-c81ae34c0232" -version = "0.5.8" +version = "0.5.9" [[Bzip2_jll]] deps = ["Libdl", "Pkg"] @@ -29,15 +29,15 @@ version = "0.5.1" [[Cbc]] deps = ["BinaryProvider", "Libdl", "MathOptInterface", "MathProgBase", "SparseArrays", "Test"] -git-tree-sha1 = "0d51c2d66fc22e5e3fc64b6092ba0f0b3839c8c1" +git-tree-sha1 = "62d80f448b5d77b3f0a59cecf6197aad2a3aa280" uuid = "9961bab8-2fa3-5c5a-9d89-47fab24efd76" -version = "0.6.6" +version = "0.6.7" [[CodeTracking]] deps = ["InteractiveUtils", "UUIDs"] -git-tree-sha1 = "0becdab7e6fbbcb7b88d8de5b72e5bb2f28239f3" +git-tree-sha1 = "cab4da992adc0a64f63fa30d2db2fd8bec40cab4" uuid = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" -version = "0.5.8" +version = "0.5.11" [[CodecBzip2]] deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"] @@ -71,9 +71,9 @@ version = "0.5.1" [[DataStructures]] deps = ["InteractiveUtils", "OrderedCollections"] -git-tree-sha1 = "73eb18320fe3ba58790c8b8f6f89420f0a622773" +git-tree-sha1 = "6166ecfaf2b8bbf2b68d791bc1d54501f345d314" uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.17.11" +version = "0.17.15" [[Dates]] deps = ["Printf"] @@ -112,9 +112,9 @@ version = "0.5.0" [[HTTP]] deps = ["Base64", "Dates", "IniFile", "MbedTLS", "Sockets"] -git-tree-sha1 = "cd60d9a575d3b70c026d7e714212fd4ecf86b4bb" +git-tree-sha1 = "fe31f4ff144392ad8176f5c7c03cca6ba320271c" uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" -version = "0.8.13" +version = "0.8.14" [[IniFile]] deps = ["Test"] @@ -140,17 +140,18 @@ version = "0.2.0" [[JuMP]] deps = ["Calculus", "DataStructures", "ForwardDiff", "LinearAlgebra", "MathOptInterface", "MutableArithmetics", "NaNMath", "Random", "SparseArrays", "Statistics"] -git-tree-sha1 = "8e87337fd19b6717fd9d5324bfab99848e363d9f" +git-tree-sha1 = "84c1cf8bec4729b8b2ef4dfc4e1db1b892ad0d30" uuid = "4076af6c-e467-56ae-b986-b466b2749572" -version = "0.21.1" +version = "0.21.2" [[JuliaInterpreter]] deps = ["CodeTracking", "InteractiveUtils", "Random", "UUIDs"] -git-tree-sha1 = "2eadbbde5534346cbb837c3a75b377cba477a06d" +git-tree-sha1 = "dda48f397146fcd0b520c38a17a749e0f890ab84" uuid = "aa1ae85d-cabe-5617-a682-6adf51b2e16a" -version = "0.7.13" +version = "0.7.14" [[LibGit2]] +deps = ["Printf"] uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" [[Libdl]] @@ -165,9 +166,9 @@ uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" [[LoweredCodeUtils]] deps = ["JuliaInterpreter"] -git-tree-sha1 = "1c41621653250b2824b6e664ac5bd805558aeff9" +git-tree-sha1 = "695206e7ec13cbec6e6ee4d19af7464e80f4d1ad" uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b" -version = "0.4.3" +version = "0.4.4" [[Markdown]] deps = ["Base64"] @@ -187,15 +188,15 @@ version = "0.7.8" [[MbedTLS]] deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"] -git-tree-sha1 = "a9e2221f06b42f56052f43ad7edecb01d0ef5ab4" +git-tree-sha1 = "426a6978b03a97ceb7ead77775a1da066343ec6e" uuid = "739be429-bea8-5141-9913-cc70e7f3736d" -version = "1.0.1" +version = "1.0.2" [[MbedTLS_jll]] deps = ["Libdl", "Pkg"] -git-tree-sha1 = "066a4467008745eed36dad973ceb66405785a621" +git-tree-sha1 = "c83f5a1d038f034ad0549f9ee4d5fac3fb429e33" uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" -version = "2.16.0+1" +version = "2.16.0+2" [[Mmap]] uuid = "a63ad114-7e13-5084-954f-fe012c677804" @@ -225,12 +226,12 @@ version = "1.1.0" [[Parsers]] deps = ["Dates", "Test"] -git-tree-sha1 = "75d07cb840c300084634b4991761886d0d762724" +git-tree-sha1 = "f8f5d2d4b4b07342e5811d2b6428e45524e241df" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "1.0.1" +version = "1.0.2" [[Pkg]] -deps = ["Dates", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Test", "UUIDs"] +deps = ["Dates", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "UUIDs"] uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" [[Printf]] @@ -239,9 +240,9 @@ uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" [[ProgressBars]] deps = ["Printf"] -git-tree-sha1 = "e66732bbdaad368cfc642cef1f639df5812dc818" +git-tree-sha1 = "fec529e15cccf342087de2ccda1b0b9064cbbb53" uuid = "49802e3a-d2f1-5c88-81d8-b72133a6f568" -version = "0.6.0" +version = "0.7.1" [[REPL]] deps = ["InteractiveUtils", "Markdown", "Sockets"] @@ -253,9 +254,9 @@ uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [[Revise]] deps = ["CodeTracking", "Distributed", "FileWatching", "JuliaInterpreter", "LibGit2", "LoweredCodeUtils", "OrderedCollections", "Pkg", "REPL", "UUIDs", "Unicode"] -git-tree-sha1 = "3c04c929f8720c2fabb12534cd102a2356a7705c" +git-tree-sha1 = "9e544fcbf1bcf394c01dca39c40f299a4d0f6441" uuid = "295af30f-e4ad-537b-8983-00126c2a3abe" -version = "2.5.4" +version = "2.6.5" [[Rotations]] deps = ["LinearAlgebra", "StaticArrays", "Statistics"] @@ -284,9 +285,9 @@ version = "0.10.0" [[StaticArrays]] deps = ["LinearAlgebra", "Random", "Statistics"] -git-tree-sha1 = "5a3bcb6233adabde68ebc97be66e95dcb787424c" +git-tree-sha1 = "5c06c0aeb81bef54aed4b3f446847905eb6cbda0" uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "0.12.1" +version = "0.12.3" [[Statistics]] deps = ["LinearAlgebra", "SparseArrays"] diff --git a/src/instance.jl b/src/instance.jl index 9b073ff..634b0e7 100644 --- a/src/instance.jl +++ b/src/instance.jl @@ -4,17 +4,59 @@ using Printf, JSON, JSONSchema import Base.getindex, Base.time -""" - mutable struct ReverseManufacturingInstance -Representation of an instance of the Facility Location for Reverse Manufacturing problem. -""" +struct Product + name::String + transportation_cost::Float64 +end + + +struct CollectionCenter + name::String + latitude::Float64 + longitude::Float64 + product::Product + amount::Float64 +end + + +struct DisposalEntry + product::Product + cost::Float64 + limit::Float64 +end + + +struct Plant + name::String + input::Product + output::Dict{Product, Float64} + latitude::Float64 + longitude::Float64 + variable_operating_cost::Float64 + fixed_operating_cost::Float64 + opening_cost::Float64 + base_capacity::Float64 + max_capacity::Float64 + expansion_cost::Float64 + disposal::Array{DisposalEntry} +end + + +struct Instance + products::Array{Product, 1} + collection_centers::Array{CollectionCenter, 1} + plants::Array{Plant, 1} +end + + mutable struct ReverseManufacturingInstance json::Dict products::Dict plants::Dict end + function Base.show(io::IO, instance::ReverseManufacturingInstance) n_plants = length(instance["plants"]) n_products = length(instance["products"]) @@ -23,34 +65,103 @@ function Base.show(io::IO, instance::ReverseManufacturingInstance) print(io, "$n_products products") end -""" - load(name::String)::ReverseManufacturingInstance - -Loads an instance from the benchmark set. - -Example -======= - - julia> ReverseManufacturing.load("samples/s1.json") -""" -function load(name::String) :: ReverseManufacturingInstance +function load(path::String)::Instance basedir = dirname(@__FILE__) - return ReverseManufacturing.readfile("$basedir/../instances/$name.json") + json = JSON.parsefile(path) + schema = Schema(JSON.parsefile("$basedir/schemas/input.json")) + + validation_results = JSONSchema.validate(json, schema) + if validation_results !== nothing + println(validation_results) + throw("Invalid input file") + end + + products = Product[] + collection_centers = CollectionCenter[] + plants = Plant[] + + product_name_to_product = Dict{String, Product}() + + # Create products + for (product_name, product_dict) in json["products"] + product = Product(product_name, product_dict["transportation cost"]) + push!(products, product) + product_name_to_product[product_name] = product + + # Create collection centers + if "initial amounts" in keys(product_dict) + for (center_name, center_dict) in product_dict["initial amounts"] + center = CollectionCenter(center_name, + center_dict["latitude"], + center_dict["longitude"], + product, + center_dict["amount"]) + push!(collection_centers, center) + end + end + end + + # Create plants + for (plant_name, plant_dict) in json["plants"] + input = product_name_to_product[plant_dict["input"]] + output = Dict() + + # Plant outputs + if "outputs" in keys(plant_dict) + output = Dict(product_name_to_product[key] => value + for (key, value) in plant_dict["outputs"] + if value > 0) + end + + for (location_name, location_dict) in plant_dict["locations"] + disposal = DisposalEntry[] + + # Plant disposal + if "disposal" in keys(location_dict) + for (product_name, disposal_dict) in location_dict["disposal"] + push!(disposal, DisposalEntry(product_name_to_product[product_name], + disposal_dict["cost"], + disposal_dict["limit"])) + end + end + + base_capacity = Inf + max_capacity = Inf + expansion_cost = 0 + + if "base capacity" in keys(location_dict) + base_capacity = location_dict["base capacity"] + end + + if "max capacity" in keys(location_dict) + max_capacity = location_dict["max capacity"] + end + + if "expansion cost" in keys(location_dict) + expansion_cost = location_dict["expansion cost"] + end + + plant = Plant(location_name, + input, + output, + location_dict["latitude"], + location_dict["longitude"], + location_dict["variable operating cost"], + location_dict["fixed operating cost"], + location_dict["opening cost"], + base_capacity, + max_capacity, + expansion_cost, + disposal) + push!(plants, plant) + end + end + + return Instance(products, collection_centers, plants) end -""" - readfile(path::String)::ReverseManufacturingInstance - -Loads an instance from the given JSON file. - -Example -======= - - julia> ReverseManufacturing.load("/home/user/instance.json") - -""" function readfile(path::String)::ReverseManufacturingInstance basedir = dirname(@__FILE__) json = JSON.parsefile(path) @@ -105,4 +216,5 @@ function readfile(path::String)::ReverseManufacturingInstance return ReverseManufacturingInstance(json, products, plants) end + export ReverseManufacturingInstance diff --git a/test/instance_test.jl b/test/instance_test.jl index f991fe4..3d5a134 100644 --- a/test/instance_test.jl +++ b/test/instance_test.jl @@ -4,15 +4,62 @@ using ReverseManufacturing @testset "Instance" begin - instance = ReverseManufacturing.load("samples/s1") - plants, products = instance.plants, instance.products - @test length(products) == 4 - - @test sort(collect(keys(plants))) == ["F1", "F2", "F3", "F4"] - @test plants["F1"]["input product"] == products["P1"] - - @test sort(collect(keys(products))) == ["P1", "P2", "P3", "P4"] - @test products["P1"]["input plants"] == [plants["F1"]] - @test products["P1"]["transportation cost"] == 0.015 - @test products["P1"]["initial amounts"]["C1"]["latitude"] == 7.0 + @testset "load" begin + basedir = dirname(@__FILE__) + instance = ReverseManufacturing.load("$basedir/../instances/samples/s1.json") + + centers = instance.collection_centers + plants = instance.plants + products = instance.products + + plant_name_to_plant = Dict(p.name => p for p in plants) + product_name_to_product = Dict(p.name => p for p in products) + + p2 = product_name_to_product["P2"] + p3 = product_name_to_product["P3"] + + @test length(centers) == 10 + @test centers[1].name == "C1" + @test centers[1].latitude == 7 + @test centers[1].latitude == 7 + @test centers[1].longitude == 7 + @test centers[1].amount == 934.56 + @test centers[1].product.name == "P1" + + @test length(plants) == 6 + + plant = plant_name_to_plant["L1"] + @test plant.name == "L1" + @test plant.input.name == "P1" + @test plant.latitude == 0 + @test plant.longitude == 0 + @test plant.opening_cost == 500 + @test plant.fixed_operating_cost == 30 + @test plant.variable_operating_cost == 30 + @test plant.base_capacity == 250 + @test plant.max_capacity == 1000 + @test plant.expansion_cost == 1 + + @test length(plant.output) == 2 + @test plant.output[p2] == 0.2 + @test plant.output[p3] == 0.5 + + @test length(plant.disposal) == 2 + @test plant.disposal[1].product.name == "P2" + @test plant.disposal[1].cost == -10 + @test plant.disposal[1].limit == 1 + + plant = plant_name_to_plant["L3"] + @test plant.name == "L3" + @test plant.input.name == "P2" + @test plant.latitude == 25 + @test plant.longitude == 65 + @test plant.opening_cost == 3000 + @test plant.fixed_operating_cost == 50 + @test plant.variable_operating_cost == 50 + @test plant.base_capacity == Inf + @test plant.max_capacity == Inf + @test plant.expansion_cost == 0 + end end + diff --git a/test/runtests.jl b/test/runtests.jl index b4e56e7..87113d7 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,5 +5,5 @@ using Test @testset "ReverseManufacturing" begin include("instance_test.jl") - include("model_test.jl") + #include("model_test.jl") end \ No newline at end of file