ommx-python-mip-adapter 3.0.0a2__tar.gz → 3.0.0a4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/PKG-INFO +2 -2
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter/adapter.py +52 -44
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter.egg-info/PKG-INFO +2 -2
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter.egg-info/SOURCES.txt +2 -1
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter.egg-info/requires.txt +1 -1
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/pyproject.toml +2 -2
- ommx_python_mip_adapter-3.0.0a4/tests/test_tracing.py +42 -0
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/README.md +0 -0
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter/__init__.py +0 -0
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter/exception.py +0 -0
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter/python_mip_to_ommx.py +0 -0
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter.egg-info/dependency_links.txt +0 -0
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter.egg-info/top_level.txt +0 -0
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/setup.cfg +0 -0
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/tests/test_adapter.py +0 -0
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/tests/test_constant_constraint.py +0 -0
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/tests/test_integration.py +0 -0
- {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/tests/test_model_to_instance.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ommx_python_mip_adapter
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.0a4
|
|
4
4
|
Summary: An adapter for the Python-MIP from/to OMMX.
|
|
5
5
|
Author-email: "Jij Inc." <info@j-ij.com>
|
|
6
6
|
Project-URL: Repository, https://github.com/Jij-Inc/ommx
|
|
@@ -15,7 +15,7 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
15
15
|
Classifier: License :: OSI Approved :: MIT License
|
|
16
16
|
Requires-Python: >=3.10
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
|
-
Requires-Dist: ommx<4.0.0,>=3.0.
|
|
18
|
+
Requires-Dist: ommx<4.0.0,>=3.0.0a4
|
|
19
19
|
Requires-Dist: mip<2.0.0,>=1.17.0
|
|
20
20
|
Requires-Dist: cffi<2.0.0,>=1.15.0
|
|
21
21
|
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import Optional
|
|
4
4
|
|
|
5
5
|
import mip
|
|
6
|
+
from opentelemetry import trace
|
|
6
7
|
|
|
7
8
|
from ommx.adapter import (
|
|
8
9
|
SolverAdapter,
|
|
@@ -14,6 +15,8 @@ from ommx.v1 import Instance, Constraint, DecisionVariable, Solution, State, Fun
|
|
|
14
15
|
|
|
15
16
|
from .exception import OMMXPythonMIPAdapterError
|
|
16
17
|
|
|
18
|
+
_tracer = trace.get_tracer("ommx.adapter.python_mip")
|
|
19
|
+
|
|
17
20
|
|
|
18
21
|
class OMMXPythonMIPAdapter(SolverAdapter):
|
|
19
22
|
def __init__(
|
|
@@ -32,33 +35,36 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
32
35
|
:param solver: Passes a specific solver to the Python-MIP model.
|
|
33
36
|
:param verbose: If True, enable Python-MIP's verbose mode
|
|
34
37
|
"""
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
sense
|
|
38
|
-
|
|
39
|
-
sense
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
with _tracer.start_as_current_span("convert"):
|
|
39
|
+
super().__init__(ommx_instance)
|
|
40
|
+
if ommx_instance.sense == Instance.MAXIMIZE:
|
|
41
|
+
sense = mip.MAXIMIZE
|
|
42
|
+
elif ommx_instance.sense == Instance.MINIMIZE:
|
|
43
|
+
sense = mip.MINIMIZE
|
|
44
|
+
else:
|
|
45
|
+
raise OMMXPythonMIPAdapterError(
|
|
46
|
+
f"Unsupported sense: {ommx_instance.sense}"
|
|
47
|
+
)
|
|
48
|
+
self.instance = ommx_instance
|
|
49
|
+
self.model = mip.Model(
|
|
50
|
+
sense=sense,
|
|
51
|
+
solver_name=solver_name,
|
|
52
|
+
solver=solver,
|
|
53
|
+
)
|
|
54
|
+
if verbose:
|
|
55
|
+
self.model.verbose = 1
|
|
56
|
+
else:
|
|
57
|
+
self.model.verbose = 0
|
|
52
58
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
self._set_decision_variables()
|
|
60
|
+
self._set_objective()
|
|
61
|
+
self._set_constraints()
|
|
56
62
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
if relax:
|
|
64
|
+
self.model.relax()
|
|
65
|
+
self._relax = True
|
|
66
|
+
else:
|
|
67
|
+
self._relax = False
|
|
62
68
|
|
|
63
69
|
@classmethod
|
|
64
70
|
def solve(
|
|
@@ -177,7 +183,8 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
177
183
|
"""
|
|
178
184
|
adapter = cls(ommx_instance, relax=relax, verbose=verbose)
|
|
179
185
|
model = adapter.solver_input
|
|
180
|
-
|
|
186
|
+
with _tracer.start_as_current_span("solve"):
|
|
187
|
+
model.optimize(relax=relax)
|
|
181
188
|
return adapter.decode(model)
|
|
182
189
|
|
|
183
190
|
@property
|
|
@@ -234,24 +241,25 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
234
241
|
42.0
|
|
235
242
|
|
|
236
243
|
"""
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
244
|
+
with _tracer.start_as_current_span("decode"):
|
|
245
|
+
state = self.decode_to_state(data)
|
|
246
|
+
solution = self.instance.evaluate(state)
|
|
247
|
+
|
|
248
|
+
dual_variables = {}
|
|
249
|
+
for constraint in data.constrs:
|
|
250
|
+
pi = constraint.pi
|
|
251
|
+
if pi is not None:
|
|
252
|
+
id = int(constraint.name)
|
|
253
|
+
dual_variables[id] = pi
|
|
254
|
+
for constraint_id, dual_value in dual_variables.items():
|
|
255
|
+
solution.set_dual_variable(constraint_id, dual_value)
|
|
256
|
+
|
|
257
|
+
if data.status == mip.OptimizationStatus.OPTIMAL:
|
|
258
|
+
solution.optimality = Solution.OPTIMAL
|
|
259
|
+
|
|
260
|
+
if self._relax:
|
|
261
|
+
solution.relaxation = Solution.LP_RELAXED
|
|
262
|
+
return solution
|
|
255
263
|
|
|
256
264
|
def decode_to_state(self, data: mip.Model) -> State:
|
|
257
265
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ommx_python_mip_adapter
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.0a4
|
|
4
4
|
Summary: An adapter for the Python-MIP from/to OMMX.
|
|
5
5
|
Author-email: "Jij Inc." <info@j-ij.com>
|
|
6
6
|
Project-URL: Repository, https://github.com/Jij-Inc/ommx
|
|
@@ -15,7 +15,7 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
15
15
|
Classifier: License :: OSI Approved :: MIT License
|
|
16
16
|
Requires-Python: >=3.10
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
|
-
Requires-Dist: ommx<4.0.0,>=3.0.
|
|
18
|
+
Requires-Dist: ommx<4.0.0,>=3.0.0a4
|
|
19
19
|
Requires-Dist: mip<2.0.0,>=1.17.0
|
|
20
20
|
Requires-Dist: cffi<2.0.0,>=1.15.0
|
|
21
21
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ommx_python_mip_adapter"
|
|
7
|
-
version = "3.0.
|
|
7
|
+
version = "3.0.0a4"
|
|
8
8
|
|
|
9
9
|
description = "An adapter for the Python-MIP from/to OMMX."
|
|
10
10
|
authors = [{ name = "Jij Inc.", email = "info@j-ij.com" }]
|
|
@@ -23,7 +23,7 @@ classifiers = [
|
|
|
23
23
|
]
|
|
24
24
|
|
|
25
25
|
dependencies = [
|
|
26
|
-
"ommx >= 3.0.
|
|
26
|
+
"ommx >= 3.0.0a4, < 4.0.0",
|
|
27
27
|
"mip >= 1.17.0, < 2.0.0",
|
|
28
28
|
"cffi >= 1.15.0, < 2.0.0",
|
|
29
29
|
]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from ommx.tracing import capture_trace
|
|
2
|
+
from ommx.v1 import DecisionVariable, Instance
|
|
3
|
+
|
|
4
|
+
from ommx_python_mip_adapter import OMMXPythonMIPAdapter
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_solve_emits_convert_solve_decode_spans():
|
|
8
|
+
x = [DecisionVariable.binary(i) for i in range(3)]
|
|
9
|
+
instance = Instance.from_components(
|
|
10
|
+
decision_variables=x,
|
|
11
|
+
objective=x[0] + x[1] + x[2],
|
|
12
|
+
constraints={0: x[0] + x[1] + x[2] <= 2},
|
|
13
|
+
sense=Instance.MINIMIZE,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
with capture_trace() as result:
|
|
17
|
+
OMMXPythonMIPAdapter.solve(instance)
|
|
18
|
+
|
|
19
|
+
names = [s.name for s in result.spans]
|
|
20
|
+
assert "convert" in names
|
|
21
|
+
assert "solve" in names
|
|
22
|
+
assert "decode" in names
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_manual_flow_emits_convert_and_decode_spans():
|
|
26
|
+
x = [DecisionVariable.binary(i) for i in range(3)]
|
|
27
|
+
instance = Instance.from_components(
|
|
28
|
+
decision_variables=x,
|
|
29
|
+
objective=x[0] + x[1] + x[2],
|
|
30
|
+
constraints={0: x[0] + x[1] + x[2] <= 2},
|
|
31
|
+
sense=Instance.MINIMIZE,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
with capture_trace() as result:
|
|
35
|
+
adapter = OMMXPythonMIPAdapter(instance)
|
|
36
|
+
model = adapter.solver_input
|
|
37
|
+
model.optimize()
|
|
38
|
+
adapter.decode(model)
|
|
39
|
+
|
|
40
|
+
names = [s.name for s in result.spans]
|
|
41
|
+
assert "convert" in names
|
|
42
|
+
assert "decode" in names
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/tests/test_integration.py
RENAMED
|
File without changes
|
{ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/tests/test_model_to_instance.py
RENAMED
|
File without changes
|