mirror of
https://github.com/ANL-CEEESA/MIPLearn.git
synced 2025-12-06 01:18:52 -06:00
GurobiModel: Capture static_var_obj_coeffs_quad
This commit is contained in:
@@ -80,6 +80,7 @@ class MaxCutGenerator:
|
|||||||
def _generate_graph(self) -> Graph:
|
def _generate_graph(self) -> Graph:
|
||||||
return nx.generators.random_graphs.binomial_graph(self.n.rvs(), self.p.rvs())
|
return nx.generators.random_graphs.binomial_graph(self.n.rvs(), self.p.rvs())
|
||||||
|
|
||||||
|
|
||||||
def build_maxcut_model_gurobipy(
|
def build_maxcut_model_gurobipy(
|
||||||
data: Union[str, MaxCutData],
|
data: Union[str, MaxCutData],
|
||||||
params: Optional[dict[str, Any]] = None,
|
params: Optional[dict[str, Any]] = None,
|
||||||
@@ -97,13 +98,16 @@ def build_maxcut_model_gurobipy(
|
|||||||
x = model.addVars(nodes, vtype=gp.GRB.BINARY, name="x")
|
x = model.addVars(nodes, vtype=gp.GRB.BINARY, name="x")
|
||||||
|
|
||||||
# Add the objective function
|
# Add the objective function
|
||||||
model.setObjective(quicksum(
|
model.setObjective(
|
||||||
- data.weights[i] * x[e[0]] * (1 - x[e[1]]) for (i, e) in enumerate(edges)
|
quicksum(
|
||||||
))
|
-data.weights[i] * x[e[0]] * (1 - x[e[1]]) for (i, e) in enumerate(edges)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
model.update()
|
model.update()
|
||||||
return GurobiModel(model)
|
return GurobiModel(model)
|
||||||
|
|
||||||
|
|
||||||
def _maxcut_read(data: Union[str, MaxCutData]) -> MaxCutData:
|
def _maxcut_read(data: Union[str, MaxCutData]) -> MaxCutData:
|
||||||
if isinstance(data, str):
|
if isinstance(data, str):
|
||||||
data = read_pkl_gz(data)
|
data = read_pkl_gz(data)
|
||||||
|
|||||||
@@ -264,6 +264,13 @@ class GurobiModel(AbstractModel):
|
|||||||
h5.put_array(
|
h5.put_array(
|
||||||
h5_field, np.array(self.inner.getAttr(gp_field, gp_vars), dtype=float)
|
h5_field, np.array(self.inner.getAttr(gp_field, gp_vars), dtype=float)
|
||||||
)
|
)
|
||||||
|
obj = self.inner.getObjective()
|
||||||
|
if isinstance(obj, gp.QuadExpr):
|
||||||
|
nvars = len(self.inner.getVars())
|
||||||
|
obj_q = np.zeros((nvars, nvars))
|
||||||
|
for i in range(obj.size()):
|
||||||
|
obj_q[obj.getVar1(i).index, obj.getVar2(i).index] = obj.getCoeff(i)
|
||||||
|
h5.put_array("static_var_obj_coeffs_quad", obj_q)
|
||||||
|
|
||||||
def _extract_after_load_constrs(self, h5: H5File) -> None:
|
def _extract_after_load_constrs(self, h5: H5File) -> None:
|
||||||
gp_constrs = self.inner.getConstrs()
|
gp_constrs = self.inner.getConstrs()
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
# MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
# MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||||
# Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
# Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||||
# Released under the modified BSD license. See COPYING.md for more details.
|
# Released under the modified BSD license. See COPYING.md for more details.
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from miplearn.problems.maxcut import MaxCutGenerator, build_maxcut_model_gurobipy
|
|
||||||
from scipy.stats import randint, uniform
|
from scipy.stats import randint, uniform
|
||||||
|
|
||||||
|
from miplearn.h5 import H5File
|
||||||
|
from miplearn.problems.maxcut import MaxCutGenerator, build_maxcut_model_gurobipy
|
||||||
|
|
||||||
|
|
||||||
def _set_seed():
|
def _set_seed():
|
||||||
random.seed(42)
|
random.seed(42)
|
||||||
np.random.seed(42)
|
np.random.seed(42)
|
||||||
|
|
||||||
|
|
||||||
def test_maxcut_generator_not_fixed() -> None:
|
def test_maxcut_generator_not_fixed() -> None:
|
||||||
_set_seed()
|
_set_seed()
|
||||||
gen = MaxCutGenerator(
|
gen = MaxCutGenerator(
|
||||||
@@ -22,12 +27,20 @@ def test_maxcut_generator_not_fixed() -> None:
|
|||||||
data = gen.generate(3)
|
data = gen.generate(3)
|
||||||
assert len(data) == 3
|
assert len(data) == 3
|
||||||
assert list(data[0].graph.nodes()) == [0, 1, 2, 3, 4]
|
assert list(data[0].graph.nodes()) == [0, 1, 2, 3, 4]
|
||||||
assert list(data[0].graph.edges()) == [(0, 2), (0, 3), (0, 4), (2, 3), (2, 4), (3, 4)]
|
assert list(data[0].graph.edges()) == [
|
||||||
|
(0, 2),
|
||||||
|
(0, 3),
|
||||||
|
(0, 4),
|
||||||
|
(2, 3),
|
||||||
|
(2, 4),
|
||||||
|
(3, 4),
|
||||||
|
]
|
||||||
assert data[0].weights.tolist() == [-1, 1, -1, -1, -1, 1]
|
assert data[0].weights.tolist() == [-1, 1, -1, -1, -1, 1]
|
||||||
assert list(data[1].graph.nodes()) == [0, 1, 2, 3, 4]
|
assert list(data[1].graph.nodes()) == [0, 1, 2, 3, 4]
|
||||||
assert list(data[1].graph.edges()) == [(0, 1), (0, 3), (0, 4), (1, 4), (3, 4)]
|
assert list(data[1].graph.edges()) == [(0, 1), (0, 3), (0, 4), (1, 4), (3, 4)]
|
||||||
assert data[1].weights.tolist() == [-1, -1, -1, 1, -1]
|
assert data[1].weights.tolist() == [-1, -1, -1, 1, -1]
|
||||||
|
|
||||||
|
|
||||||
def test_maxcut_generator_fixed() -> None:
|
def test_maxcut_generator_fixed() -> None:
|
||||||
random.seed(42)
|
random.seed(42)
|
||||||
np.random.seed(42)
|
np.random.seed(42)
|
||||||
@@ -39,19 +52,67 @@ def test_maxcut_generator_fixed() -> None:
|
|||||||
data = gen.generate(3)
|
data = gen.generate(3)
|
||||||
assert len(data) == 3
|
assert len(data) == 3
|
||||||
assert list(data[0].graph.nodes()) == [0, 1, 2, 3, 4]
|
assert list(data[0].graph.nodes()) == [0, 1, 2, 3, 4]
|
||||||
assert list(data[0].graph.edges()) == [(0, 2), (0, 3), (0, 4), (2, 3), (2, 4), (3, 4)]
|
assert list(data[0].graph.edges()) == [
|
||||||
|
(0, 2),
|
||||||
|
(0, 3),
|
||||||
|
(0, 4),
|
||||||
|
(2, 3),
|
||||||
|
(2, 4),
|
||||||
|
(3, 4),
|
||||||
|
]
|
||||||
assert data[0].weights.tolist() == [-1, 1, -1, -1, -1, 1]
|
assert data[0].weights.tolist() == [-1, 1, -1, -1, -1, 1]
|
||||||
assert list(data[1].graph.nodes()) == [0, 1, 2, 3, 4]
|
assert list(data[1].graph.nodes()) == [0, 1, 2, 3, 4]
|
||||||
assert list(data[1].graph.edges()) == [(0, 2), (0, 3), (0, 4), (2, 3), (2, 4), (3, 4)]
|
assert list(data[1].graph.edges()) == [
|
||||||
|
(0, 2),
|
||||||
|
(0, 3),
|
||||||
|
(0, 4),
|
||||||
|
(2, 3),
|
||||||
|
(2, 4),
|
||||||
|
(3, 4),
|
||||||
|
]
|
||||||
assert data[1].weights.tolist() == [-1, -1, -1, 1, -1, -1]
|
assert data[1].weights.tolist() == [-1, -1, -1, 1, -1, -1]
|
||||||
|
|
||||||
|
|
||||||
def test_maxcut_model():
|
def test_maxcut_model():
|
||||||
_set_seed()
|
_set_seed()
|
||||||
data = MaxCutGenerator(
|
data = MaxCutGenerator(
|
||||||
n=randint(low=20, high=21),
|
n=randint(low=10, high=11),
|
||||||
p=uniform(loc=0.5, scale=0.0),
|
p=uniform(loc=0.5, scale=0.0),
|
||||||
fix_graph=True,
|
fix_graph=True,
|
||||||
).generate(1)[0]
|
).generate(1)[0]
|
||||||
model = build_maxcut_model_gurobipy(data)
|
model = build_maxcut_model_gurobipy(data)
|
||||||
|
|
||||||
|
with TemporaryDirectory() as tempdir:
|
||||||
|
with H5File(f"{tempdir}/data.h5", "w") as h5:
|
||||||
|
model.extract_after_load(h5)
|
||||||
|
obj_lin = h5.get_array("static_var_obj_coeffs")
|
||||||
|
assert obj_lin is not None
|
||||||
|
assert obj_lin.tolist() == [
|
||||||
|
3.0,
|
||||||
|
1.0,
|
||||||
|
3.0,
|
||||||
|
1.0,
|
||||||
|
-1.0,
|
||||||
|
0.0,
|
||||||
|
-1.0,
|
||||||
|
0.0,
|
||||||
|
-1.0,
|
||||||
|
0.0,
|
||||||
|
]
|
||||||
|
obj_quad = h5.get_array("static_var_obj_coeffs_quad")
|
||||||
|
assert obj_quad is not None
|
||||||
|
assert obj_quad.tolist() == [
|
||||||
|
[0.0, 0.0, -1.0, 1.0, -1.0, 0.0, 0.0, 0.0, -1.0, -1.0],
|
||||||
|
[0.0, 0.0, 1.0, -1.0, 0.0, -1.0, -1.0, 0.0, 0.0, 1.0],
|
||||||
|
[0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, -1.0],
|
||||||
|
[0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 1.0, -1.0, 0.0, 0.0],
|
||||||
|
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
|
||||||
|
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
|
||||||
|
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, -1.0],
|
||||||
|
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
|
||||||
|
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
]
|
||||||
|
|
||||||
model.optimize()
|
model.optimize()
|
||||||
assert model.inner.ObjVal == -26
|
assert model.inner.ObjVal == -4
|
||||||
|
|||||||
Reference in New Issue
Block a user