ommx-python-mip-adapter 1.3.2__tar.gz → 1.4.0__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 (17) hide show
  1. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/PKG-INFO +5 -5
  2. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/README.md +3 -3
  3. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter/__init__.py +2 -0
  4. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter/ommx_to_python_mip.py +3 -17
  5. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter/python_mip_to_ommx.py +55 -4
  6. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter.egg-info/PKG-INFO +5 -5
  7. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter.egg-info/requires.txt +1 -1
  8. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/pyproject.toml +2 -2
  9. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/tests/test_integration.py +7 -9
  10. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter/exception.py +0 -0
  11. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter.egg-info/SOURCES.txt +0 -0
  12. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter.egg-info/dependency_links.txt +0 -0
  13. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter.egg-info/top_level.txt +0 -0
  14. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/setup.cfg +0 -0
  15. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/tests/test_constant_constraint.py +0 -0
  16. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/tests/test_instance_to_model.py +0 -0
  17. {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/tests/test_model_to_instance.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ommx_python_mip_adapter
3
- Version: 1.3.2
3
+ Version: 1.4.0
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-python-mip-adapter
@@ -14,7 +14,7 @@ Classifier: License :: OSI Approved :: Apache Software License
14
14
  Classifier: License :: OSI Approved :: MIT License
15
15
  Requires-Python: >=3.8
16
16
  Description-Content-Type: text/markdown
17
- Requires-Dist: ommx<2.0.0,>=1.3.2
17
+ Requires-Dist: ommx<2.0.0,>=1.4.0
18
18
  Requires-Dist: mip<2.0.0,>=1.15.0
19
19
  Provides-Extra: dev
20
20
  Requires-Dist: markdown-code-runner; extra == "dev"
@@ -47,7 +47,7 @@ sequenceDiagram
47
47
  P->>P: Solve with CBC, Gurobi, or other solvers
48
48
  P->>U: Optimized model
49
49
  U->>A: Optimized model and ommx.v1.Instance
50
- A->>U: ommx:SolutionList
50
+ A->>U: ommx.v1.Solution
51
51
  ```
52
52
 
53
53
  Python-MIP as a user interface to create OMMX instance
@@ -90,9 +90,9 @@ ommx_instance = Instance.from_components(
90
90
  model = adapter.instance_to_model(ommx_instance)
91
91
  model.optimize()
92
92
  # Create `ommx.v1.State` from Optimized `mip.Model`
93
- ommx_solutions = adapter.model_to_solution(model, ommx_instance)
93
+ ommx_state = adapter.model_to_state(model, ommx_instance)
94
94
 
95
- print(ommx_solutions)
95
+ print(ommx_state)
96
96
  ```
97
97
 
98
98
  You can get `ommx.v1.Instance` from a Python-MIP model as the following:
@@ -17,7 +17,7 @@ sequenceDiagram
17
17
  P->>P: Solve with CBC, Gurobi, or other solvers
18
18
  P->>U: Optimized model
19
19
  U->>A: Optimized model and ommx.v1.Instance
20
- A->>U: ommx:SolutionList
20
+ A->>U: ommx.v1.Solution
21
21
  ```
22
22
 
23
23
  Python-MIP as a user interface to create OMMX instance
@@ -60,9 +60,9 @@ ommx_instance = Instance.from_components(
60
60
  model = adapter.instance_to_model(ommx_instance)
61
61
  model.optimize()
62
62
  # Create `ommx.v1.State` from Optimized `mip.Model`
63
- ommx_solutions = adapter.model_to_solution(model, ommx_instance)
63
+ ommx_state = adapter.model_to_state(model, ommx_instance)
64
64
 
65
- print(ommx_solutions)
65
+ print(ommx_state)
66
66
  ```
67
67
 
68
68
  You can get `ommx.v1.Instance` from a Python-MIP model as the following:
@@ -2,12 +2,14 @@ from .ommx_to_python_mip import PythonMIPBuilder, instance_to_model, solve
2
2
  from .python_mip_to_ommx import (
3
3
  OMMXInstanceBuilder,
4
4
  model_to_instance,
5
+ model_to_state,
5
6
  model_to_solution,
6
7
  )
7
8
 
8
9
  __all__ = [
9
10
  "instance_to_model",
10
11
  "model_to_instance",
12
+ "model_to_state",
11
13
  "model_to_solution",
12
14
  "PythonMIPBuilder",
13
15
  "OMMXInstanceBuilder",
@@ -154,8 +154,8 @@ def instance_to_model(
154
154
  >>> model.optimize()
155
155
  <OptimizationStatus.OPTIMAL: 0>
156
156
 
157
- >>> ommx_solutions = adapter.model_to_solution(model, ommx_instance)
158
- >>> ommx_solutions.entries
157
+ >>> ommx_state = adapter.model_to_state(model, ommx_instance)
158
+ >>> ommx_state.entries
159
159
  {1: 0.0}
160
160
  """
161
161
  builder = PythonMIPBuilder(
@@ -303,10 +303,7 @@ def solve(
303
303
  ]:
304
304
  return Result(error=f"Unknown status: {model.status}")
305
305
 
306
- state = model_to_solution(model, instance)
307
- solution = instance.evaluate(state)
308
-
309
- assert solution.raw.feasible
306
+ solution = model_to_solution(model, instance)
310
307
 
311
308
  if model.status == mip.OptimizationStatus.OPTIMAL:
312
309
  solution.raw.optimality = Optimality.OPTIMALITY_OPTIMAL
@@ -314,15 +311,4 @@ def solve(
314
311
  if relax:
315
312
  solution.raw.relaxation = Relaxation.RELAXATION_LP_RELAXED
316
313
 
317
- dual_variables = {}
318
- for constraint in model.constrs:
319
- pi = constraint.pi
320
- if pi is not None:
321
- id = int(constraint.name)
322
- dual_variables[id] = pi
323
- for constraint in solution.raw.evaluated_constraints:
324
- id = constraint.id
325
- if id in dual_variables:
326
- constraint.dual_variable = dual_variables[id]
327
-
328
314
  return Result(solution=solution.raw)
@@ -8,7 +8,7 @@ from ommx.v1.constraint_pb2 import Constraint, Equality
8
8
  from ommx.v1.function_pb2 import Function
9
9
  from ommx.v1.linear_pb2 import Linear
10
10
  from ommx.v1.solution_pb2 import State
11
- from ommx.v1 import Instance, DecisionVariable
11
+ from ommx.v1 import Instance, DecisionVariable, Solution
12
12
 
13
13
  from .exception import OMMXPythonMIPAdapterError
14
14
 
@@ -152,7 +152,7 @@ def model_to_instance(model: mip.Model) -> Instance:
152
152
  return builder.build()
153
153
 
154
154
 
155
- def model_to_solution(
155
+ def model_to_state(
156
156
  model: mip.Model,
157
157
  instance: Instance,
158
158
  ) -> State:
@@ -180,8 +180,8 @@ def model_to_solution(
180
180
  >>> model.optimize()
181
181
  <OptimizationStatus.OPTIMAL: 0>
182
182
 
183
- >>> ommx_solutions = adapter.model_to_solution(model, ommx_instance)
184
- >>> ommx_solutions.entries
183
+ >>> ommx_state = adapter.model_to_state(model, ommx_instance)
184
+ >>> ommx_state.entries
185
185
  {1: 0.0}
186
186
  """
187
187
  if not (
@@ -198,3 +198,54 @@ def model_to_solution(
198
198
  for var in instance.raw.decision_variables
199
199
  }
200
200
  )
201
+
202
+
203
+ def model_to_solution(
204
+ model: mip.Model,
205
+ instance: Instance,
206
+ ) -> Solution:
207
+ """
208
+ Convert optimized Python-MIP model and ommx.v1.Instance to ommx.v1.Solution.
209
+
210
+ Examples
211
+ =========
212
+
213
+ .. doctest::
214
+
215
+ >>> from ommx.v1 import Instance, DecisionVariable
216
+ >>> from ommx_python_mip_adapter import instance_to_model, model_to_solution
217
+
218
+ >>> p = [10, 13, 18, 31, 7, 15]
219
+ >>> w = [11, 15, 20, 35, 10, 33]
220
+ >>> x = [DecisionVariable.binary(i) for i in range(6)]
221
+ >>> instance = Instance.from_components(
222
+ ... decision_variables=x,
223
+ ... objective=sum(p[i] * x[i] for i in range(6)),
224
+ ... constraints=[sum(w[i] * x[i] for i in range(6)) <= 47],
225
+ ... sense=Instance.MAXIMIZE,
226
+ ... )
227
+
228
+ >>> model = instance_to_model(instance)
229
+ >>> model.optimize()
230
+ <OptimizationStatus.OPTIMAL: 0>
231
+
232
+ >>> solution = model_to_solution(model, instance)
233
+ >>> solution.raw.objective
234
+ 41.0
235
+
236
+ """
237
+ state = model_to_state(model, instance)
238
+ solution = instance.evaluate(state)
239
+
240
+ dual_variables = {}
241
+ for constraint in model.constrs:
242
+ pi = constraint.pi
243
+ if pi is not None:
244
+ id = int(constraint.name)
245
+ dual_variables[id] = pi
246
+ for constraint in solution.raw.evaluated_constraints:
247
+ id = constraint.id
248
+ if id in dual_variables:
249
+ constraint.dual_variable = dual_variables[id]
250
+
251
+ return solution
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ommx_python_mip_adapter
3
- Version: 1.3.2
3
+ Version: 1.4.0
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-python-mip-adapter
@@ -14,7 +14,7 @@ Classifier: License :: OSI Approved :: Apache Software License
14
14
  Classifier: License :: OSI Approved :: MIT License
15
15
  Requires-Python: >=3.8
16
16
  Description-Content-Type: text/markdown
17
- Requires-Dist: ommx<2.0.0,>=1.3.2
17
+ Requires-Dist: ommx<2.0.0,>=1.4.0
18
18
  Requires-Dist: mip<2.0.0,>=1.15.0
19
19
  Provides-Extra: dev
20
20
  Requires-Dist: markdown-code-runner; extra == "dev"
@@ -47,7 +47,7 @@ sequenceDiagram
47
47
  P->>P: Solve with CBC, Gurobi, or other solvers
48
48
  P->>U: Optimized model
49
49
  U->>A: Optimized model and ommx.v1.Instance
50
- A->>U: ommx:SolutionList
50
+ A->>U: ommx.v1.Solution
51
51
  ```
52
52
 
53
53
  Python-MIP as a user interface to create OMMX instance
@@ -90,9 +90,9 @@ ommx_instance = Instance.from_components(
90
90
  model = adapter.instance_to_model(ommx_instance)
91
91
  model.optimize()
92
92
  # Create `ommx.v1.State` from Optimized `mip.Model`
93
- ommx_solutions = adapter.model_to_solution(model, ommx_instance)
93
+ ommx_state = adapter.model_to_state(model, ommx_instance)
94
94
 
95
- print(ommx_solutions)
95
+ print(ommx_state)
96
96
  ```
97
97
 
98
98
  You can get `ommx.v1.Instance` from a Python-MIP model as the following:
@@ -1,4 +1,4 @@
1
- ommx<2.0.0,>=1.3.2
1
+ ommx<2.0.0,>=1.4.0
2
2
  mip<2.0.0,>=1.15.0
3
3
 
4
4
  [dev]
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ommx_python_mip_adapter"
7
- version = "1.3.2"
7
+ version = "1.4.0"
8
8
 
9
9
  description = "An adapter for the Python-MIP from/to OMMX."
10
10
  authors = [
@@ -23,7 +23,7 @@ classifiers = [
23
23
  "License :: OSI Approved :: MIT License",
24
24
  ]
25
25
  dependencies = [
26
- "ommx >= 1.3.2, < 2.0.0",
26
+ "ommx >= 1.4.0, < 2.0.0",
27
27
 
28
28
  # FIXME: This project requires latest version of Python-MIP (will be 1.16.0?), which does not release yet.
29
29
  # https://github.com/coin-or/python-mip/issues/384
@@ -21,13 +21,11 @@ def test_integration_lp(generater):
21
21
 
22
22
  model = adapter.instance_to_model(ommx_instance_bytes)
23
23
  model.optimize()
24
- ommx_solution = adapter.model_to_solution(model, ommx_instance_bytes)
24
+ ommx_state = adapter.model_to_state(model, ommx_instance_bytes)
25
25
  expected_solution = generater.get_v1_state()
26
- assert ommx_solution.entries.keys() == expected_solution.entries.keys()
27
- for key in ommx_solution.entries.keys():
28
- assert ommx_solution.entries[key] == pytest.approx(
29
- expected_solution.entries[key]
30
- )
26
+ assert ommx_state.entries.keys() == expected_solution.entries.keys()
27
+ for key in ommx_state.entries.keys():
28
+ assert ommx_state.entries[key] == pytest.approx(expected_solution.entries[key])
31
29
 
32
30
 
33
31
  def test_integration_milp():
@@ -54,7 +52,7 @@ def test_integration_milp():
54
52
 
55
53
  model = adapter.instance_to_model(ommx_instance)
56
54
  model.optimize()
57
- ommx_solution = adapter.model_to_solution(model, ommx_instance)
55
+ ommx_state = adapter.model_to_state(model, ommx_instance)
58
56
 
59
- assert ommx_solution.entries[1] == pytest.approx(3)
60
- assert ommx_solution.entries[2] == pytest.approx(3)
57
+ assert ommx_state.entries[1] == pytest.approx(3)
58
+ assert ommx_state.entries[2] == pytest.approx(3)