Use compact variable and constraint features

master
Alinson S. Xavier 4 years ago
parent 185ed40648
commit e9fbf4a3c7

@ -11,9 +11,9 @@ uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
[[BenchmarkTools]] [[BenchmarkTools]]
deps = ["JSON", "Logging", "Printf", "Statistics", "UUIDs"] deps = ["JSON", "Logging", "Printf", "Statistics", "UUIDs"]
git-tree-sha1 = "9e62e66db34540a0c919d72172cc2f642ac71260" git-tree-sha1 = "068fda9b756e41e6c75da7b771e6f89fa8a43d15"
uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
version = "0.5.0" version = "0.7.0"
[[Bzip2_jll]] [[Bzip2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
@ -29,9 +29,9 @@ version = "0.5.1"
[[ChainRulesCore]] [[ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"] deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "44e9f638aa9ed1ad58885defc568c133010140aa" git-tree-sha1 = "e6b23566e025d3b0d9ccc397f5c7a134af552e27"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "0.9.37" version = "0.9.42"
[[CodecBzip2]] [[CodecBzip2]]
deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"] deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"]
@ -53,9 +53,9 @@ version = "0.3.0"
[[Compat]] [[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"] 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" git-tree-sha1 = "0a817fbe51c976de090aa8c997b7b719b786118d"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.27.0" version = "3.28.0"
[[CompilerSupportLibraries_jll]] [[CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"] deps = ["Artifacts", "Libdl"]
@ -63,9 +63,9 @@ uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
[[Conda]] [[Conda]]
deps = ["JSON", "VersionParsing"] deps = ["JSON", "VersionParsing"]
git-tree-sha1 = "6231e40619c15148bcb80aa19d731e629877d762" git-tree-sha1 = "299304989a5e6473d985212c28928899c74e9421"
uuid = "8f4d0f93-b110-5947-807f-2305c1781a2d" uuid = "8f4d0f93-b110-5947-807f-2305c1781a2d"
version = "1.5.1" version = "1.5.2"
[[DataStructures]] [[DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"] deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
@ -109,9 +109,9 @@ version = "0.10.18"
[[HTTP]] [[HTTP]]
deps = ["Base64", "Dates", "IniFile", "MbedTLS", "NetworkOptions", "Sockets", "URIs"] deps = ["Base64", "Dates", "IniFile", "MbedTLS", "NetworkOptions", "Sockets", "URIs"]
git-tree-sha1 = "c9f380c76d8aaa1fa7ea9cf97bddbc0d5b15adc2" git-tree-sha1 = "b855bf8247d6e946c75bb30f593bfe7fe591058d"
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
version = "0.9.5" version = "0.9.8"
[[IniFile]] [[IniFile]]
deps = ["Test"] deps = ["Test"]
@ -124,9 +124,10 @@ deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
[[JLLWrappers]] [[JLLWrappers]]
git-tree-sha1 = "a431f5f2ca3f4feef3bd7a5e94b8b8d4f2f647a0" deps = ["Preferences"]
git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.2.0" version = "1.3.0"
[[JSON]] [[JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"] deps = ["Dates", "Mmap", "Parsers", "Unicode"]
@ -141,10 +142,10 @@ uuid = "7d188eb4-7ad8-530c-ae41-71a32a6d4692"
version = "0.3.3" version = "0.3.3"
[[JuMP]] [[JuMP]]
deps = ["Calculus", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MathOptInterface", "MutableArithmetics", "NaNMath", "Random", "SparseArrays", "SpecialFunctions", "Statistics"] deps = ["Calculus", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MathOptInterface", "MutableArithmetics", "NaNMath", "Printf", "Random", "SparseArrays", "SpecialFunctions", "Statistics"]
git-tree-sha1 = "e952f49e2242fa21edcf27bbd6c67041685bee5d" git-tree-sha1 = "8dfc5df8aad9f2cfebc8371b69700efd02060827"
uuid = "4076af6c-e467-56ae-b986-b466b2749572" uuid = "4076af6c-e467-56ae-b986-b466b2749572"
version = "0.21.6" version = "0.21.8"
[[LibCURL]] [[LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"] deps = ["LibCURL_jll", "MozillaCACerts_jll"]
@ -184,9 +185,9 @@ uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
[[MathOptInterface]] [[MathOptInterface]]
deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "JSON", "JSONSchema", "LinearAlgebra", "MutableArithmetics", "OrderedCollections", "SparseArrays", "Test", "Unicode"] deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "JSON", "JSONSchema", "LinearAlgebra", "MutableArithmetics", "OrderedCollections", "SparseArrays", "Test", "Unicode"]
git-tree-sha1 = "606efe4246da5407d7505265a1ead72467528996" git-tree-sha1 = "cd3057ca89a9ab83ce37ec42324523b8db0c60dc"
uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
version = "0.9.20" version = "0.9.21"
[[MbedTLS]] [[MbedTLS]]
deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"] deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"]
@ -206,9 +207,9 @@ uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
[[MutableArithmetics]] [[MutableArithmetics]]
deps = ["LinearAlgebra", "SparseArrays", "Test"] deps = ["LinearAlgebra", "SparseArrays", "Test"]
git-tree-sha1 = "ff3aa3e4dbc837f80c2031de2f90125c8b3793f3" git-tree-sha1 = "ad9b2bce6021631e0e20706d361972343a03e642"
uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0"
version = "0.2.15" version = "0.2.19"
[[NaNMath]] [[NaNMath]]
git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb" git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb"
@ -220,14 +221,14 @@ uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
[[OpenSpecFun_jll]] [[OpenSpecFun_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "9db77584158d0ab52307f8c04f8e7c08ca76b5b3" git-tree-sha1 = "b9b8b8ed236998f91143938a760c2112dceeb2b4"
uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e"
version = "0.5.3+4" version = "0.5.4+0"
[[OrderedCollections]] [[OrderedCollections]]
git-tree-sha1 = "4fa2ba51070ec13fcc7517db714445b4ab986bdf" git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.0" version = "1.4.1"
[[Parsers]] [[Parsers]]
deps = ["Dates"] deps = ["Dates"]
@ -239,15 +240,21 @@ version = "1.1.0"
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
[[Preferences]]
deps = ["TOML"]
git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.2"
[[Printf]] [[Printf]]
deps = ["Unicode"] deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
[[PyCall]] [[PyCall]]
deps = ["Conda", "Dates", "Libdl", "LinearAlgebra", "MacroTools", "Serialization", "VersionParsing"] deps = ["Conda", "Dates", "Libdl", "LinearAlgebra", "MacroTools", "Serialization", "VersionParsing"]
git-tree-sha1 = "dd1a970b543bd02efce2984582e996af28cab27f" git-tree-sha1 = "169bb8ea6b1b143c5cf57df6d34d022a7b60c6db"
uuid = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" uuid = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
version = "1.92.2" version = "1.92.3"
[[REPL]] [[REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
@ -282,9 +289,9 @@ version = "1.3.0"
[[StaticArrays]] [[StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"] deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "2f01a51c23eed210ff4a1be102c4cc8236b66e5b" git-tree-sha1 = "fb46e45ef2cade8be20bb445b3ffeca3c6d6f7d3"
uuid = "90137ffa-7385-5640-81b9-e52037218182" uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.1.0" version = "1.1.3"
[[Statistics]] [[Statistics]]
deps = ["LinearAlgebra", "SparseArrays"] deps = ["LinearAlgebra", "SparseArrays"]
@ -315,9 +322,9 @@ uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
version = "0.9.5" version = "0.9.5"
[[URIs]] [[URIs]]
git-tree-sha1 = "7855809b88d7b16e9b029afd17880930626f54a2" git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355"
uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
version = "1.2.0" version = "1.3.0"
[[UUIDs]] [[UUIDs]]
deps = ["Random", "SHA"] deps = ["Random", "SHA"]

@ -13,9 +13,7 @@ PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
[compat] [compat]
Conda = "1.4"
JuMP = "0.21" JuMP = "0.21"
MathOptInterface = "0.9" MathOptInterface = "0.9"
PyCall = "1"
TimerOutputs = "0.5" TimerOutputs = "0.5"
julia = "1" julia = "1"

2
deps/build.jl vendored

@ -5,7 +5,7 @@ function install_miplearn()
Conda.update() Conda.update()
pip = joinpath(dirname(pyimport("sys").executable), "pip") pip = joinpath(dirname(pyimport("sys").executable), "pip")
isfile(pip) || error("$pip: invalid path") isfile(pip) || error("$pip: invalid path")
run(`$pip install miplearn==0.2.0.dev3`) run(`$pip install miplearn==0.2.0.dev5`)
end end
install_miplearn() install_miplearn()

@ -4,46 +4,46 @@
@pydef mutable struct JuMPInstance <: miplearn.Instance @pydef mutable struct JuMPInstance <: miplearn.Instance
function __init__(self, model) function __init__(self, model)
init_miplearn_ext(model)
features = model.ext[:miplearn][:features]
self.model = model self.model = model
# Copy training data # init_miplearn_ext(model)
training_data = [] # features = model.ext[:miplearn][:features]
for sample in self.model.ext[:miplearn][:training_samples] # # Copy training data
pysample = miplearn.TrainingSample() # training_data = []
pysample.__dict__ = sample # for sample in self.model.ext[:miplearn][:training_samples]
push!(training_data, pysample) # pysample = miplearn.TrainingSample()
end # pysample.__dict__ = sample
self.training_data = training_data # push!(training_data, pysample)
# end
# self.training_data = training_data
# Copy features to data classes # # Copy features to data classes
self.features = miplearn.Features( # self.features = miplearn.Features(
instance=miplearn.InstanceFeatures( # instance=miplearn.InstanceFeatures(
user_features=PyCall.array2py( # user_features=PyCall.array2py(
features[:instance][:user_features], # features[:instance][:user_features],
), # ),
lazy_constraint_count=0, # lazy_constraint_count=0,
), # ),
variables=Dict( # variables=Dict(
varname => miplearn.VariableFeatures( # varname => miplearn.VariableFeatures(
category=vfeatures[:category], # category=vfeatures[:category],
user_features=PyCall.array2py( # user_features=PyCall.array2py(
vfeatures[:user_features], # vfeatures[:user_features],
), # ),
) # )
for (varname, vfeatures) in features[:variables] # for (varname, vfeatures) in features[:variables]
), # ),
constraints=Dict( # constraints=Dict(
cname => miplearn.ConstraintFeatures( # cname => miplearn.ConstraintFeatures(
category=cfeat[:category], # category=cfeat[:category],
user_features=PyCall.array2py( # user_features=PyCall.array2py(
cfeat[:user_features], # cfeat[:user_features],
), # ),
) # )
for (cname, cfeat) in features[:constraints] # for (cname, cfeat) in features[:constraints]
), # ),
) # )
end end
function to_model(self) function to_model(self)

@ -14,8 +14,10 @@ mutable struct JuMPSolverData
instance instance
model model
bin_vars bin_vars
solution::Union{Nothing, Dict{String,Float64}} solution
cname_to_constr cname_to_constr
reduced_costs
dual_values
end end
@ -26,34 +28,27 @@ Optimizes a given JuMP model while capturing the solver log, then returns that l
If tee=true, prints the solver log to the standard output as the optimization takes place. If tee=true, prints the solver log to the standard output as the optimization takes place.
""" """
function optimize_and_capture_output!(model; tee::Bool=false) function optimize_and_capture_output!(model; tee::Bool=false)
original_stdout = stdout logname = tempname()
rd, wr = redirect_stdout() logfile = open(logname, "w")
task = @async begin redirect_stdout(logfile) do
log = "" JuMP.optimize!(model)
while true Base.Libc.flush_cstdio()
line = String(readavailable(rd))
isopen(rd) || break
log *= String(line)
if tee
print(original_stdout, line)
flush(original_stdout)
end
end
return log
end end
JuMP.optimize!(model) close(logfile)
sleep(1) log = String(read(logname))
redirect_stdout(original_stdout) rm(logname)
close(rd) if tee
return fetch(task) println(log)
end
return log
end end
function solve( function solve(
data::JuMPSolverData; data::JuMPSolverData;
tee::Bool=false, tee::Bool=false,
iteration_cb, iteration_cb=nothing,
)::Dict )
instance, model = data.instance, data.model instance, model = data.instance, data.model
wallclock_time = 0 wallclock_time = 0
log = "" log = ""
@ -78,14 +73,14 @@ function solve(
lower_bound = primal_bound lower_bound = primal_bound
upper_bound = dual_bound upper_bound = dual_bound
end end
return Dict( return miplearn.solvers.internal.MIPSolveStats(
"Lower bound" => lower_bound, mip_lower_bound=lower_bound,
"Upper bound" => upper_bound, mip_upper_bound=upper_bound,
"Sense" => sense, mip_sense=sense,
"Wallclock time" => wallclock_time, mip_wallclock_time=wallclock_time,
"Nodes" => 1, mip_nodes=1,
"MIP log" => log, mip_log=log,
"Warm start value" => nothing, mip_warm_start_value=nothing,
) )
end end
@ -97,24 +92,55 @@ function solve_lp(data::JuMPSolverData; tee::Bool=false)
JuMP.set_upper_bound(var, 1.0) JuMP.set_upper_bound(var, 1.0)
JuMP.set_lower_bound(var, 0.0) JuMP.set_lower_bound(var, 0.0)
end end
log = optimize_and_capture_output!(model, tee=tee) wallclock_time = @elapsed begin
log = optimize_and_capture_output!(model, tee=tee)
end
update_solution!(data) update_solution!(data)
obj_value = JuMP.objective_value(model) obj_value = JuMP.objective_value(model)
for var in bin_vars for var in bin_vars
JuMP.set_binary(var) JuMP.set_binary(var)
end end
return Dict( return miplearn.solvers.internal.LPSolveStats(
"LP value" => obj_value, lp_value=obj_value,
"LP log" => log, lp_log=log,
lp_wallclock_time=wallclock_time,
) )
end end
function update_solution!(data::JuMPSolverData) function update_solution!(data::JuMPSolverData)
data.solution = Dict( vars = JuMP.all_variables(data.model)
JuMP.name(var) => JuMP.value(var) data.solution = [JuMP.value(var) for var in vars]
for var in JuMP.all_variables(data.model)
) # Reduced costs
if has_duals(data.model)
data.reduced_costs = []
for var in vars
rc = 0.0
if has_upper_bound(var)
rc += shadow_price(UpperBoundRef(var))
end
if has_lower_bound(var)
# FIXME: Remove negative sign
rc -= shadow_price(LowerBoundRef(var))
end
if is_fixed(var)
rc += shadow_price(FixRef(var))
end
push!(data.reduced_costs, rc)
end
data.dual_values = Dict()
for (ftype, stype) in JuMP.list_of_constraint_types(data.model)
for constr in JuMP.all_constraints(data.model, ftype, stype)
# FIXME: Remove negative sign
data.dual_values[constr] = -JuMP.dual(constr)
end
end
else
data.reduced_costs = nothing
data.dual_values = nothing
end
end end
@ -195,6 +221,151 @@ function get_constraint_sense(data::JuMPSolverData, cname)
end end
function get_variables(
data::JuMPSolverData;
with_static::Bool,
)
vars = JuMP.all_variables(data.model)
lb, ub, types, obj_coeffs = nothing, nothing, nothing, nothing
rc = nothing
# Variable names
names = Tuple(JuMP.name.(vars))
if with_static
# Lower bounds
lb = Tuple(
JuMP.is_binary(v) ? 0.0 :
JuMP.has_lower_bound(v) ? JuMP.lower_bound(v) :
-Inf
for v in vars
)
# Upper bounds
ub = Tuple(
JuMP.is_binary(v) ? 1.0 :
JuMP.has_upper_bound(v) ? JuMP.upper_bound(v) :
Inf
for v in vars
)
# Variable types
types = Tuple(
JuMP.is_binary(v) ? "B" :
JuMP.is_integer(v) ? "I" :
"C"
for v in vars
)
# Objective function coefficients
obj = objective_function(data.model)
obj_coeffs = Tuple(
v keys(obj.terms) ? obj.terms[v] : 0.0
for v in vars
)
end
rc = data.reduced_costs === nothing ? nothing : Tuple(data.reduced_costs)
values = data.solution === nothing ? nothing : Tuple(data.solution)
return miplearn.features.VariableFeatures(
names=names,
lower_bounds=lb,
upper_bounds=ub,
types=types,
obj_coeffs=obj_coeffs,
reduced_costs=rc,
values=values,
)
end
function get_constraints(
data::JuMPSolverData;
with_static::Bool,
)
names = []
senses, lhs, rhs = nothing, nothing, nothing
dual_values = nothing
if data.dual_values !== nothing
dual_values = []
end
if with_static
senses, lhs, rhs = [], [], []
end
for (ftype, stype) in JuMP.list_of_constraint_types(data.model)
ftype in [JuMP.AffExpr, JuMP.VariableRef] || error("Unsupported constraint type: ($ftype, $stype)")
for constr in JuMP.all_constraints(data.model, ftype, stype)
cset = MOI.get(
constr.model.moi_backend,
MOI.ConstraintSet(),
constr.index,
)
name = JuMP.name(constr)
length(name) > 0 || continue
push!(names, name)
if data.dual_values !== nothing
push!(dual_values, data.dual_values[constr])
end
if with_static
if ftype == JuMP.AffExpr
push!(
lhs,
Tuple(
(
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
)
)
if stype == MOI.EqualTo{Float64}
push!(senses, "=")
push!(rhs, cset.value)
elseif stype == MOI.LessThan{Float64}
push!(senses, "<")
push!(rhs, cset.upper)
elseif stype == MOI.GreaterThan{Float64}
push!(senses, ">")
push!(rhs, cset.lower)
else
error("Unsupported set: $stype")
end
else
error("Unsupported ftype: $ftype")
end
end
end
end
function to_tuple(x)
x !== nothing || return nothing
return Tuple(x)
end
return miplearn.features.ConstraintFeatures(
names=to_tuple(names),
senses=to_tuple(senses),
lhs=to_tuple(lhs),
rhs=to_tuple(rhs),
dual_values=to_tuple(dual_values),
)
end
# Constraints: ScalarAffineFunction, LessThan # Constraints: ScalarAffineFunction, LessThan
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
function get_constraint_rhs( function get_constraint_rhs(
@ -355,6 +526,23 @@ function get_constraint_sense(
return "=" return "="
end end
# Test instances
# ---------------------------------------------
function build_test_instance_knapsack()
weights = [23.0, 26.0, 20.0, 18.0]
prices = [505.0, 352.0, 458.0, 220.0]
capacity = 67.0
model = Model()
n = length(weights)
@variable(model, x[0:n-1], Bin)
@variable(model, z, lower_bound=0.0, upper_bound=capacity)
@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 JuMPInstance(model)
end
@pydef mutable struct JuMPSolver <: miplearn.solvers.internal.InternalSolver @pydef mutable struct JuMPSolver <: miplearn.solvers.internal.InternalSolver
function __init__(self; optimizer) function __init__(self; optimizer)
@ -366,6 +554,8 @@ end
nothing, # bin_vars nothing, # bin_vars
nothing, # solution nothing, # solution
nothing, # cname_to_constr nothing, # cname_to_constr
nothing, # reduced_costs
nothing, # dual_values
) )
end end
@ -381,9 +571,9 @@ end
solve( solve(
self; self;
tee=false, tee=false,
iteration_cb, iteration_cb=nothing,
lazy_cb, lazy_cb=nothing,
user_cut_cb, user_cut_cb=nothing,
) = solve( ) = solve(
self.data, self.data,
tee=tee, tee=tee,
@ -396,8 +586,8 @@ end
get_solution(self) = get_solution(self) =
self.data.solution self.data.solution
get_variables(self) = get_variables(self; with_static=true) =
get_variables(self.data) get_variables(self.data; with_static=with_static)
set_branching_priorities(self, priorities) = set_branching_priorities(self, priorities) =
@warn "JuMPSolver: set_branching_priorities not implemented" @warn "JuMPSolver: set_branching_priorities not implemented"
@ -411,6 +601,9 @@ end
is_infeasible(self) = is_infeasible(self) =
is_infeasible(self.data) is_infeasible(self.data)
get_constraints(self; with_static=true) =
get_constraints(self.data; with_static=with_static)
get_constraint_ids(self) = get_constraint_ids(self) =
get_constraint_ids(self.data) get_constraint_ids(self.data)
@ -423,8 +616,45 @@ end
get_constraint_sense(self, cname) = get_constraint_sense(self, cname) =
get_constraint_sense(self.data, cname) get_constraint_sense(self.data, cname)
build_test_instance_knapsack(self) =
build_test_instance_knapsack()
clone(self) = self clone(self) = self
get_variable_attrs(self) = [
"names",
# "basis_status",
"categories",
"lower_bounds",
"obj_coeffs",
"reduced_costs",
# "sa_lb_down",
# "sa_lb_up",
# "sa_obj_down",
# "sa_obj_up",
# "sa_ub_down",
# "sa_ub_up",
"types",
"upper_bounds",
"user_features",
"values",
]
get_constraint_attrs(self) = [
# "basis_status",
"categories",
"dual_values",
"lazy",
"lhs",
"names",
"rhs",
# "sa_rhs_down",
# "sa_rhs_up",
"senses",
# "slacks",
"user_features",
]
add_cut(self) = error("not implemented") add_cut(self) = error("not implemented")
extract_constraint(self) = error("not implemented") extract_constraint(self) = error("not implemented")
is_constraint_satisfied(self) = error("not implemented") is_constraint_satisfied(self) = error("not implemented")
@ -433,6 +663,11 @@ end
get_inequality_slacks(self) = error("not implemented") get_inequality_slacks(self) = error("not implemented")
get_dual(self) = error("not implemented") get_dual(self) = error("not implemented")
get_sense(self) = error("not implemented") get_sense(self) = error("not implemented")
build_test_instance_infeasible(self) = error("not implemented")
build_test_instance_redundancy(self) = error("not implemented")
get_constraints_old(self) = error("not implemented")
is_constraint_satisfied_old(self) = error("not implemented")
remove_constraint(self) = error("not implemented")
end end
export JuMPSolver, solve!, fit!, add! export JuMPSolver, solve!, fit!, add!

@ -1,24 +0,0 @@
# 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.
macro pycall(expr)
quote
err_msg = nothing
result = nothing
try
result = $(esc(expr))
catch err
args = err.val.args[1]
if (err isa PyCall.PyError) && (args isa String) && startswith(args, "Julia")
err_msg = replace(args, r"Stacktrace.*" => "")
else
rethrow(err)
end
end
if err_msg != nothing
error(err_msg)
end
result
end
end

@ -4,6 +4,7 @@
[deps] [deps]
Cbc = "9961bab8-2fa3-5c5a-9d89-47fab24efd76" Cbc = "9961bab8-2fa3-5c5a-9d89-47fab24efd76"
Gurobi = "2e9cd046-0924-5485-92f1-d5272153d98b"
Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d" Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d"
JSON2 = "2535ab7d-5cd8-5a07-80ac-9b1792aadce3" JSON2 = "2535ab7d-5cd8-5a07-80ac-9b1792aadce3"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572" JuMP = "4076af6c-e467-56ae-b986-b466b2749572"

@ -4,18 +4,22 @@
using Test using Test
using MIPLearn using MIPLearn
using Cbc using Gurobi
using PyCall using PyCall
using JuMP
miplearn_tests = pyimport("miplearn.solvers.tests") miplearn_tests = pyimport("miplearn.solvers.tests")
traceback = pyimport("traceback")
@testset "JuMPSolver" begin @testset "JuMPSolver" begin
model = MIPLearn.knapsack_model( solver = JuMPSolver(optimizer=Gurobi.Optimizer)
[23., 26., 20., 18.], try
[505., 352., 458., 220.], miplearn_tests.run_internal_solver_tests(solver)
67.0, catch e
) if isa(e, PyCall.PyError)
instance = JuMPInstance(model) printstyled("Uncaught Python exception:\n", bold=true, color=:red)
solver = JuMPSolver(optimizer=Cbc.Optimizer) traceback.print_exception(e.T, e.val, e.traceback)
miplearn_tests.test_internal_solver(solver, instance, model) end
rethrow()
end
end end

@ -8,6 +8,6 @@ using MIPLearn
MIPLearn.setup_logger() MIPLearn.setup_logger()
@testset "MIPLearn" begin @testset "MIPLearn" begin
#include("modeling/jump_solver_test.jl") include("modeling/jump_solver_test.jl")
include("modeling/learning_solver_test.jl") #include("modeling/learning_solver_test.jl")
end end
Loading…
Cancel
Save