mirror of
https://github.com/ANL-CEEESA/MIPLearn.jl.git
synced 2025-12-06 08:28:52 -06:00
Use HDF5 for instance files
This commit is contained in:
@@ -11,6 +11,7 @@ Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d"
|
|||||||
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
|
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
|
||||||
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
|
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
|
||||||
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
|
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
|
||||||
|
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
|
||||||
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
|
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
|
||||||
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
|
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
|
||||||
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
|
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
|
||||||
|
|||||||
@@ -147,14 +147,14 @@ for i in 1:600
|
|||||||
@feature(...)
|
@feature(...)
|
||||||
@category(...)
|
@category(...)
|
||||||
|
|
||||||
# Save instances to a file
|
# Save instances to file
|
||||||
instance = JuMPInstance(m)
|
instance = JuMPInstance(m)
|
||||||
save("instance-$i.bin", instance)
|
save("instance-$i.h5", instance)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Initialize training and test instances
|
# Initialize training and test instances
|
||||||
training_instances = [FileInstance("instance-$i.bin") for i in 1:500]
|
training_instances = [FileInstance("instance-$i.h5") for i in 1:500]
|
||||||
test_instances = [FileInstance("instance-$i.bin") for i in 501:600]
|
test_instances = [FileInstance("instance-$i.h5") for i in 501:600]
|
||||||
|
|
||||||
# Initialize solver
|
# Initialize solver
|
||||||
solver = LearningSolver(Cbc.Optimizer)
|
solver = LearningSolver(Cbc.Optimizer)
|
||||||
|
|||||||
@@ -8,10 +8,13 @@ mutable struct FileInstance <: Instance
|
|||||||
py::Union{Nothing,PyCall.PyObject}
|
py::Union{Nothing,PyCall.PyObject}
|
||||||
loaded::Union{Nothing, JuMPInstance}
|
loaded::Union{Nothing, JuMPInstance}
|
||||||
filename::AbstractString
|
filename::AbstractString
|
||||||
|
h5::PyCall.PyObject
|
||||||
|
|
||||||
function FileInstance(filename::String)::FileInstance
|
function FileInstance(filename::AbstractString)::FileInstance
|
||||||
instance = new(nothing, nothing, filename)
|
instance = new(nothing, nothing, filename)
|
||||||
instance.py = PyFileInstance(instance)
|
instance.py = PyFileInstance(instance)
|
||||||
|
instance.h5 = Hdf5Sample(filename)
|
||||||
|
instance.filename = filename
|
||||||
return instance
|
return instance
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -21,8 +24,14 @@ get_instance_features(instance::FileInstance) = get_instance_features(instance.l
|
|||||||
get_variable_features(instance::FileInstance) = get_variable_features(instance.loaded)
|
get_variable_features(instance::FileInstance) = get_variable_features(instance.loaded)
|
||||||
get_variable_categories(instance::FileInstance) = get_variable_categories(instance.loaded)
|
get_variable_categories(instance::FileInstance) = get_variable_categories(instance.loaded)
|
||||||
get_constraint_features(instance::FileInstance) = get_constraint_features(instance.loaded)
|
get_constraint_features(instance::FileInstance) = get_constraint_features(instance.loaded)
|
||||||
get_samples(instance::FileInstance) = get_samples(instance.loaded)
|
|
||||||
create_sample!(instance::FileInstance) = create_sample!(instance.loaded)
|
function get_samples(instance::FileInstance)
|
||||||
|
return [instance.h5]
|
||||||
|
end
|
||||||
|
|
||||||
|
function create_sample!(instance::FileInstance)
|
||||||
|
return instance.h5
|
||||||
|
end
|
||||||
|
|
||||||
function get_constraint_categories(instance::FileInstance)
|
function get_constraint_categories(instance::FileInstance)
|
||||||
return get_constraint_categories(instance.loaded)
|
return get_constraint_categories(instance.loaded)
|
||||||
@@ -41,7 +50,6 @@ function free(instance::FileInstance)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function flush(instance::FileInstance)
|
function flush(instance::FileInstance)
|
||||||
save(instance.filename, instance.loaded)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function __init_PyFileInstance__()
|
function __init_PyFileInstance__()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
# Released under the modified BSD license. See COPYING.md for more details.
|
# Released under the modified BSD license. See COPYING.md for more details.
|
||||||
|
|
||||||
using JuMP
|
using JuMP
|
||||||
using JLD2
|
import JSON
|
||||||
|
|
||||||
mutable struct JuMPInstance <: Instance
|
mutable struct JuMPInstance <: Instance
|
||||||
py::Union{Nothing,PyCall.PyObject}
|
py::Union{Nothing,PyCall.PyObject}
|
||||||
@@ -75,42 +75,31 @@ function save(filename::AbstractString, instance::JuMPInstance)::Nothing
|
|||||||
write_to_file(model, mps_filename)
|
write_to_file(model, mps_filename)
|
||||||
mps = read(mps_filename)
|
mps = read(mps_filename)
|
||||||
|
|
||||||
# Pickle instance.py.samples. Ideally, we would use dumps and loads, but this
|
# Generate HDF5
|
||||||
# causes some issues with PyCall, probably due to automatic type conversions.
|
h5 = Hdf5Sample(filename, mode="w")
|
||||||
samples_filename = tempname()
|
h5.put_scalar("miplearn_version", "0002")
|
||||||
miplearn.write_pickle_gz(instance.samples, samples_filename)
|
h5.put_bytes("mps", mps)
|
||||||
samples = read(samples_filename)
|
h5.put_scalar("jump_ext", JSON.json(model.ext[:miplearn]))
|
||||||
|
|
||||||
# Generate JLD2 file
|
|
||||||
jldsave(
|
|
||||||
filename;
|
|
||||||
miplearn_version="0.2",
|
|
||||||
mps=mps,
|
|
||||||
ext=model.ext[:miplearn],
|
|
||||||
samples=samples,
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
function _check_miplearn_version(file)
|
function _check_miplearn_version(h5)
|
||||||
v = file["miplearn_version"]
|
v = h5.get_scalar("miplearn_version")
|
||||||
v == "0.2" || error(
|
v == "0002" || error(
|
||||||
"The file you are trying to load has been generated by " *
|
"The file you are trying to load has been generated by " *
|
||||||
"MIPLearn $(v) and you are currently running MIPLearn 0.2. " *
|
"MIPLearn $(v) and you are currently running MIPLearn 0002 " *
|
||||||
"Reading files generated by different versions of MIPLearn is " *
|
"Reading files generated by different versions of MIPLearn is " *
|
||||||
"not currently supported."
|
"not currently supported."
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
function load_instance(filename::AbstractString)::JuMPInstance
|
function load_instance(filename::AbstractString)::JuMPInstance
|
||||||
jldopen(filename, "r") do file
|
h5 = Hdf5Sample(filename)
|
||||||
_check_miplearn_version(file)
|
_check_miplearn_version(h5)
|
||||||
instance = JuMPInstance(file["mps"], file["ext"])
|
mps = h5.get_bytes("mps")
|
||||||
samples_filename = tempname()
|
ext = h5.get_scalar("jump_ext")
|
||||||
write(samples_filename, file["samples"])
|
instance = JuMPInstance(Vector{UInt8}(mps), JSON.parse(ext))
|
||||||
instance.samples = miplearn.read_pickle_gz(samples_filename)
|
return instance
|
||||||
return instance
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
export JuMPInstance, save, load_instance
|
export JuMPInstance, save, load_instance
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
# Released under the modified BSD license. See COPYING.md for more details.
|
# Released under the modified BSD license. See COPYING.md for more details.
|
||||||
|
|
||||||
using Distributed
|
using Distributed
|
||||||
|
using JLD2
|
||||||
|
|
||||||
|
|
||||||
struct LearningSolver
|
struct LearningSolver
|
||||||
@@ -117,7 +118,6 @@ end
|
|||||||
|
|
||||||
function load_solver(filename::AbstractString)::LearningSolver
|
function load_solver(filename::AbstractString)::LearningSolver
|
||||||
jldopen(filename, "r") do file
|
jldopen(filename, "r") do file
|
||||||
_check_miplearn_version(file)
|
|
||||||
solve_py_filename = tempname()
|
solve_py_filename = tempname()
|
||||||
write(solve_py_filename, file["solver_py"])
|
write(solve_py_filename, file["solver_py"])
|
||||||
solver_py = miplearn.read_pickle_gz(solve_py_filename)
|
solver_py = miplearn.read_pickle_gz(solve_py_filename)
|
||||||
|
|||||||
@@ -14,11 +14,15 @@ using Cbc
|
|||||||
filename = tempname()
|
filename = tempname()
|
||||||
save(filename, instance)
|
save(filename, instance)
|
||||||
|
|
||||||
|
h5 = MIPLearn.Hdf5Sample(filename)
|
||||||
|
@test h5.get_scalar("miplearn_version") == "0002"
|
||||||
|
@test length(h5.get_bytes("mps")) > 0
|
||||||
|
@test length(h5.get_scalar("jump_ext")) > 0
|
||||||
|
|
||||||
file_instance = FileInstance(filename)
|
file_instance = FileInstance(filename)
|
||||||
solver = LearningSolver(Cbc.Optimizer)
|
solver = LearningSolver(Cbc.Optimizer)
|
||||||
solve!(solver, file_instance)
|
solve!(solver, file_instance)
|
||||||
|
|
||||||
loaded = load_instance(filename)
|
@test length(h5.get_vector("mip_var_values")) == 3
|
||||||
@test length(loaded.samples) == 1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ MIPLearn.setup_logger()
|
|||||||
|
|
||||||
@testset "MIPLearn" begin
|
@testset "MIPLearn" begin
|
||||||
include("fixtures/knapsack.jl")
|
include("fixtures/knapsack.jl")
|
||||||
|
include("instance/file_test.jl")
|
||||||
include("solvers/jump_test.jl")
|
include("solvers/jump_test.jl")
|
||||||
include("solvers/learning_test.jl")
|
include("solvers/learning_test.jl")
|
||||||
include("instance/file_test.jl")
|
|
||||||
include("utils/benchmark_test.jl")
|
include("utils/benchmark_test.jl")
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user