ommx-python-mip-adapter 0.1.1__tar.gz → 0.3.4__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 (28) hide show
  1. {ommx_python_mip_adapter-0.1.1 → ommx_python_mip_adapter-0.3.4}/PKG-INFO +24 -38
  2. {ommx_python_mip_adapter-0.1.1 → ommx_python_mip_adapter-0.3.4}/README.md +19 -32
  3. {ommx_python_mip_adapter-0.1.1 → ommx_python_mip_adapter-0.3.4}/ommx_python_mip_adapter/__init__.py +1 -1
  4. {ommx_python_mip_adapter-0.1.1 → ommx_python_mip_adapter-0.3.4}/ommx_python_mip_adapter/adapter.py +90 -142
  5. {ommx_python_mip_adapter-0.1.1 → ommx_python_mip_adapter-0.3.4}/ommx_python_mip_adapter.egg-info/PKG-INFO +24 -38
  6. {ommx_python_mip_adapter-0.1.1 → ommx_python_mip_adapter-0.3.4}/ommx_python_mip_adapter.egg-info/SOURCES.txt +1 -12
  7. {ommx_python_mip_adapter-0.1.1 → ommx_python_mip_adapter-0.3.4}/ommx_python_mip_adapter.egg-info/requires.txt +4 -3
  8. {ommx_python_mip_adapter-0.1.1 → ommx_python_mip_adapter-0.3.4}/pyproject.toml +14 -18
  9. ommx_python_mip_adapter-0.3.4/tests/test_instance_to_model.py +90 -0
  10. ommx_python_mip_adapter-0.3.4/tests/test_integration.py +60 -0
  11. {ommx_python_mip_adapter-0.1.1 → ommx_python_mip_adapter-0.3.4}/tests/test_model_to_instance.py +29 -33
  12. ommx_python_mip_adapter-0.1.1/.github/workflows/docs.yml +0 -72
  13. ommx_python_mip_adapter-0.1.1/.github/workflows/publish.yml +0 -49
  14. ommx_python_mip_adapter-0.1.1/.github/workflows/test_and_lint.yml +0 -75
  15. ommx_python_mip_adapter-0.1.1/.gitignore +0 -162
  16. ommx_python_mip_adapter-0.1.1/LICENSE-APACHE +0 -201
  17. ommx_python_mip_adapter-0.1.1/LICENSE-MIT +0 -21
  18. ommx_python_mip_adapter-0.1.1/docs/source/conf.py +0 -50
  19. ommx_python_mip_adapter-0.1.1/docs/source/index.rst +0 -20
  20. ommx_python_mip_adapter-0.1.1/ommx_python_mip_adapter/_version.py +0 -16
  21. ommx_python_mip_adapter-0.1.1/tests/conftest.py +0 -0
  22. ommx_python_mip_adapter-0.1.1/tests/test_instance_to_model.py +0 -127
  23. ommx_python_mip_adapter-0.1.1/tests/test_integration.py +0 -142
  24. ommx_python_mip_adapter-0.1.1/tests/test_model_to_solution.py +0 -27
  25. {ommx_python_mip_adapter-0.1.1 → ommx_python_mip_adapter-0.3.4}/ommx_python_mip_adapter/exception.py +0 -0
  26. {ommx_python_mip_adapter-0.1.1 → ommx_python_mip_adapter-0.3.4}/ommx_python_mip_adapter.egg-info/dependency_links.txt +0 -0
  27. {ommx_python_mip_adapter-0.1.1 → ommx_python_mip_adapter-0.3.4}/ommx_python_mip_adapter.egg-info/top_level.txt +0 -0
  28. {ommx_python_mip_adapter-0.1.1 → ommx_python_mip_adapter-0.3.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ommx_python_mip_adapter
3
- Version: 0.1.1
3
+ Version: 0.3.4
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
@@ -15,9 +15,7 @@ Classifier: License :: OSI Approved :: Apache Software License
15
15
  Classifier: License :: OSI Approved :: MIT License
16
16
  Requires-Python: >=3.8
17
17
  Description-Content-Type: text/markdown
18
- License-File: LICENSE-APACHE
19
- License-File: LICENSE-MIT
20
- Requires-Dist: ommx<0.3.0,>=0.2.0
18
+ Requires-Dist: ommx<0.4.0,>=0.3.4
21
19
  Requires-Dist: mip
22
20
  Provides-Extra: dev
23
21
  Requires-Dist: markdown-code-runner; extra == "dev"
@@ -25,16 +23,17 @@ Requires-Dist: mypy; extra == "dev"
25
23
  Requires-Dist: numpy; extra == "dev"
26
24
  Requires-Dist: pyright; extra == "dev"
27
25
  Requires-Dist: pytest; extra == "dev"
26
+ Requires-Dist: ruff; extra == "dev"
28
27
  Requires-Dist: sphinx; extra == "dev"
29
- Requires-Dist: sphinx_rtd_theme; extra == "dev"
30
- Requires-Dist: sphinx_fontawesome; extra == "dev"
31
28
  Requires-Dist: sphinx-autoapi; extra == "dev"
29
+ Requires-Dist: sphinx_fontawesome; extra == "dev"
30
+ Requires-Dist: sphinx_rtd_theme; extra == "dev"
32
31
 
33
- OMMX adaptor for Python-MIP
32
+ OMMX adapter for Python-MIP
34
33
  ============================
35
- ![PyPI - Version](https://img.shields.io/pypi/v/ommx-python-mip-adapter)
34
+ [![PyPI - Version](https://img.shields.io/pypi/v/ommx-python-mip-adapter)](https://pypi.org/project/ommx-python-mip-adapter/)
36
35
 
37
- This package provides an adaptor for the [Python-MIP](https://www.python-mip.com/) from/to [OMMX](https://github.com/Jij-Inc/ommx)
36
+ This package provides an adapter for the [Python-MIP](https://www.python-mip.com/) from/to [OMMX](https://github.com/Jij-Inc/ommx)
38
37
 
39
38
  Python-MIP as a solver in OMMX toolchain
40
39
  -----------------------------------------
@@ -78,43 +77,30 @@ Python-MIP can be used through `ommx-python-mip-adapter` by using the following:
78
77
 
79
78
  ```python markdown-code-runner
80
79
  import ommx_python_mip_adapter as adapter
81
- from ommx.v1.decision_variables_pb2 import DecisionVariable, Bound
82
- from ommx.v1.instance_pb2 import Instance
83
- from ommx.v1.function_pb2 import Function
84
- from ommx.v1.linear_pb2 import Linear
85
- from ommx.v1.solution_pb2 import SolutionList
86
-
87
- ommx_instance = Instance(
88
- decision_variables=[
89
- DecisionVariable(
90
- id=1,
91
- kind=DecisionVariable.KIND_INTEGER,
92
- bound=Bound(lower=0, upper=5),
93
- ),
94
- ],
95
- objective=Function(
96
- linear=Linear(
97
- terms=[Linear.Term(id=1, coefficient=1)]
98
- ),
99
- ),
80
+ from ommx.v1 import Instance, DecisionVariable
81
+
82
+ x1 = DecisionVariable.integer(1, lower=0, upper=5)
83
+ ommx_instance = Instance.from_components(
84
+ decision_variables=[x1],
85
+ objective=x1,
86
+ constraints=[],
87
+ sense=Instance.MINIMIZE,
100
88
  )
101
- ommx_instance_bytes = ommx_instance.SerializeToString()
102
89
 
103
90
  # Convert from `ommx.v1.Instance` to `mip.Model`
104
- model = adapter.instance_to_model(ommx_instance_bytes)
91
+ model = adapter.instance_to_model(ommx_instance)
105
92
  model.optimize()
106
- # Create `ommx.v1.SolutionList` from Optimized `mip.Model`
107
- ommx_solutions_bytes = adapter.model_to_solution(
108
- model, ommx_instance_bytes
109
- )
93
+ # Create `ommx.v1.State` from Optimized `mip.Model`
94
+ ommx_solutions = adapter.model_to_solution(model, ommx_instance)
110
95
 
111
- print(SolutionList.FromString(ommx_solutions_bytes))
96
+ print(ommx_solutions)
112
97
  ```
98
+
113
99
  You can get `ommx.v1.Instance` from a Python-MIP model as the following:
100
+
114
101
  ```python markdown-code-runner
115
102
  import mip
116
103
  import ommx_python_mip_adapter as adapter
117
- from ommx.v1.instance_pb2 import Instance
118
104
 
119
105
  model = mip.Model()
120
106
  x1=model.add_var(name="1", var_type=mip.INTEGER, lb=0, ub=5)
@@ -122,9 +108,9 @@ x2=model.add_var(name="2", var_type=mip.CONTINUOUS, lb=0, ub=5)
122
108
  model.objective = - x1 - 2 * x2
123
109
  model.add_constr(x1 + x2 - 6 <= 0)
124
110
 
125
- ommx_instance_bytes = adapter.model_to_instance(model)
111
+ ommx_instance = adapter.model_to_instance(model)
126
112
 
127
- print(Instance.FromString(ommx_instance_bytes))
113
+ print(ommx_instance)
128
114
  ```
129
115
 
130
116
  Reference
@@ -1,8 +1,8 @@
1
- OMMX adaptor for Python-MIP
1
+ OMMX adapter for Python-MIP
2
2
  ============================
3
- ![PyPI - Version](https://img.shields.io/pypi/v/ommx-python-mip-adapter)
3
+ [![PyPI - Version](https://img.shields.io/pypi/v/ommx-python-mip-adapter)](https://pypi.org/project/ommx-python-mip-adapter/)
4
4
 
5
- This package provides an adaptor for the [Python-MIP](https://www.python-mip.com/) from/to [OMMX](https://github.com/Jij-Inc/ommx)
5
+ This package provides an adapter for the [Python-MIP](https://www.python-mip.com/) from/to [OMMX](https://github.com/Jij-Inc/ommx)
6
6
 
7
7
  Python-MIP as a solver in OMMX toolchain
8
8
  -----------------------------------------
@@ -46,43 +46,30 @@ Python-MIP can be used through `ommx-python-mip-adapter` by using the following:
46
46
 
47
47
  ```python markdown-code-runner
48
48
  import ommx_python_mip_adapter as adapter
49
- from ommx.v1.decision_variables_pb2 import DecisionVariable, Bound
50
- from ommx.v1.instance_pb2 import Instance
51
- from ommx.v1.function_pb2 import Function
52
- from ommx.v1.linear_pb2 import Linear
53
- from ommx.v1.solution_pb2 import SolutionList
54
-
55
- ommx_instance = Instance(
56
- decision_variables=[
57
- DecisionVariable(
58
- id=1,
59
- kind=DecisionVariable.KIND_INTEGER,
60
- bound=Bound(lower=0, upper=5),
61
- ),
62
- ],
63
- objective=Function(
64
- linear=Linear(
65
- terms=[Linear.Term(id=1, coefficient=1)]
66
- ),
67
- ),
49
+ from ommx.v1 import Instance, DecisionVariable
50
+
51
+ x1 = DecisionVariable.integer(1, lower=0, upper=5)
52
+ ommx_instance = Instance.from_components(
53
+ decision_variables=[x1],
54
+ objective=x1,
55
+ constraints=[],
56
+ sense=Instance.MINIMIZE,
68
57
  )
69
- ommx_instance_bytes = ommx_instance.SerializeToString()
70
58
 
71
59
  # Convert from `ommx.v1.Instance` to `mip.Model`
72
- model = adapter.instance_to_model(ommx_instance_bytes)
60
+ model = adapter.instance_to_model(ommx_instance)
73
61
  model.optimize()
74
- # Create `ommx.v1.SolutionList` from Optimized `mip.Model`
75
- ommx_solutions_bytes = adapter.model_to_solution(
76
- model, ommx_instance_bytes
77
- )
62
+ # Create `ommx.v1.State` from Optimized `mip.Model`
63
+ ommx_solutions = adapter.model_to_solution(model, ommx_instance)
78
64
 
79
- print(SolutionList.FromString(ommx_solutions_bytes))
65
+ print(ommx_solutions)
80
66
  ```
67
+
81
68
  You can get `ommx.v1.Instance` from a Python-MIP model as the following:
69
+
82
70
  ```python markdown-code-runner
83
71
  import mip
84
72
  import ommx_python_mip_adapter as adapter
85
- from ommx.v1.instance_pb2 import Instance
86
73
 
87
74
  model = mip.Model()
88
75
  x1=model.add_var(name="1", var_type=mip.INTEGER, lb=0, ub=5)
@@ -90,9 +77,9 @@ x2=model.add_var(name="2", var_type=mip.CONTINUOUS, lb=0, ub=5)
90
77
  model.objective = - x1 - 2 * x2
91
78
  model.add_constr(x1 + x2 - 6 <= 0)
92
79
 
93
- ommx_instance_bytes = adapter.model_to_instance(model)
80
+ ommx_instance = adapter.model_to_instance(model)
94
81
 
95
- print(Instance.FromString(ommx_instance_bytes))
82
+ print(ommx_instance)
96
83
  ```
97
84
 
98
85
  Reference
@@ -8,4 +8,4 @@ __all__ = [
8
8
  "instance_to_model",
9
9
  "model_to_instance",
10
10
  "model_to_solution",
11
- ]
11
+ ]
@@ -3,12 +3,11 @@ import typing as tp
3
3
  import mip
4
4
 
5
5
  from mip.exceptions import ParameterNotAvailable
6
- from ommx.v1.constraint_pb2 import Constraint
7
- from ommx.v1.decision_variables_pb2 import DecisionVariable, Bound
6
+ from ommx.v1.constraint_pb2 import Constraint, Equality, ConstraintDescription
8
7
  from ommx.v1.function_pb2 import Function
9
- from ommx.v1.instance_pb2 import Instance
10
8
  from ommx.v1.linear_pb2 import Linear
11
- from ommx.v1.solution_pb2 import Solution, SolutionList
9
+ from ommx.v1.solution_pb2 import State
10
+ from ommx.v1 import Instance, DecisionVariable
12
11
 
13
12
  from ommx_python_mip_adapter.exception import OMMXPythonMIPAdapterError
14
13
 
@@ -16,71 +15,65 @@ from ommx_python_mip_adapter.exception import OMMXPythonMIPAdapterError
16
15
  class PythonMIPBuilder:
17
16
  def __init__(
18
17
  self,
19
- ommx_instance_bytes: bytes,
18
+ instance: Instance,
20
19
  *,
21
20
  sense: str = mip.MINIMIZE,
22
21
  solver_name: str = mip.CBC,
23
22
  solver: tp.Optional[mip.Solver] = None,
24
23
  ):
25
- try:
26
- self._ommx_instance = Instance.FromString(ommx_instance_bytes)
27
- except Exception as e:
28
- raise OMMXPythonMIPAdapterError(
29
- "Invalid `ommx_instance_bytes` as ommx.v1.Instance."
30
- ) from e
31
-
24
+ self._ommx_instance = instance.raw
32
25
  self._model = mip.Model(
33
26
  sense=sense,
34
27
  solver_name=solver_name,
35
28
  solver=solver,
36
29
  )
37
30
 
38
-
39
31
  def _set_decision_variables(self):
40
32
  for var in self._ommx_instance.decision_variables:
41
- if var.kind == DecisionVariable.KIND_BINARY:
33
+ if var.kind == DecisionVariable.BINARY:
42
34
  self._model.add_var(
43
35
  name=str(var.id),
44
36
  var_type=mip.BINARY,
45
37
  )
46
- elif var.kind == DecisionVariable.KIND_INTEGER:
38
+ elif var.kind == DecisionVariable.INTEGER:
47
39
  self._model.add_var(
48
40
  name=str(var.id),
49
41
  var_type=mip.INTEGER,
50
- lb=var.bound.lower, # type: ignore
51
- ub=var.bound.upper, # type: ignore
42
+ lb=var.bound.lower, # type: ignore
43
+ ub=var.bound.upper, # type: ignore
52
44
  )
53
- elif var.kind == DecisionVariable.KIND_CONTINUOUS:
45
+ elif var.kind == DecisionVariable.CONTINUOUS:
54
46
  self._model.add_var(
55
47
  name=str(var.id),
56
48
  var_type=mip.CONTINUOUS,
57
- lb=var.bound.lower, # type: ignore
58
- ub=var.bound.upper, # type: ignore
49
+ lb=var.bound.lower, # type: ignore
50
+ ub=var.bound.upper, # type: ignore
59
51
  )
60
52
  else:
61
53
  raise OMMXPythonMIPAdapterError(
62
54
  f"Not supported decision variable kind: "
63
55
  f"id: {var.id}, kind: {var.kind}"
64
56
  )
65
-
66
-
57
+
67
58
  def _make_linear_expr(
68
59
  self,
69
60
  ommx_function: Function,
70
- ) -> mip.LinExpr:
61
+ ) -> mip.LinExpr:
71
62
  ommx_linear = ommx_function.linear
72
63
 
73
- return mip.xsum(
74
- term.coefficient * self._model.vars[str(term.id)] # type: ignore
75
- for term in ommx_linear.terms
76
- ) + ommx_linear.constant # type: ignore
64
+ return (
65
+ mip.xsum(
66
+ term.coefficient * self._model.vars[str(term.id)] # type: ignore
67
+ for term in ommx_linear.terms
68
+ )
69
+ + ommx_linear.constant
70
+ ) # type: ignore
77
71
 
78
-
79
72
  def _set_objective_function(self):
80
73
  ommx_objective = self._ommx_instance.objective
81
74
 
82
75
  if ommx_objective.HasField("constant"):
83
- self._model.objective = ommx_objective.constant # type: ignore
76
+ self._model.objective = ommx_objective.constant # type: ignore
84
77
  elif ommx_objective.HasField("linear"):
85
78
  self._model.objective = self._make_linear_expr(ommx_objective)
86
79
  else:
@@ -88,7 +81,6 @@ class PythonMIPBuilder:
88
81
  "The objective function must be either `constant` or `linear`."
89
82
  )
90
83
 
91
-
92
84
  def _set_constraints(self):
93
85
  ommx_constraints = self._ommx_instance.constraints
94
86
 
@@ -102,18 +94,17 @@ class PythonMIPBuilder:
102
94
 
103
95
  lin_expr = self._make_linear_expr(constraint.function)
104
96
 
105
- if constraint.equality == Constraint.EQUALITY_EQUAL_TO_ZERO:
106
- constr_expr = (lin_expr == 0)
107
- elif (constraint.equality == Constraint.EQUALITY_LESS_THAN_OR_EQUAL_TO_ZERO):
108
- constr_expr = (lin_expr <= 0) # type: ignore
97
+ if constraint.equality == Equality.EQUALITY_EQUAL_TO_ZERO:
98
+ constr_expr = lin_expr == 0
99
+ elif constraint.equality == Equality.EQUALITY_LESS_THAN_OR_EQUAL_TO_ZERO:
100
+ constr_expr = lin_expr <= 0 # type: ignore
109
101
  else:
110
102
  raise OMMXPythonMIPAdapterError(
111
103
  f"Not supported constraint equality: "
112
104
  f"id: {constraint.id}, equality: {constraint.equality}"
113
105
  )
114
-
115
- self._model.add_constr(constr_expr, name=str(constraint.id))
116
106
 
107
+ self._model.add_constr(constr_expr, name=str(constraint.id))
117
108
 
118
109
  def build(self) -> mip.Model:
119
110
  self._set_decision_variables()
@@ -135,11 +126,11 @@ class OMMXInstanceBuilder:
135
126
 
136
127
  for var in self._model.vars:
137
128
  if var.var_type == mip.BINARY:
138
- kind = DecisionVariable.KIND_BINARY
129
+ kind = DecisionVariable.BINARY
139
130
  elif var.var_type == mip.INTEGER:
140
- kind = DecisionVariable.KIND_INTEGER
131
+ kind = DecisionVariable.INTEGER
141
132
  elif var.var_type == mip.CONTINUOUS:
142
- kind = DecisionVariable.KIND_CONTINUOUS
133
+ kind = DecisionVariable.CONTINUOUS
143
134
  else:
144
135
  raise OMMXPythonMIPAdapterError(
145
136
  f"Not supported variable type. "
@@ -147,35 +138,32 @@ class OMMXInstanceBuilder:
147
138
  )
148
139
 
149
140
  decision_variables.append(
150
- DecisionVariable(
151
- id=var.idx,
152
- kind=kind,
153
- bound=Bound(lower=var.lb, upper=var.ub),
154
- description=DecisionVariable.Description(name=var.name)
141
+ DecisionVariable.of_type(
142
+ kind,
143
+ var.idx,
144
+ lower=var.lb,
145
+ upper=var.ub,
146
+ description=DecisionVariable.Description(name=var.name),
155
147
  )
156
148
  )
157
149
 
158
150
  return decision_variables
159
-
160
151
 
161
152
  def _make_function_from_lin_expr(
162
153
  self,
163
154
  lin_expr: mip.LinExpr,
164
155
  ) -> Function:
165
156
  terms = [
166
- Linear.Term(id=var.idx, coefficient=coeff) # type: ignore
157
+ Linear.Term(id=var.idx, coefficient=coeff) # type: ignore
167
158
  for var, coeff in lin_expr.expr.items()
168
159
  ]
169
- constant: float = lin_expr.const # type: ignore
160
+ constant: float = lin_expr.const # type: ignore
170
161
 
171
162
  # If the terms are empty, the function is a constant.
172
163
  if len(terms) == 0:
173
164
  return Function(constant=constant)
174
165
  else:
175
- return Function(
176
- linear=Linear(terms=terms, constant=constant)
177
- )
178
-
166
+ return Function(linear=Linear(terms=terms, constant=constant))
179
167
 
180
168
  def _objective(self) -> Function:
181
169
  # In Python-MIP, it is allowed not to set the objective function.
@@ -186,9 +174,8 @@ class OMMXInstanceBuilder:
186
174
  objective = self._model.objective
187
175
  except ParameterNotAvailable:
188
176
  return Function(constant=0)
189
-
190
- return self._make_function_from_lin_expr(objective)
191
177
 
178
+ return self._make_function_from_lin_expr(objective)
192
179
 
193
180
  def _constraints(self) -> tp.List[Constraint]:
194
181
  constraints = []
@@ -201,55 +188,53 @@ class OMMXInstanceBuilder:
201
188
  if lin_expr.sense == "=":
202
189
  constraint = Constraint(
203
190
  id=id,
204
- equality=Constraint.EQUALITY_EQUAL_TO_ZERO,
191
+ equality=Equality.EQUALITY_EQUAL_TO_ZERO,
205
192
  function=self._make_function_from_lin_expr(lin_expr),
206
- description=Constraint.Description(name=name),
193
+ description=ConstraintDescription(name=name),
207
194
  )
208
195
  elif lin_expr.sense == "<":
209
196
  constraint = Constraint(
210
197
  id=id,
211
- equality=Constraint.EQUALITY_LESS_THAN_OR_EQUAL_TO_ZERO,
198
+ equality=Equality.EQUALITY_LESS_THAN_OR_EQUAL_TO_ZERO,
212
199
  function=self._make_function_from_lin_expr(lin_expr),
213
- description=Constraint.Description(name=name),
200
+ description=ConstraintDescription(name=name),
214
201
  )
215
202
  elif lin_expr.sense == ">":
216
203
  # `ommx.v1.Constraint` does not support `GREATER_THAN_OR_EQUAL_TO_ZERO`.
217
204
  # So multiply the linear expression by -1.
218
205
  constraint = Constraint(
219
206
  id=id,
220
- equality=Constraint.EQUALITY_LESS_THAN_OR_EQUAL_TO_ZERO,
207
+ equality=Equality.EQUALITY_LESS_THAN_OR_EQUAL_TO_ZERO,
221
208
  function=self._make_function_from_lin_expr(-lin_expr),
222
- description=Constraint.Description(name=name),
209
+ description=ConstraintDescription(name=name),
223
210
  )
224
211
  else:
225
212
  raise OMMXPythonMIPAdapterError(
226
213
  f"Not supported constraint sense: "
227
214
  f"name: {constr.name}, sense: {lin_expr.sense}"
228
215
  )
229
-
216
+
230
217
  constraints.append(constraint)
231
218
 
232
219
  return constraints
233
220
 
234
-
235
221
  def _sense(self):
236
222
  if self._model.sense == mip.MAXIMIZE:
237
- return Instance.SENSE_MAXIMIZE
223
+ return Instance.MAXIMIZE
238
224
  else:
239
- return Instance.SENSE_MINIMIZE
225
+ return Instance.MINIMIZE
240
226
 
241
-
242
- def build(self) -> bytes:
243
- return Instance(
227
+ def build(self) -> Instance:
228
+ return Instance.from_components(
244
229
  decision_variables=self._decision_variables(),
245
230
  objective=self._objective(),
246
231
  constraints=self._constraints(),
247
232
  sense=self._sense(),
248
- ).SerializeToString()
233
+ )
249
234
 
250
235
 
251
236
  def instance_to_model(
252
- ommx_instance_bytes: bytes,
237
+ instance: Instance,
253
238
  *,
254
239
  sense: str = mip.MINIMIZE,
255
240
  solver_name: str = mip.CBC,
@@ -260,7 +245,7 @@ def instance_to_model(
260
245
 
261
246
  Args:
262
247
  ommx_instance_bytes (bytes): Serialized ommx.v1.Instance.
263
- sense (str): mip.MINIMIZE or mip.MAXIMIZE.
248
+ sense (str): mip.MINIMIZE or mip.MAXIMIZE.
264
249
  solver_name (str): mip.CBC or mip.GUROBI. Searches for which solver is available if not informed.
265
250
  solver (mip.Solver): if this argument is provided, solver_name will be ignored.
266
251
 
@@ -274,37 +259,25 @@ def instance_to_model(
274
259
  The following example of solving an unconstrained linear optimization problem with x1 as the objective function.
275
260
 
276
261
  >>> import ommx_python_mip_adapter as adapter
277
- >>> from ommx.v1.decision_variables_pb2 import DecisionVariable, Bound
278
- >>> from ommx.v1.instance_pb2 import Instance
279
- >>> from ommx.v1.function_pb2 import Function
280
- >>> from ommx.v1.linear_pb2 import Linear
281
- >>> from ommx.v1.solution_pb2 import SolutionList
282
- >>> ommx_instance = Instance(
283
- ... decision_variables=[
284
- ... DecisionVariable(
285
- ... id=1,
286
- ... kind=DecisionVariable.KIND_INTEGER,
287
- ... bound=Bound(lower=0, upper=5),
288
- ... ),
289
- ... ],
290
- ... objective=Function(
291
- ... linear=Linear(
292
- ... terms=[Linear.Term(id=1, coefficient=1)]
293
- ... ),
294
- ... ),
262
+ >>> from ommx.v1 import Instance, DecisionVariable
263
+
264
+ >>> x1 = DecisionVariable.integer(1, lower=0, upper=5)
265
+ >>> ommx_instance = Instance.from_components(
266
+ ... decision_variables=[x1],
267
+ ... objective=x1,
268
+ ... constraints=[],
269
+ ... sense=Instance.MINIMIZE,
295
270
  ... )
296
- >>> ommx_instance_bytes = ommx_instance.SerializeToString()
297
- >>> model = adapter.instance_to_model(ommx_instance_bytes)
271
+ >>> model = adapter.instance_to_model(ommx_instance)
298
272
  >>> model.optimize()
299
273
  <OptimizationStatus.OPTIMAL: 0>
300
- >>> ommx_solutions_bytes = adapter.model_to_solution(
301
- ... model, ommx_instance_bytes
302
- ... )
303
- >>> SolutionList.FromString(ommx_solutions_bytes).solutions[0].entries
274
+
275
+ >>> ommx_solutions = adapter.model_to_solution(model, ommx_instance)
276
+ >>> ommx_solutions.entries
304
277
  {1: 0.0}
305
278
  """
306
279
  builder = PythonMIPBuilder(
307
- ommx_instance_bytes,
280
+ instance,
308
281
  sense=sense,
309
282
  solver_name=solver_name,
310
283
  solver=solver,
@@ -312,13 +285,13 @@ def instance_to_model(
312
285
  return builder.build()
313
286
 
314
287
 
315
- def model_to_instance(model: mip.Model) -> bytes:
288
+ def model_to_instance(model: mip.Model) -> Instance:
316
289
  """
317
290
  The function to convert Python-MIP Model to ommx.v1.Instance.
318
291
 
319
292
  Args:
320
293
  model (mip.Model): Python-MIP Model.
321
-
294
+
322
295
  Returns:
323
296
  bytes: Serialized ommx.v1.Instance.
324
297
 
@@ -328,14 +301,12 @@ def model_to_instance(model: mip.Model) -> bytes:
328
301
  Examples:
329
302
  >>> import mip
330
303
  >>> import ommx_python_mip_adapter as adapter
331
- >>> from ommx.v1.instance_pb2 import Instance
332
304
  >>> model = mip.Model()
333
305
  >>> x1=model.add_var(name="1", var_type=mip.INTEGER, lb=0, ub=5)
334
306
  >>> x2=model.add_var(name="2", var_type=mip.CONTINUOUS, lb=0, ub=5)
335
307
  >>> model.objective = - x1 - 2 * x2
336
308
  >>> constr = model.add_constr(x1 + x2 - 6 <= 0)
337
- >>> ommx_instance_bytes = adapter.model_to_instance(model)
338
- >>> ommx_instance = Instance.FromString(ommx_instance_bytes)
309
+ >>> ommx_instance = adapter.model_to_instance(model)
339
310
  """
340
311
  builder = OMMXInstanceBuilder(model)
341
312
  return builder.build()
@@ -343,8 +314,8 @@ def model_to_instance(model: mip.Model) -> bytes:
343
314
 
344
315
  def model_to_solution(
345
316
  model: mip.Model,
346
- ommx_instance_bytes: bytes,
347
- ) -> bytes:
317
+ instance: Instance,
318
+ ) -> State:
348
319
  """
349
320
  The function to create ommx.v1.SolutionList from optimized Python-MIP Model.
350
321
 
@@ -362,33 +333,21 @@ def model_to_solution(
362
333
  The following example of solving an unconstrained linear optimization problem with x1 as the objective function.
363
334
 
364
335
  >>> import ommx_python_mip_adapter as adapter
365
- >>> from ommx.v1.decision_variables_pb2 import DecisionVariable, Bound
366
- >>> from ommx.v1.instance_pb2 import Instance
367
- >>> from ommx.v1.function_pb2 import Function
368
- >>> from ommx.v1.linear_pb2 import Linear
369
- >>> from ommx.v1.solution_pb2 import SolutionList
370
- >>> ommx_instance = Instance(
371
- ... decision_variables=[
372
- ... DecisionVariable(
373
- ... id=1,
374
- ... kind=DecisionVariable.KIND_INTEGER,
375
- ... bound=Bound(lower=0, upper=5),
376
- ... ),
377
- ... ],
378
- ... objective=Function(
379
- ... linear=Linear(
380
- ... terms=[Linear.Term(id=1, coefficient=1)]
381
- ... ),
382
- ... ),
336
+ >>> from ommx.v1 import Instance, DecisionVariable
337
+
338
+ >>> x1 = DecisionVariable.integer(1, lower=0, upper=5)
339
+ >>> ommx_instance = Instance.from_components(
340
+ ... decision_variables=[x1],
341
+ ... objective=x1,
342
+ ... constraints=[],
343
+ ... sense=Instance.MINIMIZE,
383
344
  ... )
384
- >>> ommx_instance_bytes = ommx_instance.SerializeToString()
385
- >>> model = adapter.instance_to_model(ommx_instance_bytes)
345
+ >>> model = adapter.instance_to_model(ommx_instance)
386
346
  >>> model.optimize()
387
347
  <OptimizationStatus.OPTIMAL: 0>
388
- >>> ommx_solutions_bytes = adapter.model_to_solution(
389
- ... model, ommx_instance_bytes
390
- ... )
391
- >>> SolutionList.FromString(ommx_solutions_bytes).solutions[0].entries
348
+
349
+ >>> ommx_solutions = adapter.model_to_solution(model, ommx_instance)
350
+ >>> ommx_solutions.entries
392
351
  {1: 0.0}
393
352
  """
394
353
  if not (
@@ -399,20 +358,9 @@ def model_to_solution(
399
358
  "`model.status` must be `OPTIMAL` or `FEASIBLE`."
400
359
  )
401
360
 
402
- try:
403
- ommx_instance = Instance.FromString(ommx_instance_bytes)
404
- except Exception as e:
405
- raise OMMXPythonMIPAdapterError(
406
- "Invalid `ommx_instance_bytes` as ommx.v1.Instance."
407
- ) from e
408
-
409
- return SolutionList(
410
- solutions=[
411
- Solution(
412
- entries={
413
- var.id: model.var_by_name(str(var.id)).x # type: ignore
414
- for var in ommx_instance.decision_variables
415
- }
416
- )
417
- ]
418
- ).SerializeToString()
361
+ return State(
362
+ entries={
363
+ var.id: model.var_by_name(str(var.id)).x # type: ignore
364
+ for var in instance.raw.decision_variables
365
+ }
366
+ )