mirror of
https://github.com/ANL-CEEESA/MIPLearn.jl.git
synced 2025-12-06 16:38:51 -06:00
Rewrite FileInstance
This commit is contained in:
@@ -41,6 +41,8 @@ function _optimize_and_capture_output!(model; tee::Bool=false)
|
||||
rm(logname)
|
||||
if tee
|
||||
println(log)
|
||||
flush(stdout)
|
||||
Base.Libc.flush_cstdio()
|
||||
end
|
||||
return log
|
||||
end
|
||||
@@ -150,7 +152,7 @@ function build_test_instance_knapsack()
|
||||
@objective(model, Max, sum(x[i-1] * prices[i] for i in 1:n))
|
||||
@constraint(model, eq_capacity, sum(x[i-1] * weights[i] for i in 1:n) - z == 0)
|
||||
|
||||
return PyJuMPInstance(model)
|
||||
return JuMPInstance(model).py
|
||||
end
|
||||
|
||||
|
||||
@@ -159,7 +161,7 @@ function build_test_instance_infeasible()
|
||||
@variable(model, x, Bin)
|
||||
@objective(model, Max, x)
|
||||
@constraint(model, x >= 2)
|
||||
return PyJuMPInstance(model)
|
||||
return JuMPInstance(model).py
|
||||
end
|
||||
|
||||
|
||||
@@ -389,6 +391,8 @@ end
|
||||
function get_constraints(
|
||||
data::JuMPSolverData;
|
||||
with_static::Bool,
|
||||
with_sa::Bool,
|
||||
with_lhs::Bool,
|
||||
)
|
||||
names = []
|
||||
senses, lhs, rhs = nothing, nothing, nothing
|
||||
@@ -420,24 +424,26 @@ function get_constraints(
|
||||
|
||||
if with_static
|
||||
if ftype == JuMP.AffExpr
|
||||
push!(
|
||||
lhs,
|
||||
[
|
||||
(
|
||||
MOI.get(
|
||||
if with_lhs
|
||||
push!(
|
||||
lhs,
|
||||
[
|
||||
(
|
||||
MOI.get(
|
||||
constr.model.moi_backend,
|
||||
MOI.VariableName(),
|
||||
term.variable_index
|
||||
),
|
||||
term.coefficient,
|
||||
)
|
||||
for term in MOI.get(
|
||||
constr.model.moi_backend,
|
||||
MOI.VariableName(),
|
||||
term.variable_index
|
||||
),
|
||||
term.coefficient,
|
||||
)
|
||||
for term in MOI.get(
|
||||
constr.model.moi_backend,
|
||||
MOI.ConstraintFunction(),
|
||||
constr.index,
|
||||
).terms
|
||||
]
|
||||
)
|
||||
MOI.ConstraintFunction(),
|
||||
constr.index,
|
||||
).terms
|
||||
]
|
||||
)
|
||||
end
|
||||
if stype == MOI.EqualTo{Float64}
|
||||
push!(senses, "=")
|
||||
push!(rhs, cset.value)
|
||||
@@ -535,6 +541,8 @@ function __init_JuMPSolver__()
|
||||
) = get_constraints(
|
||||
self.data,
|
||||
with_static=with_static,
|
||||
with_sa=with_sa,
|
||||
with_lhs=with_lhs,
|
||||
)
|
||||
|
||||
get_constraint_attrs(self) = [
|
||||
|
||||
@@ -17,6 +17,8 @@ function LearningSolver(
|
||||
mode::AbstractString = "exact",
|
||||
simulate_perfect::Bool = false,
|
||||
solve_lp::Bool = true,
|
||||
extract_sa::Bool = true,
|
||||
extract_lhs::Bool = true,
|
||||
)::LearningSolver
|
||||
return LearningSolver(
|
||||
miplearn.LearningSolver(
|
||||
@@ -25,6 +27,8 @@ function LearningSolver(
|
||||
solve_lp=solve_lp,
|
||||
simulate_perfect=simulate_perfect,
|
||||
components=components,
|
||||
extract_lhs=extract_lhs,
|
||||
extract_sa=extract_sa,
|
||||
),
|
||||
optimizer_factory,
|
||||
)
|
||||
@@ -47,66 +51,83 @@ end
|
||||
|
||||
function fit!(solver::LearningSolver, instances::Vector{<:Instance})
|
||||
@python_call solver.py.fit([instance.py for instance in instances])
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
function parallel_solve!(solver::LearningSolver, instances::Vector{FileInstance})
|
||||
filenames = [instance.filename for instance in instances]
|
||||
function _solve(
|
||||
solver_filename,
|
||||
instance_filename;
|
||||
discard_output::Bool,
|
||||
)
|
||||
@info "solve $instance_filename"
|
||||
solver = load_solver(solver_filename)
|
||||
solver.py._silence_miplearn_logger()
|
||||
stats = solve!(
|
||||
solver,
|
||||
FileInstance(instance_filename),
|
||||
discard_output = discard_output,
|
||||
)
|
||||
solver.py._restore_miplearn_logger()
|
||||
GC.gc()
|
||||
@info "solve $instance_filename [done]"
|
||||
return stats
|
||||
end
|
||||
|
||||
|
||||
function parallel_solve!(
|
||||
solver::LearningSolver,
|
||||
instances::Vector{FileInstance};
|
||||
discard_output::Bool = false,
|
||||
)
|
||||
instance_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
|
||||
return pmap(
|
||||
instance_filename -> _solve(
|
||||
solver_filename,
|
||||
instance_filename,
|
||||
discard_output = discard_output,
|
||||
),
|
||||
instance_filenames,
|
||||
on_error=identity,
|
||||
)
|
||||
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)
|
||||
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)
|
||||
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,
|
||||
)
|
||||
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
|
||||
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)
|
||||
internal_solver = JuMPSolver(file["optimizer_factory"])
|
||||
solver_py.internal_solver_prototype = internal_solver
|
||||
return LearningSolver(
|
||||
solver_py,
|
||||
file["optimizer_factory"],
|
||||
)
|
||||
end
|
||||
@info @sprintf("File read in %.2f seconds", time)
|
||||
return solver
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
function init_miplearn_ext(model)::Dict
|
||||
if :miplearn ∉ keys(model.ext)
|
||||
model.ext[:miplearn] = Dict{Symbol, Any}()
|
||||
model.ext[:miplearn][:instance_features] = [0.0]
|
||||
model.ext[:miplearn][:variable_features] = Dict{AbstractString, Vector{Float64}}()
|
||||
model.ext[:miplearn][:variable_categories] = Dict{AbstractString, String}()
|
||||
model.ext[:miplearn][:constraint_features] = Dict{AbstractString, Vector{Float64}}()
|
||||
model.ext[:miplearn][:constraint_categories] = Dict{AbstractString, String}()
|
||||
model.ext[:miplearn] = Dict()
|
||||
model.ext[:miplearn]["instance_features"] = [0.0]
|
||||
model.ext[:miplearn]["variable_features"] = Dict{AbstractString, Vector{Float64}}()
|
||||
model.ext[:miplearn]["variable_categories"] = Dict{AbstractString, String}()
|
||||
model.ext[:miplearn]["constraint_features"] = Dict{AbstractString, Vector{Float64}}()
|
||||
model.ext[:miplearn]["constraint_categories"] = Dict{AbstractString, String}()
|
||||
end
|
||||
return model.ext[:miplearn]
|
||||
end
|
||||
@@ -17,7 +17,7 @@ end
|
||||
|
||||
function set_features!(m::Model, f::Array{Float64})::Nothing
|
||||
ext = init_miplearn_ext(m)
|
||||
ext[:instance_features] = f
|
||||
ext["instance_features"] = f
|
||||
return
|
||||
end
|
||||
|
||||
@@ -25,7 +25,7 @@ end
|
||||
function set_features!(v::VariableRef, f::Array{Float64})::Nothing
|
||||
ext = init_miplearn_ext(v.model)
|
||||
n = _get_and_check_name(v)
|
||||
ext[:variable_features][n] = f
|
||||
ext["variable_features"][n] = f
|
||||
return
|
||||
end
|
||||
|
||||
@@ -33,7 +33,7 @@ end
|
||||
function set_category!(v::VariableRef, category::String)::Nothing
|
||||
ext = init_miplearn_ext(v.model)
|
||||
n = _get_and_check_name(v)
|
||||
ext[:variable_categories][n] = category
|
||||
ext["variable_categories"][n] = category
|
||||
return
|
||||
end
|
||||
|
||||
@@ -41,7 +41,7 @@ end
|
||||
function set_features!(c::ConstraintRef, f::Array{Float64})::Nothing
|
||||
ext = init_miplearn_ext(c.model)
|
||||
n = _get_and_check_name(c)
|
||||
ext[:constraint_features][n] = f
|
||||
ext["constraint_features"][n] = f
|
||||
return
|
||||
end
|
||||
|
||||
@@ -49,7 +49,7 @@ end
|
||||
function set_category!(c::ConstraintRef, category::String)::Nothing
|
||||
ext = init_miplearn_ext(c.model)
|
||||
n = _get_and_check_name(c)
|
||||
ext[:constraint_categories][n] = category
|
||||
ext["constraint_categories"][n] = category
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user