ommx-python-mip-adapter 3.0.0b4__tar.gz → 3.0.0b6__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.0b4 → ommx_python_mip_adapter-3.0.0b6}/PKG-INFO +4 -4
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/README.md +2 -2
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/ommx_python_mip_adapter/adapter.py +26 -21
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/ommx_python_mip_adapter/python_mip_to_ommx.py +14 -6
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/ommx_python_mip_adapter.egg-info/PKG-INFO +4 -4
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/ommx_python_mip_adapter.egg-info/requires.txt +1 -1
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/pyproject.toml +2 -2
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/tests/test_adapter.py +25 -8
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/tests/test_constant_constraint.py +3 -3
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/tests/test_integration.py +9 -9
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/tests/test_model_to_instance.py +13 -13
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/tests/test_tracing.py +3 -3
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/ommx_python_mip_adapter/__init__.py +0 -0
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/ommx_python_mip_adapter/exception.py +0 -0
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/ommx_python_mip_adapter.egg-info/SOURCES.txt +0 -0
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/ommx_python_mip_adapter.egg-info/dependency_links.txt +0 -0
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/ommx_python_mip_adapter.egg-info/top_level.txt +0 -0
- {ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/setup.cfg +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.0b6
|
|
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.0b6
|
|
19
19
|
Requires-Dist: mip<2.0.0,>=1.17.0
|
|
20
20
|
Requires-Dist: cffi<2.0.0,>=1.15.0
|
|
21
21
|
|
|
@@ -67,14 +67,14 @@ Python-MIP can be used through `ommx-python-mip-adapter` by using the following:
|
|
|
67
67
|
|
|
68
68
|
```python markdown-code-runner
|
|
69
69
|
from ommx_python_mip_adapter import OMMXPythonMIPAdapter
|
|
70
|
-
from ommx import Instance,
|
|
70
|
+
from ommx import DecisionVariable, Instance, Sense
|
|
71
71
|
|
|
72
72
|
x1 = DecisionVariable.integer(1, lower=0, upper=5)
|
|
73
73
|
ommx_instance = Instance.from_components(
|
|
74
74
|
decision_variables=[x1],
|
|
75
75
|
objective=x1,
|
|
76
76
|
constraints={},
|
|
77
|
-
sense=
|
|
77
|
+
sense=Sense.Minimize,
|
|
78
78
|
)
|
|
79
79
|
|
|
80
80
|
# Create `ommx.Solution` from the `mip.Model`
|
|
@@ -46,14 +46,14 @@ Python-MIP can be used through `ommx-python-mip-adapter` by using the following:
|
|
|
46
46
|
|
|
47
47
|
```python markdown-code-runner
|
|
48
48
|
from ommx_python_mip_adapter import OMMXPythonMIPAdapter
|
|
49
|
-
from ommx import Instance,
|
|
49
|
+
from ommx import DecisionVariable, Instance, Sense
|
|
50
50
|
|
|
51
51
|
x1 = DecisionVariable.integer(1, lower=0, upper=5)
|
|
52
52
|
ommx_instance = Instance.from_components(
|
|
53
53
|
decision_variables=[x1],
|
|
54
54
|
objective=x1,
|
|
55
55
|
constraints={},
|
|
56
|
-
sense=
|
|
56
|
+
sense=Sense.Minimize,
|
|
57
57
|
)
|
|
58
58
|
|
|
59
59
|
# Create `ommx.Solution` from the `mip.Model`
|
|
@@ -14,15 +14,13 @@ from ommx.adapter import (
|
|
|
14
14
|
NoSolutionReturned,
|
|
15
15
|
)
|
|
16
16
|
from ommx import (
|
|
17
|
-
Constraint,
|
|
18
|
-
DecisionVariable,
|
|
19
|
-
DegreeBound,
|
|
20
17
|
Equality,
|
|
21
18
|
Function,
|
|
22
19
|
Instance,
|
|
23
20
|
InstanceClass,
|
|
24
21
|
InstanceClassClause,
|
|
25
22
|
Kind,
|
|
23
|
+
PolynomialRequirement,
|
|
26
24
|
PreparationPolicy,
|
|
27
25
|
Sense,
|
|
28
26
|
Solution,
|
|
@@ -35,9 +33,9 @@ from .exception import OMMXPythonMIPAdapterError
|
|
|
35
33
|
|
|
36
34
|
_tracer = trace.get_tracer("ommx.adapter.python_mip")
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
Equality.EqualToZero:
|
|
40
|
-
Equality.LessThanOrEqualToZero:
|
|
36
|
+
_LINEAR_CONSTRAINT_POLYNOMIAL_REQUIREMENTS = {
|
|
37
|
+
Equality.EqualToZero: PolynomialRequirement.at_most(1),
|
|
38
|
+
Equality.LessThanOrEqualToZero: PolynomialRequirement.at_most(1),
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
|
|
@@ -47,8 +45,10 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
47
45
|
InstanceClassClause(
|
|
48
46
|
label="python-mip-linear-mip",
|
|
49
47
|
allowed_variable_kinds={Kind.Binary, Kind.Integer, Kind.Continuous},
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
objective_polynomial_requirement=PolynomialRequirement.at_most(1),
|
|
49
|
+
regular_constraint_polynomial_requirements=(
|
|
50
|
+
_LINEAR_CONSTRAINT_POLYNOMIAL_REQUIREMENTS
|
|
51
|
+
),
|
|
52
52
|
allowed_senses={Sense.Minimize, Sense.Maximize},
|
|
53
53
|
)
|
|
54
54
|
]
|
|
@@ -92,9 +92,9 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
92
92
|
"""
|
|
93
93
|
with _tracer.start_as_current_span("convert"):
|
|
94
94
|
self.require_applicable(ommx_instance)
|
|
95
|
-
if ommx_instance.sense ==
|
|
95
|
+
if ommx_instance.sense == Sense.Maximize:
|
|
96
96
|
sense = mip.MAXIMIZE
|
|
97
|
-
elif ommx_instance.sense ==
|
|
97
|
+
elif ommx_instance.sense == Sense.Minimize:
|
|
98
98
|
sense = mip.MINIMIZE
|
|
99
99
|
else:
|
|
100
100
|
raise OMMXPythonMIPAdapterError(
|
|
@@ -157,7 +157,7 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
157
157
|
... decision_variables=x,
|
|
158
158
|
... objective=sum(p[i] * x[i] for i in range(6)),
|
|
159
159
|
... constraints={0: sum(w[i] * x[i] for i in range(6)) <= 47},
|
|
160
|
-
... sense=
|
|
160
|
+
... sense=Sense.Maximize,
|
|
161
161
|
... )
|
|
162
162
|
|
|
163
163
|
Solve it
|
|
@@ -192,7 +192,7 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
192
192
|
... decision_variables=[x],
|
|
193
193
|
... objective=x,
|
|
194
194
|
... constraints={0: x >= 4},
|
|
195
|
-
... sense=
|
|
195
|
+
... sense=Sense.Maximize,
|
|
196
196
|
... )
|
|
197
197
|
|
|
198
198
|
>>> OMMXPythonMIPAdapter.solve(instance)
|
|
@@ -212,7 +212,7 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
212
212
|
... decision_variables=[x],
|
|
213
213
|
... objective=x,
|
|
214
214
|
... constraints={},
|
|
215
|
-
... sense=
|
|
215
|
+
... sense=Sense.Maximize,
|
|
216
216
|
... )
|
|
217
217
|
|
|
218
218
|
>>> OMMXPythonMIPAdapter.solve(instance)
|
|
@@ -233,7 +233,7 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
233
233
|
... decision_variables=[x, y],
|
|
234
234
|
... objective=x + y,
|
|
235
235
|
... constraints={0: x + y <= 1},
|
|
236
|
-
... sense=
|
|
236
|
+
... sense=Sense.Maximize,
|
|
237
237
|
... )
|
|
238
238
|
|
|
239
239
|
>>> solution = OMMXPythonMIPAdapter.solve(instance)
|
|
@@ -313,7 +313,7 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
313
313
|
... decision_variables=x,
|
|
314
314
|
... objective=sum(p[i] * x[i] for i in range(6)),
|
|
315
315
|
... constraints={0: sum(w[i] * x[i] for i in range(6)) <= 47},
|
|
316
|
-
... sense=
|
|
316
|
+
... sense=Sense.Maximize,
|
|
317
317
|
... )
|
|
318
318
|
|
|
319
319
|
>>> adapter = OMMXPythonMIPAdapter(instance)
|
|
@@ -371,7 +371,7 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
371
371
|
... decision_variables=[x1],
|
|
372
372
|
... objective=x1,
|
|
373
373
|
... constraints={},
|
|
374
|
-
... sense=
|
|
374
|
+
... sense=Sense.Minimize,
|
|
375
375
|
... )
|
|
376
376
|
>>> adapter = OMMXPythonMIPAdapter(ommx_instance)
|
|
377
377
|
>>> model = adapter.solver_input
|
|
@@ -414,19 +414,19 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
414
414
|
|
|
415
415
|
def _set_decision_variables(self):
|
|
416
416
|
for var in self.instance.used_decision_variables:
|
|
417
|
-
if var.kind ==
|
|
417
|
+
if var.kind == Kind.Binary:
|
|
418
418
|
self.model.add_var(
|
|
419
419
|
name=str(var.id),
|
|
420
420
|
var_type=mip.BINARY,
|
|
421
421
|
)
|
|
422
|
-
elif var.kind ==
|
|
422
|
+
elif var.kind == Kind.Integer:
|
|
423
423
|
self.model.add_var(
|
|
424
424
|
name=str(var.id),
|
|
425
425
|
var_type=mip.INTEGER,
|
|
426
426
|
lb=var.bound.lower, # type: ignore
|
|
427
427
|
ub=var.bound.upper, # type: ignore
|
|
428
428
|
)
|
|
429
|
-
elif var.kind ==
|
|
429
|
+
elif var.kind == Kind.Continuous:
|
|
430
430
|
self.model.add_var(
|
|
431
431
|
name=str(var.id),
|
|
432
432
|
var_type=mip.CONTINUOUS,
|
|
@@ -447,6 +447,11 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
447
447
|
Translate ommx.Function to `mip.LinExpr` or `float`.
|
|
448
448
|
"""
|
|
449
449
|
degree = f.degree()
|
|
450
|
+
if degree is None:
|
|
451
|
+
raise OMMXPythonMIPAdapterError(
|
|
452
|
+
"Non-polynomial functions are not supported. "
|
|
453
|
+
"Only linear (degree 1) and constant (degree 0) functions are supported."
|
|
454
|
+
)
|
|
450
455
|
constant = f.constant_term
|
|
451
456
|
if degree > 1:
|
|
452
457
|
raise OMMXPythonMIPAdapterError(
|
|
@@ -470,9 +475,9 @@ class OMMXPythonMIPAdapter(SolverAdapter):
|
|
|
470
475
|
def _set_constraints(self):
|
|
471
476
|
for cid, constraint in self.instance.constraints.items():
|
|
472
477
|
lin_expr = self._as_lin_expr(constraint.function)
|
|
473
|
-
if constraint.equality ==
|
|
478
|
+
if constraint.equality == Equality.EqualToZero:
|
|
474
479
|
constr_expr = lin_expr == 0
|
|
475
|
-
elif constraint.equality ==
|
|
480
|
+
elif constraint.equality == Equality.LessThanOrEqualToZero:
|
|
476
481
|
constr_expr = lin_expr <= 0 # type: ignore
|
|
477
482
|
else:
|
|
478
483
|
raise OMMXPythonMIPAdapterError(
|
|
@@ -4,7 +4,15 @@ from typing import final
|
|
|
4
4
|
import mip
|
|
5
5
|
|
|
6
6
|
from mip.exceptions import ParameterNotAvailable
|
|
7
|
-
from ommx import
|
|
7
|
+
from ommx import (
|
|
8
|
+
Constraint,
|
|
9
|
+
DecisionVariable,
|
|
10
|
+
Equality,
|
|
11
|
+
Function,
|
|
12
|
+
Instance,
|
|
13
|
+
Linear,
|
|
14
|
+
Sense,
|
|
15
|
+
)
|
|
8
16
|
|
|
9
17
|
from .exception import OMMXPythonMIPAdapterError
|
|
10
18
|
|
|
@@ -83,13 +91,13 @@ class OMMXInstanceBuilder:
|
|
|
83
91
|
if lin_expr.sense == "=":
|
|
84
92
|
constraint = Constraint(
|
|
85
93
|
function=self.as_ommx_function(lin_expr),
|
|
86
|
-
equality=
|
|
94
|
+
equality=Equality.EqualToZero,
|
|
87
95
|
name=name,
|
|
88
96
|
)
|
|
89
97
|
elif lin_expr.sense == "<":
|
|
90
98
|
constraint = Constraint(
|
|
91
99
|
function=self.as_ommx_function(lin_expr),
|
|
92
|
-
equality=
|
|
100
|
+
equality=Equality.LessThanOrEqualToZero,
|
|
93
101
|
name=name,
|
|
94
102
|
)
|
|
95
103
|
elif lin_expr.sense == ">":
|
|
@@ -97,7 +105,7 @@ class OMMXInstanceBuilder:
|
|
|
97
105
|
# So multiply the linear expression by -1.
|
|
98
106
|
constraint = Constraint(
|
|
99
107
|
function=self.as_ommx_function(-lin_expr),
|
|
100
|
-
equality=
|
|
108
|
+
equality=Equality.LessThanOrEqualToZero,
|
|
101
109
|
name=name,
|
|
102
110
|
)
|
|
103
111
|
else:
|
|
@@ -112,9 +120,9 @@ class OMMXInstanceBuilder:
|
|
|
112
120
|
|
|
113
121
|
def sense(self):
|
|
114
122
|
if self.model.sense == mip.MAXIMIZE:
|
|
115
|
-
return
|
|
123
|
+
return Sense.Maximize
|
|
116
124
|
elif self.model.sense == mip.MINIMIZE:
|
|
117
|
-
return
|
|
125
|
+
return Sense.Minimize
|
|
118
126
|
raise OMMXPythonMIPAdapterError(f"Not supported sense: {self.model.sense}")
|
|
119
127
|
|
|
120
128
|
@final
|
|
@@ -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.0b6
|
|
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.0b6
|
|
19
19
|
Requires-Dist: mip<2.0.0,>=1.17.0
|
|
20
20
|
Requires-Dist: cffi<2.0.0,>=1.15.0
|
|
21
21
|
|
|
@@ -67,14 +67,14 @@ Python-MIP can be used through `ommx-python-mip-adapter` by using the following:
|
|
|
67
67
|
|
|
68
68
|
```python markdown-code-runner
|
|
69
69
|
from ommx_python_mip_adapter import OMMXPythonMIPAdapter
|
|
70
|
-
from ommx import Instance,
|
|
70
|
+
from ommx import DecisionVariable, Instance, Sense
|
|
71
71
|
|
|
72
72
|
x1 = DecisionVariable.integer(1, lower=0, upper=5)
|
|
73
73
|
ommx_instance = Instance.from_components(
|
|
74
74
|
decision_variables=[x1],
|
|
75
75
|
objective=x1,
|
|
76
76
|
constraints={},
|
|
77
|
-
sense=
|
|
77
|
+
sense=Sense.Minimize,
|
|
78
78
|
)
|
|
79
79
|
|
|
80
80
|
# Create `ommx.Solution` from the `mip.Model`
|
|
@@ -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.0b6"
|
|
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.0b6, < 4.0.0",
|
|
27
27
|
"mip >= 1.17.0, < 2.0.0",
|
|
28
28
|
"cffi >= 1.15.0, < 2.0.0",
|
|
29
29
|
]
|
|
@@ -2,13 +2,14 @@ import pytest
|
|
|
2
2
|
|
|
3
3
|
from ommx import (
|
|
4
4
|
DecisionVariable,
|
|
5
|
-
DegreeBound,
|
|
6
5
|
Equality,
|
|
6
|
+
Function,
|
|
7
7
|
IndicatorConstraint,
|
|
8
8
|
Instance,
|
|
9
9
|
InstanceClassMismatch,
|
|
10
10
|
Kind,
|
|
11
11
|
OneHotConstraint,
|
|
12
|
+
PolynomialRequirement,
|
|
12
13
|
Sense,
|
|
13
14
|
Sos1Constraint,
|
|
14
15
|
)
|
|
@@ -26,12 +27,12 @@ def test_declares_linear_mip_input_class() -> None:
|
|
|
26
27
|
Kind.Integer,
|
|
27
28
|
Kind.Continuous,
|
|
28
29
|
}
|
|
29
|
-
assert clause.
|
|
30
|
-
assert clause.
|
|
31
|
-
Equality.EqualToZero:
|
|
32
|
-
Equality.LessThanOrEqualToZero:
|
|
30
|
+
assert clause.objective_polynomial_requirement == PolynomialRequirement.at_most(1)
|
|
31
|
+
assert clause.regular_constraint_polynomial_requirements == {
|
|
32
|
+
Equality.EqualToZero: PolynomialRequirement.at_most(1),
|
|
33
|
+
Equality.LessThanOrEqualToZero: PolynomialRequirement.at_most(1),
|
|
33
34
|
}
|
|
34
|
-
assert clause.
|
|
35
|
+
assert clause.indicator_body_polynomial_requirements == {}
|
|
35
36
|
assert not clause.allows_one_hot
|
|
36
37
|
assert not clause.allows_sos1
|
|
37
38
|
assert clause.allowed_senses == {Sense.Minimize, Sense.Maximize}
|
|
@@ -62,7 +63,7 @@ def test_error_nonlinear_objective():
|
|
|
62
63
|
decision_variables=[x],
|
|
63
64
|
objective=2.3 * x * x,
|
|
64
65
|
constraints={},
|
|
65
|
-
sense=
|
|
66
|
+
sense=Sense.Minimize,
|
|
66
67
|
)
|
|
67
68
|
|
|
68
69
|
with pytest.raises(AdapterNotApplicableError) as e:
|
|
@@ -73,6 +74,22 @@ def test_error_nonlinear_objective():
|
|
|
73
74
|
)
|
|
74
75
|
|
|
75
76
|
|
|
77
|
+
def test_error_non_polynomial_objective() -> None:
|
|
78
|
+
x = DecisionVariable.continuous(0)
|
|
79
|
+
instance = Instance.from_components(
|
|
80
|
+
decision_variables=[x],
|
|
81
|
+
objective=abs(Function(x)),
|
|
82
|
+
constraints={},
|
|
83
|
+
sense=Sense.Minimize,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
with pytest.raises(AdapterNotApplicableError) as error:
|
|
87
|
+
OMMXPythonMIPAdapter(instance)
|
|
88
|
+
|
|
89
|
+
[mismatch] = error.value.report.clause_reports[0].mismatches
|
|
90
|
+
assert isinstance(mismatch, InstanceClassMismatch.ObjectiveFunctionNotPolynomial)
|
|
91
|
+
|
|
92
|
+
|
|
76
93
|
def test_error_nonlinear_constraint():
|
|
77
94
|
# Objective function: 0
|
|
78
95
|
# Constraint: 2.3 * x * x = 0
|
|
@@ -81,7 +98,7 @@ def test_error_nonlinear_constraint():
|
|
|
81
98
|
decision_variables=[x],
|
|
82
99
|
objective=0.0,
|
|
83
100
|
constraints={0: 2.3 * x * x == 0},
|
|
84
|
-
sense=
|
|
101
|
+
sense=Sense.Minimize,
|
|
85
102
|
)
|
|
86
103
|
|
|
87
104
|
with pytest.raises(AdapterNotApplicableError) as e:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from ommx_python_mip_adapter import OMMXPythonMIPAdapter
|
|
2
|
-
from ommx import Instance,
|
|
2
|
+
from ommx import DecisionVariable, Instance, Linear, Sense
|
|
3
3
|
from ommx.adapter import InfeasibleDetected
|
|
4
4
|
import pytest
|
|
5
5
|
|
|
@@ -17,7 +17,7 @@ def test_constant_constraint_feasible():
|
|
|
17
17
|
Linear(terms={}, constant=1) >= 0,
|
|
18
18
|
1: x <= 1,
|
|
19
19
|
},
|
|
20
|
-
sense=
|
|
20
|
+
sense=Sense.Maximize,
|
|
21
21
|
)
|
|
22
22
|
solution = OMMXPythonMIPAdapter.solve(instance)
|
|
23
23
|
|
|
@@ -40,7 +40,7 @@ def test_constant_constraint_infeasible():
|
|
|
40
40
|
Linear(terms={}, constant=-1) >= 0,
|
|
41
41
|
1: x <= 1,
|
|
42
42
|
},
|
|
43
|
-
sense=
|
|
43
|
+
sense=Sense.Maximize,
|
|
44
44
|
)
|
|
45
45
|
with pytest.raises(InfeasibleDetected):
|
|
46
46
|
OMMXPythonMIPAdapter.solve(instance)
|
{ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/tests/test_integration.py
RENAMED
|
@@ -49,7 +49,7 @@ def test_integration_milp():
|
|
|
49
49
|
decision_variables=[x1, x2],
|
|
50
50
|
objective=-x1 - x2,
|
|
51
51
|
constraints={0: 3 * x1 - x2 <= 6, 1: -x1 + 3 * x2 <= 6},
|
|
52
|
-
sense=
|
|
52
|
+
sense=Sense.Minimize,
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
adapter = OMMXPythonMIPAdapter(ommx_instance)
|
|
@@ -68,7 +68,7 @@ def test_solution_optimality():
|
|
|
68
68
|
decision_variables=[x, y],
|
|
69
69
|
objective=x + y,
|
|
70
70
|
constraints={},
|
|
71
|
-
sense=
|
|
71
|
+
sense=Sense.Maximize,
|
|
72
72
|
)
|
|
73
73
|
|
|
74
74
|
solution = OMMXPythonMIPAdapter.solve(ommx_instance)
|
|
@@ -81,7 +81,7 @@ def test_solution_optimality_is_not_transported_through_fixed_penalty():
|
|
|
81
81
|
decision_variables=[x],
|
|
82
82
|
objective=x,
|
|
83
83
|
constraints={7: x == 1},
|
|
84
|
-
sense=
|
|
84
|
+
sense=Sense.Minimize,
|
|
85
85
|
)
|
|
86
86
|
instance.to_qubo(uniform_penalty_weight=0.0)
|
|
87
87
|
|
|
@@ -115,7 +115,7 @@ def test_partial_evaluate():
|
|
|
115
115
|
decision_variables=x,
|
|
116
116
|
objective=x[0] + x[1] + x[2],
|
|
117
117
|
constraints={0: x[0] + x[1] + x[2] <= 1}, # one-hot constraint
|
|
118
|
-
sense=
|
|
118
|
+
sense=Sense.Minimize,
|
|
119
119
|
)
|
|
120
120
|
assert instance.used_decision_variables == x
|
|
121
121
|
partial = instance.partial_evaluate({0: 1})
|
|
@@ -141,7 +141,7 @@ def test_relax_constraint():
|
|
|
141
141
|
decision_variables=x,
|
|
142
142
|
objective=x[0] + x[1],
|
|
143
143
|
constraints={0: x[0] + 2 * x[1] <= 1, 1: x[1] + x[2] <= 1},
|
|
144
|
-
sense=
|
|
144
|
+
sense=Sense.Minimize,
|
|
145
145
|
)
|
|
146
146
|
|
|
147
147
|
assert instance.used_decision_variables == x
|
|
@@ -182,7 +182,7 @@ def test_integration_timelimit():
|
|
|
182
182
|
decision_variables=x,
|
|
183
183
|
objective=sum(v[i] * x[i] for i in range(n)),
|
|
184
184
|
constraints={0: constraint},
|
|
185
|
-
sense=
|
|
185
|
+
sense=Sense.Maximize,
|
|
186
186
|
)
|
|
187
187
|
adapter = OMMXPythonMIPAdapter(instance)
|
|
188
188
|
model = adapter.solver_input
|
|
@@ -204,7 +204,7 @@ def test_infeasible_problem():
|
|
|
204
204
|
decision_variables=[x],
|
|
205
205
|
objective=x,
|
|
206
206
|
constraints={0: x >= 4},
|
|
207
|
-
sense=
|
|
207
|
+
sense=Sense.Maximize,
|
|
208
208
|
)
|
|
209
209
|
adapter = OMMXPythonMIPAdapter(instance)
|
|
210
210
|
model = adapter.solver_input
|
|
@@ -221,7 +221,7 @@ def test_unbounded_problem():
|
|
|
221
221
|
decision_variables=[x],
|
|
222
222
|
objective=x,
|
|
223
223
|
constraints={},
|
|
224
|
-
sense=
|
|
224
|
+
sense=Sense.Maximize,
|
|
225
225
|
)
|
|
226
226
|
adapter = OMMXPythonMIPAdapter(instance)
|
|
227
227
|
model = adapter.solver_input
|
|
@@ -237,7 +237,7 @@ def test_decode_before_optimize():
|
|
|
237
237
|
decision_variables=[x],
|
|
238
238
|
objective=x,
|
|
239
239
|
constraints={},
|
|
240
|
-
sense=
|
|
240
|
+
sense=Sense.Minimize,
|
|
241
241
|
)
|
|
242
242
|
adapter = OMMXPythonMIPAdapter(instance)
|
|
243
243
|
model = adapter.solver_input
|
{ommx_python_mip_adapter-3.0.0b4 → ommx_python_mip_adapter-3.0.0b6}/tests/test_model_to_instance.py
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import mip
|
|
2
2
|
|
|
3
|
-
from ommx import
|
|
3
|
+
from ommx import Equality, Kind, Sense
|
|
4
4
|
|
|
5
5
|
from ommx_python_mip_adapter import model_to_instance
|
|
6
6
|
|
|
@@ -45,25 +45,25 @@ def test_milp():
|
|
|
45
45
|
|
|
46
46
|
ommx_instance = model_to_instance(model)
|
|
47
47
|
|
|
48
|
-
assert ommx_instance.sense ==
|
|
48
|
+
assert ommx_instance.sense == Sense.Minimize
|
|
49
49
|
|
|
50
50
|
# Check the decision variables
|
|
51
51
|
assert len(ommx_instance.decision_variables) == 3
|
|
52
52
|
decision_variables_x1 = ommx_instance.get_decision_variable_by_id(0)
|
|
53
53
|
assert decision_variables_x1.id == 0
|
|
54
|
-
assert decision_variables_x1.kind ==
|
|
54
|
+
assert decision_variables_x1.kind == Kind.Continuous
|
|
55
55
|
assert decision_variables_x1.bound.lower == CONTINUOUS_LOWER_BOUND
|
|
56
56
|
assert decision_variables_x1.bound.upper == CONTINUOUS_UPPER_BOUND
|
|
57
57
|
assert decision_variables_x1.name == "1"
|
|
58
58
|
decision_variables_x2 = ommx_instance.get_decision_variable_by_id(1)
|
|
59
59
|
assert decision_variables_x2.id == 1
|
|
60
|
-
assert decision_variables_x2.kind ==
|
|
60
|
+
assert decision_variables_x2.kind == Kind.Integer
|
|
61
61
|
assert decision_variables_x2.bound.lower == INTEGER_LOWER_BOUND
|
|
62
62
|
assert decision_variables_x2.bound.upper == INTEGER_UPPER_BOUND
|
|
63
63
|
assert decision_variables_x2.name == "2"
|
|
64
64
|
decision_variables_x3 = ommx_instance.get_decision_variable_by_id(2)
|
|
65
65
|
assert decision_variables_x3.id == 2
|
|
66
|
-
assert decision_variables_x3.kind ==
|
|
66
|
+
assert decision_variables_x3.kind == Kind.Binary
|
|
67
67
|
assert decision_variables_x3.bound.lower == 0
|
|
68
68
|
assert decision_variables_x3.bound.upper == 1
|
|
69
69
|
assert decision_variables_x3.name == "3"
|
|
@@ -81,7 +81,7 @@ def test_milp():
|
|
|
81
81
|
assert len(ommx_instance.constraints) == 3
|
|
82
82
|
|
|
83
83
|
constraint1 = ommx_instance.get_constraint_by_id(0)
|
|
84
|
-
assert constraint1.equality ==
|
|
84
|
+
assert constraint1.equality == Equality.EqualToZero
|
|
85
85
|
assert constraint1.function.degree() == 1
|
|
86
86
|
assert constraint1.function.constant_term == 6
|
|
87
87
|
constraint1_terms = constraint1.function.linear_terms
|
|
@@ -90,7 +90,7 @@ def test_milp():
|
|
|
90
90
|
assert constraint1_terms[1] == -5
|
|
91
91
|
|
|
92
92
|
constraint2 = ommx_instance.get_constraint_by_id(1)
|
|
93
|
-
assert constraint2.equality ==
|
|
93
|
+
assert constraint2.equality == Equality.LessThanOrEqualToZero
|
|
94
94
|
assert constraint2.function.degree() == 1
|
|
95
95
|
assert constraint2.function.constant_term == -9
|
|
96
96
|
constraint2_terms = constraint2.function.linear_terms
|
|
@@ -99,7 +99,7 @@ def test_milp():
|
|
|
99
99
|
assert constraint2_terms[2] == 8
|
|
100
100
|
|
|
101
101
|
constraint3 = ommx_instance.get_constraint_by_id(2)
|
|
102
|
-
assert constraint3.equality ==
|
|
102
|
+
assert constraint3.equality == Equality.LessThanOrEqualToZero
|
|
103
103
|
assert constraint3.function.degree() == 1
|
|
104
104
|
assert constraint3.function.constant_term == -12
|
|
105
105
|
constraint3_terms = constraint3.function.linear_terms
|
|
@@ -138,19 +138,19 @@ def test_no_objective_model():
|
|
|
138
138
|
|
|
139
139
|
ommx_instance = model_to_instance(model)
|
|
140
140
|
|
|
141
|
-
assert ommx_instance.sense ==
|
|
141
|
+
assert ommx_instance.sense == Sense.Maximize
|
|
142
142
|
|
|
143
143
|
# Check the decision variables
|
|
144
144
|
assert len(ommx_instance.decision_variables) == 2
|
|
145
145
|
decision_variables_x1 = ommx_instance.get_decision_variable_by_id(0)
|
|
146
146
|
assert decision_variables_x1.id == 0
|
|
147
|
-
assert decision_variables_x1.kind ==
|
|
147
|
+
assert decision_variables_x1.kind == Kind.Continuous
|
|
148
148
|
assert decision_variables_x1.bound.lower == LOWER_BOUND
|
|
149
149
|
assert decision_variables_x1.bound.upper == UPPER_BOUND
|
|
150
150
|
assert decision_variables_x1.name == "1"
|
|
151
151
|
decision_variables_x2 = ommx_instance.get_decision_variable_by_id(1)
|
|
152
152
|
assert decision_variables_x2.id == 1
|
|
153
|
-
assert decision_variables_x2.kind ==
|
|
153
|
+
assert decision_variables_x2.kind == Kind.Continuous
|
|
154
154
|
assert decision_variables_x2.bound.lower == LOWER_BOUND
|
|
155
155
|
assert decision_variables_x2.bound.upper == UPPER_BOUND
|
|
156
156
|
assert decision_variables_x2.name == "2"
|
|
@@ -163,7 +163,7 @@ def test_no_objective_model():
|
|
|
163
163
|
assert len(ommx_instance.constraints) == 2
|
|
164
164
|
|
|
165
165
|
constraint1 = ommx_instance.get_constraint_by_id(0)
|
|
166
|
-
assert constraint1.equality ==
|
|
166
|
+
assert constraint1.equality == Equality.EqualToZero
|
|
167
167
|
assert constraint1.function.degree() == 1
|
|
168
168
|
assert constraint1.function.constant_term == -5
|
|
169
169
|
constraint1_terms = constraint1.function.linear_terms
|
|
@@ -172,7 +172,7 @@ def test_no_objective_model():
|
|
|
172
172
|
assert constraint1_terms[1] == 2
|
|
173
173
|
|
|
174
174
|
constraint2 = ommx_instance.get_constraint_by_id(1)
|
|
175
|
-
assert constraint2.equality ==
|
|
175
|
+
assert constraint2.equality == Equality.EqualToZero
|
|
176
176
|
assert constraint2.function.degree() == 1
|
|
177
177
|
assert constraint2.function.constant_term == -10
|
|
178
178
|
constraint2_terms = constraint2.function.linear_terms
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from ommx.tracing import capture_trace
|
|
2
|
-
from ommx import DecisionVariable, Instance
|
|
2
|
+
from ommx import DecisionVariable, Instance, Sense
|
|
3
3
|
|
|
4
4
|
from ommx_python_mip_adapter import OMMXPythonMIPAdapter
|
|
5
5
|
|
|
@@ -10,7 +10,7 @@ def test_solve_emits_convert_solve_decode_spans():
|
|
|
10
10
|
decision_variables=x,
|
|
11
11
|
objective=x[0] + x[1] + x[2],
|
|
12
12
|
constraints={0: x[0] + x[1] + x[2] <= 2},
|
|
13
|
-
sense=
|
|
13
|
+
sense=Sense.Minimize,
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
with capture_trace() as result:
|
|
@@ -29,7 +29,7 @@ def test_manual_flow_emits_convert_and_decode_spans():
|
|
|
29
29
|
decision_variables=x,
|
|
30
30
|
objective=x[0] + x[1] + x[2],
|
|
31
31
|
constraints={0: x[0] + x[1] + x[2] <= 2},
|
|
32
|
-
sense=
|
|
32
|
+
sense=Sense.Minimize,
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
with capture_trace() as result:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|