ommx-python-mip-adapter 0.0.2__tar.gz → 0.1.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 (32) hide show
  1. ommx_python_mip_adapter-0.1.0/.github/workflows/docs.yml +72 -0
  2. {ommx_python_mip_adapter-0.0.2 → ommx_python_mip_adapter-0.1.0}/.github/workflows/test_and_lint.yml +23 -2
  3. ommx_python_mip_adapter-0.1.0/PKG-INFO +104 -0
  4. ommx_python_mip_adapter-0.1.0/README.md +72 -0
  5. ommx_python_mip_adapter-0.1.0/docs/source/conf.py +50 -0
  6. ommx_python_mip_adapter-0.1.0/docs/source/index.rst +20 -0
  7. ommx_python_mip_adapter-0.1.0/ommx_python_mip_adapter/__init__.py +9 -0
  8. {ommx_python_mip_adapter-0.0.2 → ommx_python_mip_adapter-0.1.0}/ommx_python_mip_adapter/_version.py +2 -2
  9. ommx_python_mip_adapter-0.1.0/ommx_python_mip_adapter/adapter.py +262 -0
  10. ommx_python_mip_adapter-0.1.0/ommx_python_mip_adapter/exception.py +2 -0
  11. ommx_python_mip_adapter-0.1.0/ommx_python_mip_adapter.egg-info/PKG-INFO +104 -0
  12. {ommx_python_mip_adapter-0.0.2 → ommx_python_mip_adapter-0.1.0}/ommx_python_mip_adapter.egg-info/SOURCES.txt +8 -2
  13. ommx_python_mip_adapter-0.1.0/ommx_python_mip_adapter.egg-info/requires.txt +13 -0
  14. {ommx_python_mip_adapter-0.0.2 → ommx_python_mip_adapter-0.1.0}/pyproject.toml +9 -2
  15. ommx_python_mip_adapter-0.1.0/tests/test_adapter.py +147 -0
  16. ommx_python_mip_adapter-0.1.0/tests/test_import.py +9 -0
  17. ommx_python_mip_adapter-0.1.0/tests/test_integration.py +142 -0
  18. ommx_python_mip_adapter-0.0.2/PKG-INFO +0 -47
  19. ommx_python_mip_adapter-0.0.2/README.md +0 -22
  20. ommx_python_mip_adapter-0.0.2/ommx_python_mip_adapter/__init__.py +0 -0
  21. ommx_python_mip_adapter-0.0.2/ommx_python_mip_adapter/ommx_to_python_mip.py +0 -2
  22. ommx_python_mip_adapter-0.0.2/ommx_python_mip_adapter.egg-info/PKG-INFO +0 -47
  23. ommx_python_mip_adapter-0.0.2/ommx_python_mip_adapter.egg-info/requires.txt +0 -6
  24. ommx_python_mip_adapter-0.0.2/tests/test_omm_to_python_mip.py +0 -2
  25. {ommx_python_mip_adapter-0.0.2 → ommx_python_mip_adapter-0.1.0}/.github/workflows/publish.yml +0 -0
  26. {ommx_python_mip_adapter-0.0.2 → ommx_python_mip_adapter-0.1.0}/.gitignore +0 -0
  27. {ommx_python_mip_adapter-0.0.2 → ommx_python_mip_adapter-0.1.0}/LICENSE-APACHE +0 -0
  28. {ommx_python_mip_adapter-0.0.2 → ommx_python_mip_adapter-0.1.0}/LICENSE-MIT +0 -0
  29. {ommx_python_mip_adapter-0.0.2 → ommx_python_mip_adapter-0.1.0}/ommx_python_mip_adapter.egg-info/dependency_links.txt +0 -0
  30. {ommx_python_mip_adapter-0.0.2 → ommx_python_mip_adapter-0.1.0}/ommx_python_mip_adapter.egg-info/top_level.txt +0 -0
  31. {ommx_python_mip_adapter-0.0.2 → ommx_python_mip_adapter-0.1.0}/setup.cfg +0 -0
  32. {ommx_python_mip_adapter-0.0.2 → ommx_python_mip_adapter-0.1.0}/tests/conftest.py +0 -0
@@ -0,0 +1,72 @@
1
+ name: Documents
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ workflow_dispatch:
9
+
10
+ # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
11
+ permissions:
12
+ contents: read
13
+ pages: write
14
+ id-token: write
15
+
16
+ # Allow one concurrent deployment
17
+ concurrency:
18
+ group: "pages"
19
+ cancel-in-progress: true
20
+
21
+ jobs:
22
+ build:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - name: Checkout
26
+ uses: actions/checkout@v4
27
+
28
+ - name: Setup Python
29
+ uses: actions/setup-python@v5
30
+ with:
31
+ python-version: "3.8"
32
+
33
+ - name: Install dependencies
34
+ run: |
35
+ python -m pip install ".[dev]"
36
+
37
+ - name: Build Python documentation
38
+ run: |
39
+ sphinx-build -b html ./docs/source ./docs/build
40
+
41
+ - name: Upload HTML
42
+ uses: actions/upload-artifact@v4
43
+ with:
44
+ name: docs
45
+ path: ./docs/build
46
+ retention-days: 30
47
+
48
+ deploy:
49
+ if: github.ref == 'refs/heads/main'
50
+ needs: build
51
+ environment:
52
+ name: github-pages
53
+ url: ${{ steps.deployment.outputs.page_url }}
54
+ runs-on: ubuntu-latest
55
+ steps:
56
+ - name: Download HTML
57
+ uses: actions/download-artifact@v4
58
+ with:
59
+ name: docs
60
+ path: .
61
+
62
+ - name: Configure GitHub Pages
63
+ uses: actions/configure-pages@v4
64
+
65
+ - name: Upload artifact
66
+ uses: actions/upload-pages-artifact@v3
67
+ with:
68
+ path: "."
69
+
70
+ - name: Deploy to GitHub Pages
71
+ id: deployment
72
+ uses: actions/deploy-pages@v4
@@ -28,7 +28,7 @@ jobs:
28
28
 
29
29
  - name: Run Tests
30
30
  run: |
31
- python -m pytest
31
+ python -m pytest --doctest-modules -vv
32
32
 
33
33
  lint:
34
34
  runs-on: ubuntu-latest
@@ -50,5 +50,26 @@ jobs:
50
50
 
51
51
  - name: Lint
52
52
  run: |
53
- python -m mypy ./ommx_python_mip_adapter
54
53
  python -m pyright ./ommx_python_mip_adapter
54
+
55
+ markdown-code-runner:
56
+ runs-on: ubuntu-latest
57
+ strategy:
58
+ fail-fast: false
59
+ matrix:
60
+ python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
61
+ steps:
62
+ - uses: actions/checkout@v4
63
+
64
+ - name: Setup Python ${{ matrix.python-version }}
65
+ uses: actions/setup-python@v5
66
+ with:
67
+ python-version: ${{ matrix.python-version }}
68
+
69
+ - name: Install Dependencies
70
+ run: |
71
+ python -m pip install ".[dev]"
72
+
73
+ - name: Lint
74
+ run: |
75
+ markdown-code-runner --verbose README.md
@@ -0,0 +1,104 @@
1
+ Metadata-Version: 2.1
2
+ Name: ommx_python_mip_adapter
3
+ Version: 0.1.0
4
+ Summary: An adapter for the Python-MIP from/to OMMX.
5
+ Author-email: "Jij Inc." <info@j-ij.com>
6
+ Project-URL: Repository, https://github.com/Jij-Inc/ommx-python-mip-adapter
7
+ Project-URL: Issues, https://github.com/Jij-Inc/ommx-python-mip-adapter/issues
8
+ Classifier: Programming Language :: Python :: 3 :: Only
9
+ Classifier: Programming Language :: Python :: 3.8
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE-APACHE
19
+ License-File: LICENSE-MIT
20
+ Requires-Dist: ommx<0.2.0,>=0.1.1
21
+ Requires-Dist: mip
22
+ Provides-Extra: dev
23
+ Requires-Dist: markdown-code-runner; extra == "dev"
24
+ Requires-Dist: mypy; extra == "dev"
25
+ Requires-Dist: numpy; extra == "dev"
26
+ Requires-Dist: pyright; extra == "dev"
27
+ Requires-Dist: pytest; extra == "dev"
28
+ Requires-Dist: sphinx; extra == "dev"
29
+ Requires-Dist: sphinx_rtd_theme; extra == "dev"
30
+ Requires-Dist: sphinx_fontawesome; extra == "dev"
31
+ Requires-Dist: sphinx-autoapi; extra == "dev"
32
+
33
+ OMMX adaptor for Python-MIP
34
+ ============================
35
+ ![PyPI - Version](https://img.shields.io/pypi/v/ommx-python-mip-adapter)
36
+
37
+ This package provides an adaptor for the [Python-MIP](https://www.python-mip.com/) from/to [OMMX](https://github.com/Jij-Inc/ommx)
38
+
39
+ Python-MIP as a solver in OMMX toolchain
40
+ -----------------------------------------
41
+ ```mermaid
42
+ sequenceDiagram
43
+ participant O as Other OMMX toolchain
44
+ participant A as Adapter
45
+ participant P as Python-MIP
46
+ O->>A: ommx::Instance and Parameters for Python-MIP;
47
+ A->>P: Translate into Python-MIP input
48
+ P->>P: Solve with CBC, Gurobi, or other solvers
49
+ P->>A: Solution
50
+ A->>O: ommx:Solution
51
+ ```
52
+
53
+ Python-MIP as a user interface to create OMMX instance
54
+ -------------------------------------------------------
55
+ TBW
56
+
57
+ Usage
58
+ ======
59
+ `ommx-python-mip-adapter` can be installed from PyPI as follows:
60
+
61
+ ```bash
62
+ pip install ommx-python-mip-adapter
63
+ ```
64
+
65
+ Python-MIP can be used through `ommx-python-mip-adapter` by using the following:
66
+
67
+ ```python markdown-code-runner
68
+ import ommx_python_mip_adapter as adapter
69
+ from ommx.v1.decision_variables_pb2 import DecisionVariable, Bound
70
+ from ommx.v1.instance_pb2 import Instance
71
+ from ommx.v1.function_pb2 import Function
72
+ from ommx.v1.linear_pb2 import Linear
73
+ from ommx.v1.solution_pb2 import SolutionList
74
+
75
+ ommx_instance = Instance(
76
+ decision_variables=[
77
+ DecisionVariable(
78
+ id=1,
79
+ kind=DecisionVariable.KIND_INTEGER,
80
+ bound=Bound(lower=0, upper=5),
81
+ ),
82
+ ],
83
+ objective=Function(
84
+ linear=Linear(
85
+ terms=[Linear.Term(id=1, coefficient=1)]
86
+ ),
87
+ ),
88
+ )
89
+ ommx_instance_bytes = ommx_instance.SerializeToString()
90
+
91
+ # Convert from `ommx.v1.Instance` to `mip.Model`
92
+ model = adapter.instance_to_model(ommx_instance_bytes)
93
+ model.optimize()
94
+ # Create `ommx.v1.SolutionList` from Optimized `mip.Model`
95
+ ommx_solutions_bytes = adapter.model_to_solution(
96
+ model, ommx_instance_bytes
97
+ )
98
+
99
+ print(SolutionList.FromString(ommx_solutions_bytes))
100
+ ```
101
+
102
+ Reference
103
+ ==============
104
+ - [OMMX-Python-MIP-Adapter API Reference](https://jij-inc.github.io/ommx-python-mip-adapter/index.html)
@@ -0,0 +1,72 @@
1
+ OMMX adaptor for Python-MIP
2
+ ============================
3
+ ![PyPI - Version](https://img.shields.io/pypi/v/ommx-python-mip-adapter)
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)
6
+
7
+ Python-MIP as a solver in OMMX toolchain
8
+ -----------------------------------------
9
+ ```mermaid
10
+ sequenceDiagram
11
+ participant O as Other OMMX toolchain
12
+ participant A as Adapter
13
+ participant P as Python-MIP
14
+ O->>A: ommx::Instance and Parameters for Python-MIP;
15
+ A->>P: Translate into Python-MIP input
16
+ P->>P: Solve with CBC, Gurobi, or other solvers
17
+ P->>A: Solution
18
+ A->>O: ommx:Solution
19
+ ```
20
+
21
+ Python-MIP as a user interface to create OMMX instance
22
+ -------------------------------------------------------
23
+ TBW
24
+
25
+ Usage
26
+ ======
27
+ `ommx-python-mip-adapter` can be installed from PyPI as follows:
28
+
29
+ ```bash
30
+ pip install ommx-python-mip-adapter
31
+ ```
32
+
33
+ Python-MIP can be used through `ommx-python-mip-adapter` by using the following:
34
+
35
+ ```python markdown-code-runner
36
+ import ommx_python_mip_adapter as adapter
37
+ from ommx.v1.decision_variables_pb2 import DecisionVariable, Bound
38
+ from ommx.v1.instance_pb2 import Instance
39
+ from ommx.v1.function_pb2 import Function
40
+ from ommx.v1.linear_pb2 import Linear
41
+ from ommx.v1.solution_pb2 import SolutionList
42
+
43
+ ommx_instance = Instance(
44
+ decision_variables=[
45
+ DecisionVariable(
46
+ id=1,
47
+ kind=DecisionVariable.KIND_INTEGER,
48
+ bound=Bound(lower=0, upper=5),
49
+ ),
50
+ ],
51
+ objective=Function(
52
+ linear=Linear(
53
+ terms=[Linear.Term(id=1, coefficient=1)]
54
+ ),
55
+ ),
56
+ )
57
+ ommx_instance_bytes = ommx_instance.SerializeToString()
58
+
59
+ # Convert from `ommx.v1.Instance` to `mip.Model`
60
+ model = adapter.instance_to_model(ommx_instance_bytes)
61
+ model.optimize()
62
+ # Create `ommx.v1.SolutionList` from Optimized `mip.Model`
63
+ ommx_solutions_bytes = adapter.model_to_solution(
64
+ model, ommx_instance_bytes
65
+ )
66
+
67
+ print(SolutionList.FromString(ommx_solutions_bytes))
68
+ ```
69
+
70
+ Reference
71
+ ==============
72
+ - [OMMX-Python-MIP-Adapter API Reference](https://jij-inc.github.io/ommx-python-mip-adapter/index.html)
@@ -0,0 +1,50 @@
1
+ # Configuration file for the Sphinx documentation builder.
2
+ #
3
+ # For the full list of built-in configuration values, see the documentation:
4
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html
5
+
6
+ import sphinx_rtd_theme
7
+ import sphinx_fontawesome
8
+
9
+ # -- Project information -----------------------------------------------------
10
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
11
+
12
+ project = 'ommx-python-mip-adapter'
13
+ copyright = '2024, Jij Inc.'
14
+ author = 'Jij Inc.'
15
+
16
+ version = '0.1.0'
17
+ release = '0.1.0'
18
+
19
+ # -- General configuration ---------------------------------------------------
20
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
21
+
22
+ extensions = [
23
+ 'sphinx.ext.autodoc',
24
+ 'sphinx.ext.napoleon',
25
+ 'sphinx_rtd_theme',
26
+ 'sphinx_fontawesome',
27
+ 'autoapi.extension',
28
+ ]
29
+ source_suffix = {
30
+ '.rst': 'restructuredtext',
31
+ '.md': 'markdown',
32
+ }
33
+
34
+ templates_path = ['_templates']
35
+ language = 'en'
36
+ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
37
+
38
+ # -- Options for HTML output -------------------------------------------------
39
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
40
+
41
+ html_theme = "sphinx_rtd_theme"
42
+ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
43
+ html_show_sourcelink = False
44
+ html_static_path = ['_static']
45
+
46
+ # -- AutoAPI settings --------------------------------------------------------
47
+ # https://sphinx-autoapi.readthedocs.io/en/latest/reference/config.html#event-autoapi-skip-member
48
+
49
+ autoapi_dirs = ['../../ommx_python_mip_adapter']
50
+ autoapi_member_order = 'groupwise'
@@ -0,0 +1,20 @@
1
+ .. ommx-python-mip-adapter documentation master file, created by
2
+ sphinx-quickstart on Mon Apr 22 14:29:19 2024.
3
+ You can adapt this file completely to your liking, but it should at least
4
+ contain the root `toctree` directive.
5
+
6
+ Welcome to ommx-python-mip-adapter's documentation!
7
+ ===================================================
8
+
9
+ .. toctree::
10
+ :maxdepth: 2
11
+ :caption: Contents:
12
+
13
+
14
+
15
+ Indices and tables
16
+ ==================
17
+
18
+ * :ref:`genindex`
19
+ * :ref:`modindex`
20
+ * :ref:`search`
@@ -0,0 +1,9 @@
1
+ from ommx_python_mip_adapter.adapter import (
2
+ instance_to_model,
3
+ model_to_solution,
4
+ )
5
+
6
+ __all__ = [
7
+ "instance_to_model",
8
+ "model_to_solution",
9
+ ]
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.0.2'
16
- __version_tuple__ = version_tuple = (0, 0, 2)
15
+ __version__ = version = '0.1.0'
16
+ __version_tuple__ = version_tuple = (0, 1, 0)
@@ -0,0 +1,262 @@
1
+ import typing as tp
2
+
3
+ import mip
4
+
5
+ from ommx.v1.constraint_pb2 import Constraint
6
+ from ommx.v1.decision_variables_pb2 import DecisionVariable
7
+ from ommx.v1.function_pb2 import Function
8
+ from ommx.v1.instance_pb2 import Instance
9
+ from ommx.v1.solution_pb2 import Solution, SolutionList
10
+
11
+ from ommx_python_mip_adapter.exception import OMMXPythonMIPAdapterError
12
+
13
+
14
+ class PythonMIPBuilder:
15
+ def __init__(
16
+ self,
17
+ ommx_instance_bytes: bytes,
18
+ *,
19
+ sense: str = mip.MINIMIZE,
20
+ solver_name: str = mip.CBC,
21
+ solver: tp.Optional[mip.Solver] = None,
22
+ ):
23
+ try:
24
+ self._ommx_instance = Instance.FromString(ommx_instance_bytes)
25
+ except Exception as e:
26
+ raise OMMXPythonMIPAdapterError(
27
+ "Invalid `ommx_instance_bytes` as ommx.v1.Instance."
28
+ ) from e
29
+
30
+ self._model = mip.Model(
31
+ sense=sense,
32
+ solver_name=solver_name,
33
+ solver=solver,
34
+ )
35
+
36
+
37
+ def _set_decision_variables(self):
38
+ for var in self._ommx_instance.decision_variables:
39
+ if var.kind == DecisionVariable.KIND_BINARY:
40
+ self._model.add_var(
41
+ name=str(var.id),
42
+ var_type=mip.BINARY,
43
+ )
44
+ elif var.kind == DecisionVariable.KIND_INTEGER:
45
+ self._model.add_var(
46
+ name=str(var.id),
47
+ var_type=mip.INTEGER,
48
+ lb=var.bound.lower, # type: ignore
49
+ ub=var.bound.upper, # type: ignore
50
+ )
51
+ elif var.kind == DecisionVariable.KIND_CONTINUOUS:
52
+ self._model.add_var(
53
+ name=str(var.id),
54
+ var_type=mip.CONTINUOUS,
55
+ lb=var.bound.lower, # type: ignore
56
+ ub=var.bound.upper, # type: ignore
57
+ )
58
+ else:
59
+ raise OMMXPythonMIPAdapterError(
60
+ f"Not supported decision variable kind: "
61
+ f"id: {var.id}, kind: {var.kind}"
62
+ )
63
+
64
+
65
+ def _make_linear_expr(
66
+ self,
67
+ ommx_function: Function,
68
+ ) -> mip.LinExpr:
69
+ ommx_linear = ommx_function.linear
70
+
71
+ return mip.xsum(
72
+ term.coefficient * self._model.vars[str(term.id)] # type: ignore
73
+ for term in ommx_linear.terms
74
+ ) + ommx_linear.constant # type: ignore
75
+
76
+
77
+ def _set_objective_function(self):
78
+ ommx_objective = self._ommx_instance.objective
79
+
80
+ if ommx_objective.HasField("constant"):
81
+ self._model.objective = ommx_objective.constant # type: ignore
82
+ elif ommx_objective.HasField("linear"):
83
+ self._model.objective = self._make_linear_expr(ommx_objective)
84
+ else:
85
+ raise OMMXPythonMIPAdapterError(
86
+ "The objective function must be either `constant` or `linear`."
87
+ )
88
+
89
+
90
+ def _set_constraints(self):
91
+ ommx_constraints = self._ommx_instance.constraints
92
+
93
+ for constraint in ommx_constraints:
94
+ if not constraint.function.HasField("linear"):
95
+ raise OMMXPythonMIPAdapterError(
96
+ f"Only linear constraints are supported: "
97
+ f"id: {constraint.id}, "
98
+ f"type: {constraint.function.WhichOneof('function')}"
99
+ )
100
+
101
+ lin_expr = self._make_linear_expr(constraint.function)
102
+
103
+ if constraint.equality == Constraint.EQUALITY_EQUAL_TO_ZERO:
104
+ constr_expr = (lin_expr == 0)
105
+ elif (constraint.equality == Constraint.EQUALITY_LESS_THAN_OR_EQUAL_TO_ZERO):
106
+ constr_expr = (lin_expr <= 0) # type: ignore
107
+ else:
108
+ raise OMMXPythonMIPAdapterError(
109
+ f"Not supported constraint equality: "
110
+ f"id: {constraint.id}, equality: {constraint.equality}"
111
+ )
112
+
113
+ self._model.add_constr(constr_expr, name=str(constraint.id))
114
+
115
+
116
+ def build(self) -> mip.Model:
117
+ self._set_decision_variables()
118
+ self._set_objective_function()
119
+ self._set_constraints()
120
+
121
+ return self._model
122
+
123
+
124
+ def instance_to_model(
125
+ ommx_instance_bytes: bytes,
126
+ *,
127
+ sense: str = mip.MINIMIZE,
128
+ solver_name: str = mip.CBC,
129
+ solver: tp.Optional[mip.Solver] = None,
130
+ ) -> mip.Model:
131
+ """
132
+ The function to convert ommx.v1.Instance to Python-MIP Model.
133
+
134
+ Args:
135
+ ommx_instance_bytes (bytes): Serialized ommx.v1.Instance.
136
+ sense (str): mip.MINIMIZE or mip.MAXIMIZE.
137
+ solver_name (str): mip.CBC or mip.GUROBI. Searches for which solver is available if not informed.
138
+ solver (mip.Solver): if this argument is provided, solver_name will be ignored.
139
+
140
+ Returns:
141
+ mip.Model: Python-MIP Model converted from ommx.v1.Instance.
142
+
143
+ Raises:
144
+ OMMXPythonMIPAdapterError: If converting is not possible.
145
+
146
+ Examples:
147
+ The following example of solving an unconstrained linear optimization problem with x1 as the objective function.
148
+
149
+ >>> import ommx_python_mip_adapter as adapter
150
+ >>> from ommx.v1.decision_variables_pb2 import DecisionVariable, Bound
151
+ >>> from ommx.v1.instance_pb2 import Instance
152
+ >>> from ommx.v1.function_pb2 import Function
153
+ >>> from ommx.v1.linear_pb2 import Linear
154
+ >>> from ommx.v1.solution_pb2 import SolutionList
155
+ >>> ommx_instance = Instance(
156
+ ... decision_variables=[
157
+ ... DecisionVariable(
158
+ ... id=1,
159
+ ... kind=DecisionVariable.KIND_INTEGER,
160
+ ... bound=Bound(lower=0, upper=5),
161
+ ... ),
162
+ ... ],
163
+ ... objective=Function(
164
+ ... linear=Linear(
165
+ ... terms=[Linear.Term(id=1, coefficient=1)]
166
+ ... ),
167
+ ... ),
168
+ ... )
169
+ >>> ommx_instance_bytes = ommx_instance.SerializeToString()
170
+ >>> model = adapter.instance_to_model(ommx_instance_bytes)
171
+ >>> model.optimize()
172
+ <OptimizationStatus.OPTIMAL: 0>
173
+ >>> ommx_solutions_bytes = adapter.model_to_solution(
174
+ ... model, ommx_instance_bytes
175
+ ... )
176
+ >>> SolutionList.FromString(ommx_solutions_bytes).solutions[0].entries
177
+ {1: 0.0}
178
+ """
179
+ builder = PythonMIPBuilder(
180
+ ommx_instance_bytes,
181
+ sense=sense,
182
+ solver_name=solver_name,
183
+ solver=solver,
184
+ )
185
+ return builder.build()
186
+
187
+
188
+ def model_to_solution(
189
+ model: mip.Model,
190
+ ommx_instance_bytes: bytes,
191
+ ) -> bytes:
192
+ """
193
+ The function to create ommx.v1.SolutionList from optimized Python-MIP Model.
194
+
195
+ Args:
196
+ model (mip.Model): Optimized Python-MIP Model.
197
+ ommx_instance_bytes (bytes): Serialized ommx.v1.Instance.
198
+
199
+ Returns:
200
+ bytes: Serialized ommx.v1.SolutionList
201
+
202
+ Raises:
203
+ OMMXPythonMIPAdapterError: When ommx.v1.SolutionList cannot be created.
204
+
205
+ Examples:
206
+ The following example of solving an unconstrained linear optimization problem with x1 as the objective function.
207
+
208
+ >>> import ommx_python_mip_adapter as adapter
209
+ >>> from ommx.v1.decision_variables_pb2 import DecisionVariable, Bound
210
+ >>> from ommx.v1.instance_pb2 import Instance
211
+ >>> from ommx.v1.function_pb2 import Function
212
+ >>> from ommx.v1.linear_pb2 import Linear
213
+ >>> from ommx.v1.solution_pb2 import SolutionList
214
+ >>> ommx_instance = Instance(
215
+ ... decision_variables=[
216
+ ... DecisionVariable(
217
+ ... id=1,
218
+ ... kind=DecisionVariable.KIND_INTEGER,
219
+ ... bound=Bound(lower=0, upper=5),
220
+ ... ),
221
+ ... ],
222
+ ... objective=Function(
223
+ ... linear=Linear(
224
+ ... terms=[Linear.Term(id=1, coefficient=1)]
225
+ ... ),
226
+ ... ),
227
+ ... )
228
+ >>> ommx_instance_bytes = ommx_instance.SerializeToString()
229
+ >>> model = adapter.instance_to_model(ommx_instance_bytes)
230
+ >>> model.optimize()
231
+ <OptimizationStatus.OPTIMAL: 0>
232
+ >>> ommx_solutions_bytes = adapter.model_to_solution(
233
+ ... model, ommx_instance_bytes
234
+ ... )
235
+ >>> SolutionList.FromString(ommx_solutions_bytes).solutions[0].entries
236
+ {1: 0.0}
237
+ """
238
+ if not (
239
+ model.status == mip.OptimizationStatus.OPTIMAL
240
+ or model.status == mip.OptimizationStatus.FEASIBLE
241
+ ):
242
+ raise OMMXPythonMIPAdapterError(
243
+ "`model.status` must be `OPTIMAL` or `FEASIBLE`."
244
+ )
245
+
246
+ try:
247
+ ommx_instance = Instance.FromString(ommx_instance_bytes)
248
+ except Exception as e:
249
+ raise OMMXPythonMIPAdapterError(
250
+ "Invalid `ommx_instance_bytes` as ommx.v1.Instance."
251
+ ) from e
252
+
253
+ return SolutionList(
254
+ solutions=[
255
+ Solution(
256
+ entries={
257
+ var.id: model.var_by_name(str(var.id)).x # type: ignore
258
+ for var in ommx_instance.decision_variables
259
+ }
260
+ )
261
+ ]
262
+ ).SerializeToString()
@@ -0,0 +1,2 @@
1
+ class OMMXPythonMIPAdapterError(Exception):
2
+ pass
@@ -0,0 +1,104 @@
1
+ Metadata-Version: 2.1
2
+ Name: ommx_python_mip_adapter
3
+ Version: 0.1.0
4
+ Summary: An adapter for the Python-MIP from/to OMMX.
5
+ Author-email: "Jij Inc." <info@j-ij.com>
6
+ Project-URL: Repository, https://github.com/Jij-Inc/ommx-python-mip-adapter
7
+ Project-URL: Issues, https://github.com/Jij-Inc/ommx-python-mip-adapter/issues
8
+ Classifier: Programming Language :: Python :: 3 :: Only
9
+ Classifier: Programming Language :: Python :: 3.8
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE-APACHE
19
+ License-File: LICENSE-MIT
20
+ Requires-Dist: ommx<0.2.0,>=0.1.1
21
+ Requires-Dist: mip
22
+ Provides-Extra: dev
23
+ Requires-Dist: markdown-code-runner; extra == "dev"
24
+ Requires-Dist: mypy; extra == "dev"
25
+ Requires-Dist: numpy; extra == "dev"
26
+ Requires-Dist: pyright; extra == "dev"
27
+ Requires-Dist: pytest; extra == "dev"
28
+ Requires-Dist: sphinx; extra == "dev"
29
+ Requires-Dist: sphinx_rtd_theme; extra == "dev"
30
+ Requires-Dist: sphinx_fontawesome; extra == "dev"
31
+ Requires-Dist: sphinx-autoapi; extra == "dev"
32
+
33
+ OMMX adaptor for Python-MIP
34
+ ============================
35
+ ![PyPI - Version](https://img.shields.io/pypi/v/ommx-python-mip-adapter)
36
+
37
+ This package provides an adaptor for the [Python-MIP](https://www.python-mip.com/) from/to [OMMX](https://github.com/Jij-Inc/ommx)
38
+
39
+ Python-MIP as a solver in OMMX toolchain
40
+ -----------------------------------------
41
+ ```mermaid
42
+ sequenceDiagram
43
+ participant O as Other OMMX toolchain
44
+ participant A as Adapter
45
+ participant P as Python-MIP
46
+ O->>A: ommx::Instance and Parameters for Python-MIP;
47
+ A->>P: Translate into Python-MIP input
48
+ P->>P: Solve with CBC, Gurobi, or other solvers
49
+ P->>A: Solution
50
+ A->>O: ommx:Solution
51
+ ```
52
+
53
+ Python-MIP as a user interface to create OMMX instance
54
+ -------------------------------------------------------
55
+ TBW
56
+
57
+ Usage
58
+ ======
59
+ `ommx-python-mip-adapter` can be installed from PyPI as follows:
60
+
61
+ ```bash
62
+ pip install ommx-python-mip-adapter
63
+ ```
64
+
65
+ Python-MIP can be used through `ommx-python-mip-adapter` by using the following:
66
+
67
+ ```python markdown-code-runner
68
+ import ommx_python_mip_adapter as adapter
69
+ from ommx.v1.decision_variables_pb2 import DecisionVariable, Bound
70
+ from ommx.v1.instance_pb2 import Instance
71
+ from ommx.v1.function_pb2 import Function
72
+ from ommx.v1.linear_pb2 import Linear
73
+ from ommx.v1.solution_pb2 import SolutionList
74
+
75
+ ommx_instance = Instance(
76
+ decision_variables=[
77
+ DecisionVariable(
78
+ id=1,
79
+ kind=DecisionVariable.KIND_INTEGER,
80
+ bound=Bound(lower=0, upper=5),
81
+ ),
82
+ ],
83
+ objective=Function(
84
+ linear=Linear(
85
+ terms=[Linear.Term(id=1, coefficient=1)]
86
+ ),
87
+ ),
88
+ )
89
+ ommx_instance_bytes = ommx_instance.SerializeToString()
90
+
91
+ # Convert from `ommx.v1.Instance` to `mip.Model`
92
+ model = adapter.instance_to_model(ommx_instance_bytes)
93
+ model.optimize()
94
+ # Create `ommx.v1.SolutionList` from Optimized `mip.Model`
95
+ ommx_solutions_bytes = adapter.model_to_solution(
96
+ model, ommx_instance_bytes
97
+ )
98
+
99
+ print(SolutionList.FromString(ommx_solutions_bytes))
100
+ ```
101
+
102
+ Reference
103
+ ==============
104
+ - [OMMX-Python-MIP-Adapter API Reference](https://jij-inc.github.io/ommx-python-mip-adapter/index.html)
@@ -3,15 +3,21 @@ LICENSE-APACHE
3
3
  LICENSE-MIT
4
4
  README.md
5
5
  pyproject.toml
6
+ .github/workflows/docs.yml
6
7
  .github/workflows/publish.yml
7
8
  .github/workflows/test_and_lint.yml
9
+ docs/source/conf.py
10
+ docs/source/index.rst
8
11
  ommx_python_mip_adapter/__init__.py
9
12
  ommx_python_mip_adapter/_version.py
10
- ommx_python_mip_adapter/ommx_to_python_mip.py
13
+ ommx_python_mip_adapter/adapter.py
14
+ ommx_python_mip_adapter/exception.py
11
15
  ommx_python_mip_adapter.egg-info/PKG-INFO
12
16
  ommx_python_mip_adapter.egg-info/SOURCES.txt
13
17
  ommx_python_mip_adapter.egg-info/dependency_links.txt
14
18
  ommx_python_mip_adapter.egg-info/requires.txt
15
19
  ommx_python_mip_adapter.egg-info/top_level.txt
16
20
  tests/conftest.py
17
- tests/test_omm_to_python_mip.py
21
+ tests/test_adapter.py
22
+ tests/test_import.py
23
+ tests/test_integration.py
@@ -0,0 +1,13 @@
1
+ ommx<0.2.0,>=0.1.1
2
+ mip
3
+
4
+ [dev]
5
+ markdown-code-runner
6
+ mypy
7
+ numpy
8
+ pyright
9
+ pytest
10
+ sphinx
11
+ sphinx_rtd_theme
12
+ sphinx_fontawesome
13
+ sphinx-autoapi
@@ -18,15 +18,22 @@ classifiers = [
18
18
  "License :: OSI Approved :: MIT License",
19
19
  ]
20
20
  dependencies = [
21
- "ommx >= 0.1.0",
21
+ "ommx >= 0.1.1, < 0.2.0",
22
+ "mip",
22
23
  ]
23
24
 
24
25
 
25
26
  [project.optional-dependencies]
26
27
  dev = [
27
- "pytest",
28
+ "markdown-code-runner",
28
29
  "mypy",
30
+ "numpy",
29
31
  "pyright",
32
+ "pytest",
33
+ "sphinx",
34
+ "sphinx_rtd_theme",
35
+ "sphinx_fontawesome",
36
+ "sphinx-autoapi",
30
37
  ]
31
38
 
32
39
 
@@ -0,0 +1,147 @@
1
+ import mip
2
+ import pytest
3
+
4
+ from ommx.v1.constraint_pb2 import Constraint
5
+ from ommx.v1.decision_variables_pb2 import DecisionVariable
6
+ from ommx.v1.function_pb2 import Function
7
+ from ommx.v1.instance_pb2 import Instance
8
+ from ommx.v1.linear_pb2 import Linear
9
+ from ommx.v1.quadratic_pb2 import Quadratic
10
+ from ommx.testing import SingleFeasibleLPGenerator, DataType
11
+
12
+ import ommx_python_mip_adapter as adapter
13
+
14
+ from ommx_python_mip_adapter.exception import OMMXPythonMIPAdapterError
15
+
16
+ def test_error_invalid_instance():
17
+ with pytest.raises(OMMXPythonMIPAdapterError) as e:
18
+ adapter.instance_to_model(b"invalid")
19
+ assert "Invalid `ommx_instance_bytes`" in str(e.value)
20
+
21
+
22
+ def test_error_not_suppoerted_decision_variable():
23
+ ommx_instance = Instance(
24
+ decision_variables=[
25
+ DecisionVariable(
26
+ id=1,
27
+ kind=DecisionVariable.KIND_UNSPECIFIED,
28
+ )
29
+ ],
30
+ )
31
+ ommx_instance_bytes = ommx_instance.SerializeToString()
32
+
33
+ with pytest.raises(OMMXPythonMIPAdapterError) as e:
34
+ adapter.instance_to_model(ommx_instance_bytes)
35
+ assert "Not supported decision variable" in str(e.value)
36
+
37
+
38
+ def test_error_nonlinear_objective():
39
+ # Objective function: 2.3 * x * x
40
+ ommx_instance = Instance(
41
+ decision_variables=[
42
+ DecisionVariable(
43
+ id=0,
44
+ kind=DecisionVariable.KIND_CONTINUOUS,
45
+ ),
46
+ ],
47
+ objective=Function(
48
+ quadratic=Quadratic(
49
+ rows=[1],
50
+ columns=[1],
51
+ values=[2.3],
52
+ ),
53
+ ),
54
+ )
55
+ ommx_instance_bytes = ommx_instance.SerializeToString()
56
+
57
+ with pytest.raises(OMMXPythonMIPAdapterError) as e:
58
+ adapter.instance_to_model(ommx_instance_bytes)
59
+ assert "The objective function must be" in str(e.value)
60
+
61
+
62
+ def test_error_nonlinear_constraint():
63
+ # Objective function: 0
64
+ # Constraint: 2.3 * x * x = 0
65
+ ommx_instance = Instance(
66
+ decision_variables=[
67
+ DecisionVariable(
68
+ id=1,
69
+ kind=DecisionVariable.KIND_CONTINUOUS,
70
+ ),
71
+ ],
72
+ objective=Function(
73
+ constant=0,
74
+ ),
75
+ constraints=[
76
+ Constraint(
77
+ function=Function(
78
+ quadratic=Quadratic(
79
+ rows=[1],
80
+ columns=[1],
81
+ values=[2.3],
82
+ ),
83
+ ),
84
+ equality=Constraint.EQUALITY_EQUAL_TO_ZERO,
85
+ ),
86
+ ],
87
+ )
88
+ ommx_instance_bytes = ommx_instance.SerializeToString()
89
+
90
+ with pytest.raises(OMMXPythonMIPAdapterError) as e:
91
+ adapter.instance_to_model(ommx_instance_bytes)
92
+ assert "Only linear constraints are supported" in str(e.value)
93
+
94
+
95
+ def test_error_not_supported_constraint_equality():
96
+ # Objective function: 0
97
+ # Constraint: 2x ?? 0 (equality: unspecified)
98
+ ommx_instance = Instance(
99
+ decision_variables=[
100
+ DecisionVariable(
101
+ id=1,
102
+ kind=DecisionVariable.KIND_CONTINUOUS,
103
+ ),
104
+ ],
105
+ objective=Function(
106
+ constant=0,
107
+ ),
108
+ constraints=[
109
+ Constraint(
110
+ function=Function(
111
+ linear=Linear(
112
+ terms=[
113
+ Linear.Term(
114
+ id=1,
115
+ coefficient=2,
116
+ ),
117
+ ],
118
+ ),
119
+ ),
120
+ equality=Constraint.EQUALITY_UNSPECIFIED,
121
+ ),
122
+ ],
123
+ )
124
+ ommx_instance_bytes = ommx_instance.SerializeToString()
125
+
126
+ with pytest.raises(OMMXPythonMIPAdapterError) as e:
127
+ adapter.instance_to_model(ommx_instance_bytes)
128
+ assert "Not supported constraint equality" in str(e.value)
129
+
130
+
131
+ def test_error_not_optimized_model():
132
+ model = mip.Model()
133
+
134
+ with pytest.raises(OMMXPythonMIPAdapterError) as e:
135
+ adapter.model_to_solution(model, b"")
136
+ assert "`model.status` must be " in str(e.value)
137
+
138
+
139
+ def test_error_invalid_ommx_instance_bytes():
140
+ generator = SingleFeasibleLPGenerator(10, DataType.INT)
141
+ ommx_instance_bytes = generator.get_v1_instance()
142
+ model = adapter.instance_to_model(ommx_instance_bytes)
143
+ model.optimize()
144
+
145
+ with pytest.raises(OMMXPythonMIPAdapterError) as e:
146
+ adapter.model_to_solution(model, b"invalid")
147
+ assert "Invalid `ommx_instance_bytes`" in str(e.value)
@@ -0,0 +1,9 @@
1
+ def test_import():
2
+ import ommx_python_mip_adapter as adapter
3
+ from ommx_python_mip_adapter import instance_to_model
4
+ from ommx_python_mip_adapter import model_to_solution
5
+
6
+ assert adapter.instance_to_model
7
+ assert adapter.model_to_solution
8
+ assert instance_to_model
9
+ assert model_to_solution
@@ -0,0 +1,142 @@
1
+ import pytest
2
+
3
+ from ommx.v1.constraint_pb2 import Constraint
4
+ from ommx.v1.decision_variables_pb2 import DecisionVariable, Bound
5
+ from ommx.v1.function_pb2 import Function
6
+ from ommx.v1.instance_pb2 import Instance
7
+ from ommx.v1.linear_pb2 import Linear
8
+ from ommx.v1.solution_pb2 import SolutionList
9
+ from ommx.testing import SingleFeasibleLPGenerator, DataType
10
+
11
+ import ommx_python_mip_adapter as adapter
12
+
13
+
14
+ @pytest.mark.parametrize(
15
+ "generater",
16
+ [
17
+ SingleFeasibleLPGenerator(10, DataType.INT),
18
+ SingleFeasibleLPGenerator(10, DataType.FLOAT),
19
+ ]
20
+ )
21
+ def test_integration_lp(generater):
22
+ # Objective function: 0
23
+ # Constraints:
24
+ # A @ x = b (A: regular matrix, b: constant vector)
25
+ ommx_instance_bytes = generater.get_v1_instance()
26
+
27
+ model = adapter.instance_to_model(ommx_instance_bytes)
28
+ model.optimize()
29
+ ommx_solution = adapter.model_to_solution(model, ommx_instance_bytes)
30
+
31
+ ommx_solution_obj = SolutionList.FromString(ommx_solution)
32
+ expected_solution_obj = SolutionList.FromString(
33
+ generater.get_v1_solution()
34
+ )
35
+
36
+ # Check the number of solutions
37
+ assert len(ommx_solution_obj.solutions) == 1
38
+
39
+ actual_entries = ommx_solution_obj.solutions[0].entries
40
+ expected_entries = expected_solution_obj.solutions[0].entries
41
+
42
+ # Check the solution of each decision variable
43
+ for key, actual_value in actual_entries.items():
44
+ expected_value = expected_entries[key]
45
+ assert actual_value == pytest.approx(expected_value)
46
+
47
+
48
+ def test_integration_milp():
49
+ # Objective function: - x1 - x2
50
+ # Constraints:
51
+ # 3x1 - x2 - 6 <= 0
52
+ # -x1 + 3x2 - 6 <= 0
53
+ # 0 <= x1 <= 10 (x: integer)
54
+ # 0 <= x2 <= 10 (x: continuous)
55
+ # Optimal solution: x1 = 3, x2 = 3
56
+ LOWER_BOUND = 0
57
+ UPPER_BOUND = 10
58
+ ommx_instance = Instance(
59
+ decision_variables=[
60
+ DecisionVariable(
61
+ id=1,
62
+ kind=DecisionVariable.KIND_INTEGER,
63
+ bound=Bound(
64
+ lower=LOWER_BOUND,
65
+ upper=UPPER_BOUND,
66
+ ),
67
+ ),
68
+ DecisionVariable(
69
+ id=2,
70
+ kind=DecisionVariable.KIND_CONTINUOUS,
71
+ bound=Bound(
72
+ lower=LOWER_BOUND,
73
+ upper=UPPER_BOUND,
74
+ ),
75
+ ),
76
+ ],
77
+ objective=Function(
78
+ linear=Linear(
79
+ terms=[
80
+ Linear.Term(
81
+ id=1,
82
+ coefficient=-1,
83
+ ),
84
+ Linear.Term(
85
+ id=2,
86
+ coefficient=-1,
87
+ ),
88
+ ],
89
+ )
90
+ ),
91
+ constraints=[
92
+ Constraint(
93
+ function=Function(
94
+ linear=Linear(
95
+ terms=[
96
+ Linear.Term(
97
+ id=1,
98
+ coefficient=3,
99
+ ),
100
+ Linear.Term(
101
+ id=2,
102
+ coefficient=-1,
103
+ ),
104
+ ],
105
+ constant=-6
106
+ ),
107
+ ),
108
+ equality=Constraint.EQUALITY_LESS_THAN_OR_EQUAL_TO_ZERO,
109
+ ),
110
+ Constraint(
111
+ function=Function(
112
+ linear=Linear(
113
+ terms=[
114
+ Linear.Term(
115
+ id=1,
116
+ coefficient=-1,
117
+ ),
118
+ Linear.Term(
119
+ id=2,
120
+ coefficient=3,
121
+ ),
122
+ ],
123
+ constant=-6
124
+ ),
125
+ ),
126
+ equality=Constraint.EQUALITY_LESS_THAN_OR_EQUAL_TO_ZERO,
127
+ ),
128
+ ],
129
+ )
130
+ ommx_instance_bytes = ommx_instance.SerializeToString()
131
+
132
+ model = adapter.instance_to_model(ommx_instance_bytes)
133
+ model.optimize()
134
+ ommx_solution = adapter.model_to_solution(model, ommx_instance_bytes)
135
+
136
+ ommx_solution_obj = SolutionList.FromString(ommx_solution)
137
+
138
+ assert len(ommx_solution_obj.solutions) == 1
139
+
140
+ actual_entries = ommx_solution_obj.solutions[0].entries
141
+ assert actual_entries[1] == pytest.approx(3)
142
+ assert actual_entries[2] == pytest.approx(3)
@@ -1,47 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: ommx_python_mip_adapter
3
- Version: 0.0.2
4
- Summary: An adapter for the Python-MIP from/to OMMX.
5
- Author-email: "Jij Inc." <info@j-ij.com>
6
- Project-URL: Repository, https://github.com/Jij-Inc/ommx-python-mip-adapter
7
- Project-URL: Issues, https://github.com/Jij-Inc/ommx-python-mip-adapter/issues
8
- Classifier: Programming Language :: Python :: 3 :: Only
9
- Classifier: Programming Language :: Python :: 3.8
10
- Classifier: Programming Language :: Python :: 3.9
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3.11
13
- Classifier: Programming Language :: Python :: 3.12
14
- Classifier: License :: OSI Approved :: Apache Software License
15
- Classifier: License :: OSI Approved :: MIT License
16
- Requires-Python: >=3.8
17
- Description-Content-Type: text/markdown
18
- License-File: LICENSE-APACHE
19
- License-File: LICENSE-MIT
20
- Requires-Dist: ommx>=0.1.0
21
- Provides-Extra: dev
22
- Requires-Dist: pytest; extra == "dev"
23
- Requires-Dist: mypy; extra == "dev"
24
- Requires-Dist: pyright; extra == "dev"
25
-
26
- OMMX adaptor for Python-MIP
27
- ============================
28
-
29
- This package provides an adaptor for the [Python-MIP](https://www.python-mip.com/) from/to [OMMX](https://github.com/Jij-Inc/ommx)
30
-
31
- Python-MIP as a solver in OMMX toolchain
32
- -----------------------------------------
33
- ```mermaid
34
- sequenceDiagram
35
- participant O as Other OMMX toolchain
36
- participant A as Adapter
37
- participant P as Python-MIP
38
- O->>A: ommx::Instance and Parameters for Python-MIP;
39
- A->>P: Translate into Python-MIP input
40
- P->>P: Solve with CBC, Gurobi, or other solvers
41
- P->>A: Solution
42
- A->>O: ommx:Solution
43
- ```
44
-
45
- Python-MIP as a user interface to create OMMX instance
46
- -------------------------------------------------------
47
- TBW
@@ -1,22 +0,0 @@
1
- OMMX adaptor for Python-MIP
2
- ============================
3
-
4
- This package provides an adaptor for the [Python-MIP](https://www.python-mip.com/) from/to [OMMX](https://github.com/Jij-Inc/ommx)
5
-
6
- Python-MIP as a solver in OMMX toolchain
7
- -----------------------------------------
8
- ```mermaid
9
- sequenceDiagram
10
- participant O as Other OMMX toolchain
11
- participant A as Adapter
12
- participant P as Python-MIP
13
- O->>A: ommx::Instance and Parameters for Python-MIP;
14
- A->>P: Translate into Python-MIP input
15
- P->>P: Solve with CBC, Gurobi, or other solvers
16
- P->>A: Solution
17
- A->>O: ommx:Solution
18
- ```
19
-
20
- Python-MIP as a user interface to create OMMX instance
21
- -------------------------------------------------------
22
- TBW
@@ -1,2 +0,0 @@
1
- def ommx_to_python_mip() -> None:
2
- print("Hello, OMMX-PythonMIP-Adapter!")
@@ -1,47 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: ommx_python_mip_adapter
3
- Version: 0.0.2
4
- Summary: An adapter for the Python-MIP from/to OMMX.
5
- Author-email: "Jij Inc." <info@j-ij.com>
6
- Project-URL: Repository, https://github.com/Jij-Inc/ommx-python-mip-adapter
7
- Project-URL: Issues, https://github.com/Jij-Inc/ommx-python-mip-adapter/issues
8
- Classifier: Programming Language :: Python :: 3 :: Only
9
- Classifier: Programming Language :: Python :: 3.8
10
- Classifier: Programming Language :: Python :: 3.9
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3.11
13
- Classifier: Programming Language :: Python :: 3.12
14
- Classifier: License :: OSI Approved :: Apache Software License
15
- Classifier: License :: OSI Approved :: MIT License
16
- Requires-Python: >=3.8
17
- Description-Content-Type: text/markdown
18
- License-File: LICENSE-APACHE
19
- License-File: LICENSE-MIT
20
- Requires-Dist: ommx>=0.1.0
21
- Provides-Extra: dev
22
- Requires-Dist: pytest; extra == "dev"
23
- Requires-Dist: mypy; extra == "dev"
24
- Requires-Dist: pyright; extra == "dev"
25
-
26
- OMMX adaptor for Python-MIP
27
- ============================
28
-
29
- This package provides an adaptor for the [Python-MIP](https://www.python-mip.com/) from/to [OMMX](https://github.com/Jij-Inc/ommx)
30
-
31
- Python-MIP as a solver in OMMX toolchain
32
- -----------------------------------------
33
- ```mermaid
34
- sequenceDiagram
35
- participant O as Other OMMX toolchain
36
- participant A as Adapter
37
- participant P as Python-MIP
38
- O->>A: ommx::Instance and Parameters for Python-MIP;
39
- A->>P: Translate into Python-MIP input
40
- P->>P: Solve with CBC, Gurobi, or other solvers
41
- P->>A: Solution
42
- A->>O: ommx:Solution
43
- ```
44
-
45
- Python-MIP as a user interface to create OMMX instance
46
- -------------------------------------------------------
47
- TBW
@@ -1,6 +0,0 @@
1
- ommx>=0.1.0
2
-
3
- [dev]
4
- pytest
5
- mypy
6
- pyright
@@ -1,2 +0,0 @@
1
- def test_import():
2
- import ommx_python_mip_adapter