diff --git a/Manifest.toml b/Manifest.toml index 6b961e3..d0b125a 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -21,6 +21,12 @@ git-tree-sha1 = "c3598e525718abcc440f69cc6d5f60dda0a1b61e" uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" version = "1.0.6+5" +[[CSV]] +deps = ["Dates", "Mmap", "Parsers", "PooledArrays", "SentinelArrays", "Tables", "Unicode"] +git-tree-sha1 = "b83aa3f513be680454437a0eee21001607e5d983" +uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +version = "0.8.5" + [[Calculus]] deps = ["LinearAlgebra"] git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad" @@ -67,12 +73,33 @@ git-tree-sha1 = "299304989a5e6473d985212c28928899c74e9421" uuid = "8f4d0f93-b110-5947-807f-2305c1781a2d" version = "1.5.2" +[[Crayons]] +git-tree-sha1 = "3f71217b538d7aaee0b69ab47d9b7724ca8afa0d" +uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" +version = "4.0.4" + +[[DataAPI]] +git-tree-sha1 = "dfb3b7e89e395be1e25c2ad6d7690dc29cc53b1d" +uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" +version = "1.6.0" + +[[DataFrames]] +deps = ["Compat", "DataAPI", "Future", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrettyTables", "Printf", "REPL", "Reexport", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"] +git-tree-sha1 = "66ee4fe515a9294a8836ef18eea7239c6ac3db5e" +uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +version = "1.1.1" + [[DataStructures]] deps = ["Compat", "InteractiveUtils", "OrderedCollections"] git-tree-sha1 = "4437b64df1e0adccc3e5d1adbc3ac741095e4677" uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" version = "0.18.9" +[[DataValueInterfaces]] +git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" +uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" +version = "1.0.0" + [[Dates]] deps = ["Printf"] uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" @@ -107,12 +134,22 @@ git-tree-sha1 = "cfb694feaddf4f0381ef3cc9d4c0d8fc6b7e2ea7" uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" version = "1.9.0" +[[Formatting]] +deps = ["Printf"] +git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" +uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" +version = "0.4.2" + [[ForwardDiff]] deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "NaNMath", "Printf", "Random", "SpecialFunctions", "StaticArrays"] git-tree-sha1 = "e2af66012e08966366a43251e1fd421522908be6" uuid = "f6369f11-7733-5829-9624-2563aa707210" version = "0.10.18" +[[Future]] +deps = ["Random"] +uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" + [[HTTP]] deps = ["Base64", "Dates", "IniFile", "MbedTLS", "NetworkOptions", "Sockets", "URIs"] git-tree-sha1 = "b855bf8247d6e946c75bb30f593bfe7fe591058d" @@ -129,6 +166,17 @@ version = "0.5.0" deps = ["Markdown"] uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" +[[InvertedIndices]] +deps = ["Test"] +git-tree-sha1 = "15732c475062348b0165684ffe28e85ea8396afc" +uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" +version = "1.0.0" + +[[IteratorInterfaceExtensions]] +git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" +uuid = "82899510-4779-5014-852e-03e436cf321d" +version = "1.0.0" + [[JLD2]] deps = ["DataStructures", "FileIO", "MacroTools", "Mmap", "Pkg", "Printf", "Reexport", "TranscodingStreams", "UUIDs"] git-tree-sha1 = "236b8ca4b8f01ebc6f2fceedf344a077f0e69e79" @@ -211,6 +259,12 @@ version = "1.0.3" deps = ["Artifacts", "Libdl"] uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +[[Missings]] +deps = ["DataAPI"] +git-tree-sha1 = "4ea90bd5d3985ae1f9a908bd4500ae88921c5ce7" +uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" +version = "1.0.0" + [[Mmap]] uuid = "a63ad114-7e13-5084-954f-fe012c677804" @@ -252,12 +306,24 @@ version = "1.1.0" deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +[[PooledArrays]] +deps = ["DataAPI", "Future"] +git-tree-sha1 = "cde4ce9d6f33219465b55162811d8de8139c0414" +uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" +version = "1.2.1" + [[Preferences]] deps = ["TOML"] git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a" uuid = "21216c6a-2e73-6563-6e65-726566657250" version = "1.2.2" +[[PrettyTables]] +deps = ["Crayons", "Formatting", "Markdown", "Reexport", "Tables"] +git-tree-sha1 = "b60494adf99652d220cdef46f8a32232182cc22d" +uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" +version = "1.0.1" + [[Printf]] deps = ["Unicode"] uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" @@ -290,6 +356,12 @@ version = "1.1.3" [[SHA]] uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +[[SentinelArrays]] +deps = ["Dates", "Random"] +git-tree-sha1 = "2ce5f07bbc1be0a1b5d5c0e281441d3bf8a7a2e5" +uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c" +version = "1.3.0" + [[Serialization]] uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" @@ -300,6 +372,12 @@ uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" [[Sockets]] uuid = "6462fe0b-24de-5631-8697-dd941f90decc" +[[SortingAlgorithms]] +deps = ["DataStructures"] +git-tree-sha1 = "2ec1962eba973f383239da22e75218565c390a96" +uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" +version = "1.0.0" + [[SparseArrays]] deps = ["LinearAlgebra", "Random"] uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" @@ -324,6 +402,18 @@ uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" deps = ["Dates"] uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +[[TableTraits]] +deps = ["IteratorInterfaceExtensions"] +git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" +uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" +version = "1.0.1" + +[[Tables]] +deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"] +git-tree-sha1 = "c9d2d262e9a327be1f35844df25fe4561d258dc9" +uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +version = "1.4.2" + [[Tar]] deps = ["ArgTools", "SHA"] uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" diff --git a/Project.toml b/Project.toml index 6e1bf52..6be3fd3 100644 --- a/Project.toml +++ b/Project.toml @@ -4,7 +4,9 @@ authors = ["Alinson S Xavier "] version = "0.2.0" [deps] +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d" +DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b" JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" JuMP = "4076af6c-e467-56ae-b986-b466b2749572" diff --git a/src/MIPLearn.jl b/src/MIPLearn.jl index 4957a9e..17319b2 100644 --- a/src/MIPLearn.jl +++ b/src/MIPLearn.jl @@ -17,5 +17,20 @@ include("instance/file.jl") include("solvers/jump.jl") include("solvers/learning.jl") include("solvers/macros.jl") +include("utils/benchmark.jl") + +DynamicLazyConstraintsComponent = miplearn.DynamicLazyConstraintsComponent +UserCutsComponent = miplearn.UserCutsComponent +ObjectiveValueComponent = miplearn.ObjectiveValueComponent +PrimalSolutionComponent = miplearn.PrimalSolutionComponent +StaticLazyConstraintsComponent = miplearn.StaticLazyConstraintsComponent +MinPrecisionThreshold = miplearn.MinPrecisionThreshold + +export DynamicLazyConstraintsComponent, + UserCutsComponent, + ObjectiveValueComponent, + PrimalSolutionComponent, + StaticLazyConstraintsComponent, + MinPrecisionThreshold end # module diff --git a/src/solvers/learning.jl b/src/solvers/learning.jl index 9bcc3b6..66609a8 100644 --- a/src/solvers/learning.jl +++ b/src/solvers/learning.jl @@ -11,10 +11,21 @@ struct LearningSolver end -function LearningSolver(optimizer_factory)::LearningSolver - py = miplearn.LearningSolver(solver=JuMPSolver(optimizer_factory)) +function LearningSolver( + optimizer_factory; + components = nothing, + mode::AbstractString = "exact", + simulate_perfect::Bool = false, + solve_lp::Bool = true, +)::LearningSolver return LearningSolver( - py, + miplearn.LearningSolver( + solver=JuMPSolver(optimizer_factory), + mode=mode, + solve_lp=solve_lp, + simulate_perfect=simulate_perfect, + components=components, + ), optimizer_factory, ) end @@ -36,7 +47,6 @@ end function parallel_solve!(solver::LearningSolver, instances::Vector{FileInstance}) filenames = [instance.filename for instance in instances] - optimizer_factory = solver.optimizer_factory solver_filename = tempname() save(solver_filename, solver) @sync @distributed for filename in filenames diff --git a/src/utils/benchmark.jl b/src/utils/benchmark.jl new file mode 100644 index 0000000..02f26ac --- /dev/null +++ b/src/utils/benchmark.jl @@ -0,0 +1,68 @@ +# MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization +# Copyright (C) 2020-2021, UChicago Argonne, LLC. All rights reserved. +# Released under the modified BSD license. See COPYING.md for more details. + +using CSV +using DataFrames + + +mutable struct BenchmarkRunner + solvers::Dict + results::Union{Nothing,DataFrame} +end + + +function BenchmarkRunner(; solvers::Dict) + return BenchmarkRunner( + solvers, + nothing, # results + ) +end + + +function parallel_solve!( + runner::BenchmarkRunner, + instances::Vector{FileInstance}; + n_trials::Int = 3, +)::Nothing + for (solver_name, solver) in runner.solvers + for i in 1:n_trials + for instance in instances + stats = solve!(solver, instance) + stats["Solver"] = solver_name + stats = Dict(k => isnothing(v) ? missing : v for (k, v) in stats) + if runner.results === nothing + runner.results = DataFrame(stats) + else + push!(runner.results, stats, cols=:union) + end + end + end + end +end + + +function fit!( + runner::BenchmarkRunner, + instances::Vector{FileInstance} +)::Nothing + for (solver_name, solver) in runner.solvers + fit!(solver, instances) + end +end + + +function write_csv!( + runner::BenchmarkRunner, + filename::AbstractString, +)::Nothing + @info "Writing: $filename" + CSV.write(filename, runner.results) + return +end + + +export BenchmarkRunner, + parallel_solve!, + fit!, + write_csv! diff --git a/test/Manifest.toml b/test/Manifest.toml deleted file mode 100644 index c1717b5..0000000 --- a/test/Manifest.toml +++ /dev/null @@ -1,421 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -[[ArgTools]] -uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" - -[[Artifacts]] -uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" - -[[Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" - -[[BenchmarkTools]] -deps = ["JSON", "Logging", "Printf", "Statistics", "UUIDs"] -git-tree-sha1 = "9e62e66db34540a0c919d72172cc2f642ac71260" -uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" -version = "0.5.0" - -[[BinaryProvider]] -deps = ["Libdl", "Logging", "SHA"] -git-tree-sha1 = "ecdec412a9abc8db54c0efc5548c64dfce072058" -uuid = "b99e7846-7c00-51b0-8f62-c81ae34c0232" -version = "0.5.10" - -[[Bzip2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "c3598e525718abcc440f69cc6d5f60dda0a1b61e" -uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" -version = "1.0.6+5" - -[[CEnum]] -git-tree-sha1 = "215a9aa4a1f23fbd05b92769fdd62559488d70e9" -uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" -version = "0.4.1" - -[[Calculus]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad" -uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9" -version = "0.5.1" - -[[Cbc]] -deps = ["BinaryProvider", "CEnum", "Cbc_jll", "Libdl", "MathOptInterface", "SparseArrays"] -git-tree-sha1 = "8da071e2f96de95decbd551d54db9ac82c0bf4f6" -uuid = "9961bab8-2fa3-5c5a-9d89-47fab24efd76" -version = "0.8.0" - -[[Cbc_jll]] -deps = ["Artifacts", "Cgl_jll", "Clp_jll", "CoinUtils_jll", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "OpenBLAS32_jll", "Osi_jll", "Pkg"] -git-tree-sha1 = "5d24ea46edebb4f067b180cfc092a45d4d2c48b3" -uuid = "38041ee0-ae04-5750-a4d2-bb4d0d83d27d" -version = "2.10.5+2" - -[[Cgl_jll]] -deps = ["Artifacts", "Clp_jll", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "0c41f887cca7e95e7ca1cda5bd6e82e6f43b317d" -uuid = "3830e938-1dd0-5f3e-8b8e-b3ee43226782" -version = "0.60.2+6" - -[[ChainRulesCore]] -deps = ["Compat", "LinearAlgebra", "SparseArrays"] -git-tree-sha1 = "44e9f638aa9ed1ad58885defc568c133010140aa" -uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "0.9.37" - -[[Clp_jll]] -deps = ["Artifacts", "CoinUtils_jll", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "OpenBLAS32_jll", "Osi_jll", "Pkg"] -git-tree-sha1 = "d9eca9fa2435959b5542b13409a8ec5f64c947c8" -uuid = "06985876-5285-5a41-9fcb-8948a742cc53" -version = "1.17.6+7" - -[[CodecBzip2]] -deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"] -git-tree-sha1 = "2e62a725210ce3c3c2e1a3080190e7ca491f18d7" -uuid = "523fee87-0ab8-5b00-afb7-3ecf72e48cfd" -version = "0.7.2" - -[[CodecZlib]] -deps = ["TranscodingStreams", "Zlib_jll"] -git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da" -uuid = "944b1d66-785c-5afd-91f1-9de20f533193" -version = "0.7.0" - -[[CoinUtils_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "OpenBLAS32_jll", "Pkg"] -git-tree-sha1 = "5186155a8609b71eae7e104fa2b8fbf6ecd5d9bb" -uuid = "be027038-0da8-5614-b30d-e42594cb92df" -version = "2.11.3+4" - -[[CommonSubexpressions]] -deps = ["MacroTools", "Test"] -git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" -uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" -version = "0.3.0" - -[[Compat]] -deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] -git-tree-sha1 = "ac4132ad78082518ec2037ae5770b6e796f7f956" -uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "3.27.0" - -[[CompilerSupportLibraries_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" - -[[Conda]] -deps = ["JSON", "VersionParsing"] -git-tree-sha1 = "6231e40619c15148bcb80aa19d731e629877d762" -uuid = "8f4d0f93-b110-5947-807f-2305c1781a2d" -version = "1.5.1" - -[[DataStructures]] -deps = ["Compat", "InteractiveUtils", "OrderedCollections"] -git-tree-sha1 = "4437b64df1e0adccc3e5d1adbc3ac741095e4677" -uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.18.9" - -[[Dates]] -deps = ["Printf"] -uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" - -[[DelimitedFiles]] -deps = ["Mmap"] -uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" - -[[DiffResults]] -deps = ["StaticArrays"] -git-tree-sha1 = "c18e98cba888c6c25d1c3b048e4b3380ca956805" -uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" -version = "1.0.3" - -[[DiffRules]] -deps = ["NaNMath", "Random", "SpecialFunctions"] -git-tree-sha1 = "214c3fcac57755cfda163d91c58893a8723f93e9" -uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" -version = "1.0.2" - -[[Distributed]] -deps = ["Random", "Serialization", "Sockets"] -uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" - -[[Downloads]] -deps = ["ArgTools", "LibCURL", "NetworkOptions"] -uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" - -[[ForwardDiff]] -deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "NaNMath", "Printf", "Random", "SpecialFunctions", "StaticArrays"] -git-tree-sha1 = "e2af66012e08966366a43251e1fd421522908be6" -uuid = "f6369f11-7733-5829-9624-2563aa707210" -version = "0.10.18" - -[[HTTP]] -deps = ["Base64", "Dates", "IniFile", "MbedTLS", "NetworkOptions", "Sockets", "URIs"] -git-tree-sha1 = "c9f380c76d8aaa1fa7ea9cf97bddbc0d5b15adc2" -uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" -version = "0.9.5" - -[[IniFile]] -deps = ["Test"] -git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8" -uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f" -version = "0.5.0" - -[[InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" - -[[JLLWrappers]] -git-tree-sha1 = "a431f5f2ca3f4feef3bd7a5e94b8b8d4f2f647a0" -uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" -version = "1.2.0" - -[[JSON]] -deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "81690084b6198a2e1da36fcfda16eeca9f9f24e4" -uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.1" - -[[JSON2]] -deps = ["Dates", "Parsers", "Test"] -git-tree-sha1 = "66397cc6c08922f98a28ab05a8d3002f9853b129" -uuid = "2535ab7d-5cd8-5a07-80ac-9b1792aadce3" -version = "0.3.2" - -[[JSONSchema]] -deps = ["HTTP", "JSON", "ZipFile"] -git-tree-sha1 = "b84ab8139afde82c7c65ba2b792fe12e01dd7307" -uuid = "7d188eb4-7ad8-530c-ae41-71a32a6d4692" -version = "0.3.3" - -[[JuMP]] -deps = ["Calculus", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MathOptInterface", "MutableArithmetics", "NaNMath", "Random", "SparseArrays", "SpecialFunctions", "Statistics"] -git-tree-sha1 = "e952f49e2242fa21edcf27bbd6c67041685bee5d" -uuid = "4076af6c-e467-56ae-b986-b466b2749572" -version = "0.21.6" - -[[LibCURL]] -deps = ["LibCURL_jll", "MozillaCACerts_jll"] -uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" - -[[LibCURL_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] -uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" - -[[LibGit2]] -deps = ["Base64", "NetworkOptions", "Printf", "SHA"] -uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" - -[[LibSSH2_jll]] -deps = ["Artifacts", "Libdl", "MbedTLS_jll"] -uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" - -[[Libdl]] -uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" - -[[LinearAlgebra]] -deps = ["Libdl"] -uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" - -[[Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - -[[MIPLearn]] -deps = ["Conda", "JSON2", "JuMP", "Logging", "MathOptInterface", "PackageCompiler", "Printf", "PyCall", "TimerOutputs"] -git-tree-sha1 = "86a0bef09e21ec65ee5becf7d662315bb325b1c6" -uuid = "2b1277c3-b477-4c49-a15e-7ba350325c68" -version = "0.1.0" - -[[MacroTools]] -deps = ["Markdown", "Random"] -git-tree-sha1 = "6a8a2a625ab0dea913aba95c11370589e0239ff0" -uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" -version = "0.5.6" - -[[Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" - -[[MathOptInterface]] -deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "JSON", "JSONSchema", "LinearAlgebra", "MutableArithmetics", "OrderedCollections", "SparseArrays", "Test", "Unicode"] -git-tree-sha1 = "606efe4246da5407d7505265a1ead72467528996" -uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" -version = "0.9.20" - -[[MbedTLS]] -deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"] -git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe" -uuid = "739be429-bea8-5141-9913-cc70e7f3736d" -version = "1.0.3" - -[[MbedTLS_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" - -[[Mmap]] -uuid = "a63ad114-7e13-5084-954f-fe012c677804" - -[[MozillaCACerts_jll]] -uuid = "14a3606d-f60d-562e-9121-12d972cd8159" - -[[MutableArithmetics]] -deps = ["LinearAlgebra", "SparseArrays", "Test"] -git-tree-sha1 = "ff3aa3e4dbc837f80c2031de2f90125c8b3793f3" -uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" -version = "0.2.15" - -[[NaNMath]] -git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb" -uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" -version = "0.3.5" - -[[NetworkOptions]] -uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" - -[[OpenBLAS32_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "ba4a8f683303c9082e84afba96f25af3c7fb2436" -uuid = "656ef2d0-ae68-5445-9ca0-591084a874a2" -version = "0.3.12+1" - -[[OpenSpecFun_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "9db77584158d0ab52307f8c04f8e7c08ca76b5b3" -uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" -version = "0.5.3+4" - -[[OrderedCollections]] -git-tree-sha1 = "4fa2ba51070ec13fcc7517db714445b4ab986bdf" -uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -version = "1.4.0" - -[[Osi_jll]] -deps = ["Artifacts", "CoinUtils_jll", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "OpenBLAS32_jll", "Pkg"] -git-tree-sha1 = "ef540e28c9b82cb879e33c0885e1bbc9a1e6c571" -uuid = "7da25872-d9ce-5375-a4d3-7a845f58efdd" -version = "0.108.5+4" - -[[PackageCompiler]] -deps = ["Libdl", "Pkg", "UUIDs"] -git-tree-sha1 = "d448727c4b86be81b225b738c88d30334fda6779" -uuid = "9b87118b-4619-50d2-8e1e-99f35a4d4d9d" -version = "1.2.5" - -[[Parsers]] -deps = ["Dates"] -git-tree-sha1 = "c8abc88faa3f7a3950832ac5d6e690881590d6dc" -uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "1.1.0" - -[[Pkg]] -deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] -uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" - -[[Printf]] -deps = ["Unicode"] -uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" - -[[PyCall]] -deps = ["Conda", "Dates", "Libdl", "LinearAlgebra", "MacroTools", "Serialization", "VersionParsing"] -git-tree-sha1 = "dd1a970b543bd02efce2984582e996af28cab27f" -uuid = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" -version = "1.92.2" - -[[REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] -uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" - -[[Random]] -deps = ["Serialization"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" - -[[Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" - -[[SharedArrays]] -deps = ["Distributed", "Mmap", "Random", "Serialization"] -uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" - -[[Sockets]] -uuid = "6462fe0b-24de-5631-8697-dd941f90decc" - -[[SparseArrays]] -deps = ["LinearAlgebra", "Random"] -uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - -[[SpecialFunctions]] -deps = ["ChainRulesCore", "OpenSpecFun_jll"] -git-tree-sha1 = "5919936c0e92cff40e57d0ddf0ceb667d42e5902" -uuid = "276daf66-3868-5448-9aa4-cd146d93841b" -version = "1.3.0" - -[[StaticArrays]] -deps = ["LinearAlgebra", "Random", "Statistics"] -git-tree-sha1 = "2f01a51c23eed210ff4a1be102c4cc8236b66e5b" -uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "1.1.0" - -[[Statistics]] -deps = ["LinearAlgebra", "SparseArrays"] -uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" - -[[TOML]] -deps = ["Dates"] -uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" - -[[Tar]] -deps = ["ArgTools", "SHA"] -uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" - -[[Test]] -deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[TimerOutputs]] -deps = ["Printf"] -git-tree-sha1 = "32cdbe6cd2d214c25a0b88f985c9e0092877c236" -uuid = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" -version = "0.5.8" - -[[TranscodingStreams]] -deps = ["Random", "Test"] -git-tree-sha1 = "7c53c35547de1c5b9d46a4797cf6d8253807108c" -uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" -version = "0.9.5" - -[[URIs]] -git-tree-sha1 = "7855809b88d7b16e9b029afd17880930626f54a2" -uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" -version = "1.2.0" - -[[UUIDs]] -deps = ["Random", "SHA"] -uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" - -[[Unicode]] -uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" - -[[VersionParsing]] -git-tree-sha1 = "80229be1f670524750d905f8fc8148e5a8c4537f" -uuid = "81def892-9a0e-5fdd-b105-ffc91e053289" -version = "1.2.0" - -[[ZipFile]] -deps = ["Libdl", "Printf", "Zlib_jll"] -git-tree-sha1 = "c3a5637e27e914a7a445b8d0ad063d701931e9f7" -uuid = "a5390f91-8eb1-5f08-bee0-b1d1ffed6cea" -version = "0.9.3" - -[[Zlib_jll]] -deps = ["Libdl"] -uuid = "83775a58-1f1d-513f-b197-d71354ab007a" - -[[nghttp2_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" - -[[p7zip_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" diff --git a/test/Project.toml b/test/Project.toml index 5cf0f13..64b0bac 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -15,3 +15,5 @@ Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" diff --git a/test/fixtures/knapsack.jl b/test/fixtures/knapsack.jl new file mode 100644 index 0000000..3bc2803 --- /dev/null +++ b/test/fixtures/knapsack.jl @@ -0,0 +1,50 @@ +# MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization +# Copyright (C) 2020-2021, UChicago Argonne, LLC. All rights reserved. +# Released under the modified BSD license. See COPYING.md for more details. + +using JuMP +using MIPLearn + + +function build_knapsack_model() + # Create standard JuMP model + weights = [1.0, 2.0, 3.0] + prices = [5.0, 6.0, 7.0] + capacity = 3.0 + model = Model() + + n = length(weights) + @variable(model, x[1:n], Bin) + @objective(model, Max, sum(x[i] * prices[i] for i in 1:n)) + @constraint(model, c1, sum(x[i] * weights[i] for i in 1:n) <= capacity) + + # Add ML information to the model + @feature(model, [5.0]) + @feature(c1, [1.0, 2.0, 3.0]) + @category(c1, "c1") + for i in 1:n + @feature(x[i], [weights[i]; prices[i]]) + @category(x[i], "type-$i") + end + + # Should store ML information + @test model.ext[:miplearn][:variable_features][x[1]] == [1.0, 5.0] + @test model.ext[:miplearn][:variable_features][x[2]] == [2.0, 6.0] + @test model.ext[:miplearn][:variable_features][x[3]] == [3.0, 7.0] + @test model.ext[:miplearn][:variable_categories][x[1]] == "type-1" + @test model.ext[:miplearn][:variable_categories][x[2]] == "type-2" + @test model.ext[:miplearn][:variable_categories][x[3]] == "type-3" + @test model.ext[:miplearn][:constraint_features][c1] == [1.0, 2.0, 3.0] + @test model.ext[:miplearn][:constraint_categories][c1] == "c1" + @test model.ext[:miplearn][:instance_features] == [5.0] + + return model +end + +function build_knapsack_file_instance() + model = build_knapsack_model() + instance = JuMPInstance(model) + filename = tempname() + save(filename, instance) + return FileInstance(filename) +end diff --git a/test/instance/file_test.jl b/test/instance/file_test.jl index cf7031b..3279bb2 100644 --- a/test/instance/file_test.jl +++ b/test/instance/file_test.jl @@ -6,12 +6,10 @@ using JuMP using MIPLearn using Gurobi + @testset "FileInstance" begin @testset "solve" begin - model = Model() - @variable(model, x, Bin) - @variable(model, y, Bin) - @objective(model, Max, x + y) + model = build_knapsack_model() instance = JuMPInstance(model) filename = tempname() save(filename, instance) diff --git a/test/instance/jump_test.jl b/test/instance/jump_test.jl index b47eb0f..605b2a8 100644 --- a/test/instance/jump_test.jl +++ b/test/instance/jump_test.jl @@ -2,18 +2,13 @@ # Copyright (C) 2020-2021, UChicago Argonne, LLC. All rights reserved. # Released under the modified BSD license. See COPYING.md for more details. -@testset "JuMPInstance" begin - @testset "save and load" begin - # Create basic model - model = Model() - @variable(model, x, Bin) - @variable(model, y, Bin) - @objective(model, Max, x + y) - @feature(x, [1.0]) - @category(x, "cat1") - @feature(model, [5.0]) +using MIPLearn + - # Solve +@testset "JuMPInstance" begin + @testset "Save and load" begin + # Build instance and solve + model = model = build_knapsack_model() instance = JuMPInstance(model) solver = LearningSolver(Gurobi.Optimizer) stats = solve!(solver, instance) diff --git a/test/runtests.jl b/test/runtests.jl index a7fef64..0bf0662 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -8,7 +8,9 @@ using MIPLearn MIPLearn.setup_logger() @testset "MIPLearn" begin + include("fixtures/knapsack.jl") include("solvers/jump_test.jl") include("solvers/learning_test.jl") include("instance/file_test.jl") + include("utils/benchmark_test.jl") end diff --git a/test/solvers/learning_test.jl b/test/solvers/learning_test.jl index d2ff46a..675d079 100644 --- a/test/solvers/learning_test.jl +++ b/test/solvers/learning_test.jl @@ -8,37 +8,7 @@ using Gurobi @testset "LearningSolver" begin @testset "Model with annotations" begin - # Create standard JuMP model - weights = [1.0, 2.0, 3.0] - prices = [5.0, 6.0, 7.0] - capacity = 3.0 - model = Model() - - n = length(weights) - @variable(model, x[1:n], Bin) - @objective(model, Max, sum(x[i] * prices[i] for i in 1:n)) - @constraint(model, c1, sum(x[i] * weights[i] for i in 1:n) <= capacity) - - # Add ML information to the model - @feature(model, [5.0]) - @feature(c1, [1.0, 2.0, 3.0]) - @category(c1, "c1") - for i in 1:n - @feature(x[i], [weights[i]; prices[i]]) - @category(x[i], "type-$i") - end - - # Should store ML information - @test model.ext[:miplearn][:variable_features][x[1]] == [1.0, 5.0] - @test model.ext[:miplearn][:variable_features][x[2]] == [2.0, 6.0] - @test model.ext[:miplearn][:variable_features][x[3]] == [3.0, 7.0] - @test model.ext[:miplearn][:variable_categories][x[1]] == "type-1" - @test model.ext[:miplearn][:variable_categories][x[2]] == "type-2" - @test model.ext[:miplearn][:variable_categories][x[3]] == "type-3" - @test model.ext[:miplearn][:constraint_features][c1] == [1.0, 2.0, 3.0] - @test model.ext[:miplearn][:constraint_categories][c1] == "c1" - @test model.ext[:miplearn][:instance_features] == [5.0] - + model = build_knapsack_model() solver = LearningSolver(Gurobi.Optimizer) instance = JuMPInstance(model) stats = solve!(solver, instance) @@ -49,14 +19,11 @@ using Gurobi end @testset "Model without annotations" begin - model = Model() - @variable(model, x, Bin) - @variable(model, y, Bin) - @objective(model, Max, x + y) + model = build_knapsack_model() solver = LearningSolver(Gurobi.Optimizer) instance = JuMPInstance(model) stats = solve!(solver, instance) - @test stats["mip_lower_bound"] == 2.0 + @test stats["mip_lower_bound"] == 11.0 end @testset "Save and load" begin diff --git a/test/utils/benchmark_test.jl b/test/utils/benchmark_test.jl new file mode 100644 index 0000000..52cda27 --- /dev/null +++ b/test/utils/benchmark_test.jl @@ -0,0 +1,31 @@ +# MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization +# Copyright (C) 2020-2021, UChicago Argonne, LLC. All rights reserved. +# Released under the modified BSD license. See COPYING.md for more details. + +using CSV +using DataFrames +using Gurobi + + +@testset "BenchmarkRunner" begin + # Configure benchmark suite + benchmark = BenchmarkRunner( + solvers=Dict( + "Baseline" => LearningSolver(Gurobi.Optimizer, components=[]), + "Proposed" => LearningSolver(Gurobi.Optimizer), + ), + ) + + # Solve instances in parallel + instances = [ + build_knapsack_file_instance(), + build_knapsack_file_instance(), + ] + parallel_solve!(benchmark, instances) + + # Write CSV + csv_filename = tempname() + write_csv!(benchmark, csv_filename) + @test isfile(csv_filename) + csv = DataFrame(CSV.File(csv_filename)) +end