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.
- {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/PKG-INFO +5 -5
- {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/README.md +3 -3
- {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter/__init__.py +2 -0
- {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
- {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
- {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter.egg-info/PKG-INFO +5 -5
- {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter.egg-info/requires.txt +1 -1
- {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/pyproject.toml +2 -2
- {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/tests/test_integration.py +7 -9
- {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter/exception.py +0 -0
- {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter.egg-info/SOURCES.txt +0 -0
- {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
- {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
- {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/setup.cfg +0 -0
- {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/tests/test_constant_constraint.py +0 -0
- {ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/tests/test_instance_to_model.py +0 -0
- {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
|
+
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.
|
|
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
|
|
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
|
-
|
|
93
|
+
ommx_state = adapter.model_to_state(model, ommx_instance)
|
|
94
94
|
|
|
95
|
-
print(
|
|
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
|
|
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
|
-
|
|
63
|
+
ommx_state = adapter.model_to_state(model, ommx_instance)
|
|
64
64
|
|
|
65
|
-
print(
|
|
65
|
+
print(ommx_state)
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
You can get `ommx.v1.Instance` from a Python-MIP model as the following:
|
{ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter/__init__.py
RENAMED
|
@@ -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
|
-
>>>
|
|
158
|
-
>>>
|
|
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
|
-
|
|
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
|
|
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
|
-
>>>
|
|
184
|
-
>>>
|
|
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
|
+
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.
|
|
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
|
|
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
|
-
|
|
93
|
+
ommx_state = adapter.model_to_state(model, ommx_instance)
|
|
94
94
|
|
|
95
|
-
print(
|
|
95
|
+
print(ommx_state)
|
|
96
96
|
```
|
|
97
97
|
|
|
98
98
|
You can get `ommx.v1.Instance` from a Python-MIP model as the following:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ommx_python_mip_adapter"
|
|
7
|
-
version = "1.
|
|
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.
|
|
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
|
-
|
|
24
|
+
ommx_state = adapter.model_to_state(model, ommx_instance_bytes)
|
|
25
25
|
expected_solution = generater.get_v1_state()
|
|
26
|
-
assert
|
|
27
|
-
for key in
|
|
28
|
-
assert
|
|
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
|
-
|
|
55
|
+
ommx_state = adapter.model_to_state(model, ommx_instance)
|
|
58
56
|
|
|
59
|
-
assert
|
|
60
|
-
assert
|
|
57
|
+
assert ommx_state.entries[1] == pytest.approx(3)
|
|
58
|
+
assert ommx_state.entries[2] == pytest.approx(3)
|
{ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/ommx_python_mip_adapter/exception.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/tests/test_constant_constraint.py
RENAMED
|
File without changes
|
{ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/tests/test_instance_to_model.py
RENAMED
|
File without changes
|
{ommx_python_mip_adapter-1.3.2 → ommx_python_mip_adapter-1.4.0}/tests/test_model_to_instance.py
RENAMED
|
File without changes
|