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.
Files changed (18) hide show
  1. {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/PKG-INFO +2 -2
  2. {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter/adapter.py +52 -44
  3. {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter.egg-info/PKG-INFO +2 -2
  4. {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter.egg-info/SOURCES.txt +2 -1
  5. {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter.egg-info/requires.txt +1 -1
  6. {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/pyproject.toml +2 -2
  7. ommx_python_mip_adapter-3.0.0a4/tests/test_tracing.py +42 -0
  8. {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/README.md +0 -0
  9. {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter/__init__.py +0 -0
  10. {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/ommx_python_mip_adapter/exception.py +0 -0
  11. {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
  12. {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
  13. {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
  14. {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/setup.cfg +0 -0
  15. {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/tests/test_adapter.py +0 -0
  16. {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/tests/test_constant_constraint.py +0 -0
  17. {ommx_python_mip_adapter-3.0.0a2 → ommx_python_mip_adapter-3.0.0a4}/tests/test_integration.py +0 -0
  18. {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.0a2
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.0a2
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
- super().__init__(ommx_instance)
36
- if ommx_instance.sense == Instance.MAXIMIZE:
37
- sense = mip.MAXIMIZE
38
- elif ommx_instance.sense == Instance.MINIMIZE:
39
- sense = mip.MINIMIZE
40
- else:
41
- raise OMMXPythonMIPAdapterError(f"Unsupported sense: {ommx_instance.sense}")
42
- self.instance = ommx_instance
43
- self.model = mip.Model(
44
- sense=sense,
45
- solver_name=solver_name,
46
- solver=solver,
47
- )
48
- if verbose:
49
- self.model.verbose = 1
50
- else:
51
- self.model.verbose = 0
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
- self._set_decision_variables()
54
- self._set_objective()
55
- self._set_constraints()
59
+ self._set_decision_variables()
60
+ self._set_objective()
61
+ self._set_constraints()
56
62
 
57
- if relax:
58
- self.model.relax()
59
- self._relax = True
60
- else:
61
- self._relax = False
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
- model.optimize(relax=relax)
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
- state = self.decode_to_state(data)
238
- solution = self.instance.evaluate(state)
239
-
240
- dual_variables = {}
241
- for constraint in data.constrs:
242
- pi = constraint.pi
243
- if pi is not None:
244
- id = int(constraint.name)
245
- dual_variables[id] = pi
246
- for constraint_id, dual_value in dual_variables.items():
247
- solution.set_dual_variable(constraint_id, dual_value)
248
-
249
- if data.status == mip.OptimizationStatus.OPTIMAL:
250
- solution.optimality = Solution.OPTIMAL
251
-
252
- if self._relax:
253
- solution.relaxation = Solution.LP_RELAXED
254
- return solution
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.0a2
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.0a2
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
 
@@ -12,4 +12,5 @@ ommx_python_mip_adapter.egg-info/top_level.txt
12
12
  tests/test_adapter.py
13
13
  tests/test_constant_constraint.py
14
14
  tests/test_integration.py
15
- tests/test_model_to_instance.py
15
+ tests/test_model_to_instance.py
16
+ tests/test_tracing.py
@@ -1,3 +1,3 @@
1
- ommx<4.0.0,>=3.0.0a2
1
+ ommx<4.0.0,>=3.0.0a4
2
2
  mip<2.0.0,>=1.17.0
3
3
  cffi<2.0.0,>=1.15.0
@@ -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.0a2"
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.0a2, < 4.0.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