parent
1ea432fb57
commit
d69c4bbfa7
@ -0,0 +1,60 @@
|
||||
# MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020-2024, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
using JuMP
|
||||
using HiGHS
|
||||
|
||||
global MaxWeightStableSetData = PyNULL()
|
||||
global MaxWeightStableSetGenerator = PyNULL()
|
||||
|
||||
function __init_problems_stab__()
|
||||
copy!(MaxWeightStableSetData, pyimport("miplearn.problems.stab").MaxWeightStableSetData)
|
||||
copy!(MaxWeightStableSetGenerator, pyimport("miplearn.problems.stab").MaxWeightStableSetGenerator)
|
||||
end
|
||||
|
||||
function build_stab_model_jump(data::Any; optimizer=HiGHS.Optimizer)
|
||||
nx = pyimport("networkx")
|
||||
|
||||
if data isa String
|
||||
data = read_pkl_gz(data)
|
||||
end
|
||||
model = Model(optimizer)
|
||||
|
||||
# Variables and objective function
|
||||
nodes = data.graph.nodes
|
||||
x = @variable(model, x[nodes], Bin)
|
||||
@objective(model, Min, sum(-data.weights[i+1] * x[i] for i in nodes))
|
||||
|
||||
# Edge inequalities
|
||||
for (i1, i2) in data.graph.edges
|
||||
@constraint(model, x[i1] + x[i2] <= 1, base_name = "eq_edge[$i1,$i2]")
|
||||
end
|
||||
|
||||
function cuts_separate(cb_data)
|
||||
x_val = callback_value.(Ref(cb_data), x)
|
||||
violations = []
|
||||
for clique in nx.find_cliques(data.graph)
|
||||
if sum(x_val[i] for i in clique) > 1.0001
|
||||
push!(violations, sort(clique))
|
||||
end
|
||||
end
|
||||
return violations
|
||||
end
|
||||
|
||||
function cuts_enforce(violations)
|
||||
@info "Adding $(length(violations)) clique cuts..."
|
||||
for clique in violations
|
||||
constr = @build_constraint(sum(x[i] for i in clique) <= 1)
|
||||
submit(model, constr)
|
||||
end
|
||||
end
|
||||
|
||||
return JumpModel(
|
||||
model,
|
||||
cuts_separate=cuts_separate,
|
||||
cuts_enforce=cuts_enforce,
|
||||
)
|
||||
end
|
||||
|
||||
export MaxWeightStableSetData, MaxWeightStableSetGenerator, build_stab_model_jump
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,45 @@
|
||||
# MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020-2024, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
using SCIP
|
||||
|
||||
function gen_stab()
|
||||
np = pyimport("numpy")
|
||||
uniform = pyimport("scipy.stats").uniform
|
||||
randint = pyimport("scipy.stats").randint
|
||||
np.random.seed(42)
|
||||
gen = MaxWeightStableSetGenerator(
|
||||
w=uniform(10.0, scale=1.0),
|
||||
n=randint(low=50, high=51),
|
||||
p=uniform(loc=0.5, scale=0.0),
|
||||
fix_graph=true,
|
||||
)
|
||||
data = gen.generate(1)
|
||||
data_filenames = write_pkl_gz(data, "$BASEDIR/../fixtures", prefix="stab-n50-")
|
||||
collector = BasicCollector(write_mps=false)
|
||||
collector.collect(
|
||||
data_filenames,
|
||||
data -> build_stab_model_jump(data, optimizer=SCIP.Optimizer),
|
||||
progress=true,
|
||||
verbose=true,
|
||||
)
|
||||
end
|
||||
|
||||
function test_cuts()
|
||||
data_filenames = ["$BASEDIR/../fixtures/stab-n50-0000$i.pkl.gz" for i in 0:0]
|
||||
clf = pyimport("sklearn.neighbors").KNeighborsClassifier(n_neighbors=1)
|
||||
extractor = H5FieldsExtractor(
|
||||
instance_fields=["static_var_obj_coeffs"],
|
||||
)
|
||||
comp = MemorizingCutsComponent(clf=clf, extractor=extractor)
|
||||
solver = LearningSolver(components=[comp])
|
||||
solver.fit(data_filenames)
|
||||
@show comp.n_features_
|
||||
@show comp.n_targets_
|
||||
stats = solver.optimize(
|
||||
data_filenames[1],
|
||||
data -> build_stab_model_jump(data, optimizer=SCIP.Optimizer),
|
||||
)
|
||||
@test stats["Cuts: AOT"] > 0
|
||||
end
|
@ -0,0 +1,27 @@
|
||||
# MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020-2024, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
using PyCall
|
||||
using SCIP
|
||||
|
||||
function test_problems_stab()
|
||||
test_problems_stab_1()
|
||||
test_problems_stab_2()
|
||||
end
|
||||
|
||||
function test_problems_stab_1()
|
||||
nx = pyimport("networkx")
|
||||
data = MaxWeightStableSetData(
|
||||
graph=nx.gnp_random_graph(25, 0.5, seed=42),
|
||||
weights=repeat([1.0], 25),
|
||||
)
|
||||
h5 = H5File(tempname(), "w")
|
||||
model = build_stab_model_jump(data, optimizer=SCIP.Optimizer)
|
||||
model.extract_after_load(h5)
|
||||
model.optimize()
|
||||
model.extract_after_mip(h5)
|
||||
@test h5.get_scalar("mip_obj_value") == -6
|
||||
@test h5.get_scalar("mip_cuts")[1:20] == "[[0,8,11,13],[0,8,13"
|
||||
h5.close()
|
||||
end
|
Loading…
Reference in new issue