You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
3.2 KiB
115 lines
3.2 KiB
# 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 Distributed
|
|
|
|
|
|
struct LearningSolver
|
|
py::PyCall.PyObject
|
|
optimizer_factory
|
|
end
|
|
|
|
|
|
function LearningSolver(
|
|
optimizer_factory;
|
|
components = nothing,
|
|
mode::AbstractString = "exact",
|
|
simulate_perfect::Bool = false,
|
|
solve_lp::Bool = true,
|
|
)::LearningSolver
|
|
return LearningSolver(
|
|
miplearn.LearningSolver(
|
|
solver=JuMPSolver(optimizer_factory),
|
|
mode=mode,
|
|
solve_lp=solve_lp,
|
|
simulate_perfect=simulate_perfect,
|
|
components=components,
|
|
),
|
|
optimizer_factory,
|
|
)
|
|
end
|
|
|
|
|
|
function solve!(
|
|
solver::LearningSolver,
|
|
instance::Instance;
|
|
tee::Bool = false,
|
|
)
|
|
return @python_call solver.py.solve(instance.py, tee=tee)
|
|
end
|
|
|
|
|
|
function fit!(solver::LearningSolver, instances::Vector{<:Instance})
|
|
@python_call solver.py.fit([instance.py for instance in instances])
|
|
end
|
|
|
|
|
|
function parallel_solve!(solver::LearningSolver, instances::Vector{FileInstance})
|
|
filenames = [instance.filename for instance in instances]
|
|
solver_filename = tempname()
|
|
save(solver_filename, solver)
|
|
@sync @distributed for filename in filenames
|
|
s = load_solver(solver_filename)
|
|
solve!(s, FileInstance(filename))
|
|
nothing
|
|
end
|
|
end
|
|
|
|
|
|
function save(filename::AbstractString, solver::LearningSolver)
|
|
@info "Writing: $filename"
|
|
time = @elapsed begin
|
|
# Pickle solver.py
|
|
internal_solver = solver.py.internal_solver
|
|
internal_solver_prototype = solver.py.internal_solver_prototype
|
|
solver.py.internal_solver = nothing
|
|
solver.py.internal_solver_prototype = nothing
|
|
solver_py_filename = tempname()
|
|
miplearn.write_pickle_gz(solver.py, solver_py_filename, quiet=true)
|
|
solver_py = read(solver_py_filename)
|
|
solver.py.internal_solver = internal_solver
|
|
solver.py.internal_solver_prototype = internal_solver_prototype
|
|
|
|
jldsave(
|
|
filename;
|
|
miplearn_version="0.2",
|
|
solver_py=solver_py,
|
|
optimizer_factory=solver.optimizer_factory,
|
|
)
|
|
end
|
|
@info @sprintf("File written in %.2f seconds", time)
|
|
return
|
|
end
|
|
|
|
|
|
function load_solver(filename::AbstractString)::LearningSolver
|
|
@info "Reading: $filename"
|
|
solver = nothing
|
|
time = @elapsed begin
|
|
jldopen(filename, "r") do file
|
|
_check_miplearn_version(file)
|
|
solve_py_filename = tempname()
|
|
write(solve_py_filename, file["solver_py"])
|
|
solver_py = miplearn.read_pickle_gz(solve_py_filename, quiet=true)
|
|
internal_solver = JuMPSolver(file["optimizer_factory"])
|
|
solver_py.internal_solver_prototype = internal_solver
|
|
solver = LearningSolver(
|
|
solver_py,
|
|
file["optimizer_factory"],
|
|
)
|
|
end
|
|
end
|
|
@info @sprintf("File read in %.2f seconds", time)
|
|
return solver
|
|
end
|
|
|
|
|
|
export Instance,
|
|
LearningSolver,
|
|
solve!,
|
|
fit!,
|
|
parallel_solve!,
|
|
save,
|
|
load_solver
|