Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MPS and GZ support in translators #583

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .pylintdict
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ gurobi
gurobioptimizer
gurobipy
gutmann
gzip'ed
hamilton
hamiltonian
hamiltonians
Expand Down Expand Up @@ -125,6 +126,7 @@ minimizer
minimumeigenoptimizer
mmp
mpm
mps
multiset
mypy
nannicini
Expand Down Expand Up @@ -233,6 +235,7 @@ transpiling
travelling
troyer
tsplib
uncompress
undirected
upperbound
variational
Expand Down
27 changes: 22 additions & 5 deletions docs/tutorials/01_quadratic_program.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@
"\n",
"quadratic dict w/ index:\t {(0, 1): 2, (2, 2): -1}\n",
"quadratic dict w/ name:\t\t {('x', 'y'): 2, ('z', 'z'): -1}\n",
"symmetric quadratic dict w/ name:\t {('y', 'x'): 1, ('x', 'y'): 1, ('z', 'z'): -1}\n",
"symmetric quadratic dict w/ name:\t {('x', 'y'): 1, ('y', 'x'): 1, ('z', 'z'): -1}\n",
"quadratic matrix:\n",
" [[ 0 2 0]\n",
" [ 0 0 0]\n",
Expand Down Expand Up @@ -786,12 +786,15 @@
}
],
"source": [
"from qiskit_optimization.translators import export_as_lp_string\n",
"\n",
"mod = QuadraticProgram()\n",
"mod.binary_var(name=\"e\")\n",
"mod.binary_var(name=\"f\")\n",
"mod.continuous_var(name=\"g\")\n",
"mod.minimize(linear=[1, 2, 3])\n",
"print(mod.export_as_lp_string())"
"\n",
"print(export_as_lp_string(mod))"
]
},
{
Expand All @@ -802,7 +805,7 @@
{
"data": {
"text/html": [
"<h3>Version Information</h3><table><tr><th>Qiskit Software</th><th>Version</th></tr><tr><td><code>qiskit-terra</code></td><td>0.21.0.dev0+dbd3961</td></tr><tr><td><code>qiskit-aer</code></td><td>0.10.4</td></tr><tr><td><code>qiskit-ibmq-provider</code></td><td>0.19.1</td></tr><tr><td><code>qiskit-optimization</code></td><td>0.4.0</td></tr><tr><th>System information</th></tr><tr><td>Python version</td><td>3.10.4</td></tr><tr><td>Python compiler</td><td>GCC 11.2.0</td></tr><tr><td>Python build</td><td>main, Apr 2 2022 09:04:19</td></tr><tr><td>OS</td><td>Linux</td></tr><tr><td>CPUs</td><td>4</td></tr><tr><td>Memory (Gb)</td><td>14.577545166015625</td></tr><tr><td colspan='2'>Wed May 18 16:03:27 2022 JST</td></tr></table>"
"<h3>Version Information</h3><table><tr><th>Software</th><th>Version</th></tr><tr><td><code>qiskit</code></td><td>0.45.1</td></tr><tr><td><code>qiskit_optimization</code></td><td>0.7.0</td></tr><tr><th colspan='2'>System information</th></tr><tr><td>Python version</td><td>3.10.13</td></tr><tr><td>Python compiler</td><td>GCC 13.2.1 20231205 (Red Hat 13.2.1-6)</td></tr><tr><td>Python build</td><td>main, Dec 18 2023 00:00:00</td></tr><tr><td>OS</td><td>Linux</td></tr><tr><td>CPUs</td><td>12</td></tr><tr><td>Memory (Gb)</td><td>31.056407928466797</td></tr><tr><td colspan='2'>Mon Feb 05 10:25:02 2024 CET</td></tr></table>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
Expand All @@ -814,7 +817,7 @@
{
"data": {
"text/html": [
"<div style='width: 100%; background-color:#d5d9e0;padding-left: 10px; padding-bottom: 10px; padding-right: 10px; padding-top: 5px'><h3>This code is a part of Qiskit</h3><p>&copy; Copyright IBM 2017, 2022.</p><p>This code is licensed under the Apache License, Version 2.0. You may<br>obtain a copy of this license in the LICENSE.txt file in the root directory<br> of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.<p>Any modifications or derivative works of this code must retain this<br>copyright notice, and modified files need to carry a notice indicating<br>that they have been altered from the originals.</p></div>"
"<div style='width: 100%; background-color:#d5d9e0;padding-left: 10px; padding-bottom: 10px; padding-right: 10px; padding-top: 5px'><h3>This code is a part of Qiskit</h3><p>&copy; Copyright IBM 2017, 2024.</p><p>This code is licensed under the Apache License, Version 2.0. You may<br>obtain a copy of this license in the LICENSE.txt file in the root directory<br> of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.<p>Any modifications or derivative works of this code must retain this<br>copyright notice, and modified files need to carry a notice indicating<br>that they have been altered from the originals.</p></div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
Expand All @@ -840,8 +843,22 @@
}
],
"metadata": {
"kernelspec": {
"display_name": "venv",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python"
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
}
},
"nbformat": 4,
Expand Down
9 changes: 5 additions & 4 deletions qiskit_optimization/algorithms/admm_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from ..problems.linear_expression import LinearExpression
from ..problems.quadratic_program import QuadraticProgram
from ..problems.variable import Variable, VarType
from ..translators import export_as_lp_string
from .minimum_eigen_optimizer import MinimumEigenOptimizer
from .optimization_algorithm import (
OptimizationAlgorithm,
Expand Down Expand Up @@ -282,7 +283,7 @@ def solve(self, problem: QuadraticProgram) -> ADMMOptimizationResult:
self._verify_compatibility(problem)

# debug
self._log.debug("Initial problem: %s", problem.export_as_lp_string())
self._log.debug("Initial problem: %s", export_as_lp_string(problem))

# map integer variables to binary variables
from ..converters.integer_to_binary import IntegerToBinary
Expand Down Expand Up @@ -321,15 +322,15 @@ def solve(self, problem: QuadraticProgram) -> ADMMOptimizationResult:
op1 = self._create_step1_problem()
self._state.x0 = self._update_x0(op1)
# debug
self._log.debug("Step 1 sub-problem: %s", op1.export_as_lp_string())
self._log.debug("Step 1 sub-problem: %s", export_as_lp_string(op1))
# else, no binary variables exist, and no update to be done in this case.
# debug
self._log.debug("x0=%s", self._state.x0)

op2 = self._create_step2_problem()
self._state.u, self._state.z = self._update_x1(op2)
# debug
self._log.debug("Step 2 sub-problem: %s", op2.export_as_lp_string())
self._log.debug("Step 2 sub-problem: %s", export_as_lp_string(op2))
self._log.debug("u=%s", self._state.u)
self._log.debug("z=%s", self._state.z)

Expand All @@ -338,7 +339,7 @@ def solve(self, problem: QuadraticProgram) -> ADMMOptimizationResult:
op3 = self._create_step3_problem()
self._state.y = self._update_y(op3)
# debug
self._log.debug("Step 3 sub-problem: %s", op3.export_as_lp_string())
self._log.debug("Step 3 sub-problem: %s", export_as_lp_string(op3))
# debug
self._log.debug("y=%s", self._state.y)

Expand Down
60 changes: 33 additions & 27 deletions qiskit_optimization/problems/quadratic_program.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of a Qiskit project.
#
# (C) Copyright IBM 2019, 2023.
# (C) Copyright IBM 2019, 2024.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
Expand All @@ -20,8 +20,8 @@
from warnings import warn

import numpy as np
from docplex.mp.model_reader import ModelReader
from numpy import ndarray
from qiskit.utils.deprecation import deprecate_func
from qiskit.quantum_info import SparsePauliOp
from qiskit.quantum_info.operators.base_operator import BaseOperator
from scipy.sparse import spmatrix
Expand Down Expand Up @@ -911,52 +911,58 @@ def _copy_from(self, other: "QuadraticProgram", include_name: bool) -> None:
elem.quadratic_program = self
setattr(self, attr, val)

@deprecate_func(
additional_msg=(
"Please use export_as_lp_string from qiskit_optimization.translators.file_io instead."
),
since="0.6.0",
pending=True,
)
def export_as_lp_string(self) -> str:
"""Returns the quadratic program as a string of LP format.

Returns:
A string representing the quadratic program.
"""

# pylint: disable=cyclic-import
from ..translators.docplex_mp import to_docplex_mp
from ..translators.file_io import export_as_lp_string

return to_docplex_mp(self).export_as_lp_string()
return export_as_lp_string(self)

@_optionals.HAS_CPLEX.require_in_call
@deprecate_func(
additional_msg=(
"Please use read_from_lp_file from qiskit_optimization.translators.file_io instead."
),
since="0.6.0",
pending=True,
)
def read_from_lp_file(self, filename: str) -> None:
"""Loads the quadratic program from a LP file.
"""Loads the quadratic program from a LP file (may be gzip'ed).

Args:
filename: The filename of the file to be loaded.

Raises:
FileNotFoundError: If the file does not exist.
IOError: If the file type is not recognized, not supported or the file is not found.

Note:
This method requires CPLEX to be installed and present in ``PYTHONPATH``.
"""

def _parse_problem_name(filename: str) -> str:
# Because docplex model reader uses the base name as model name,
# we parse the model name in the LP file manually.
# https://ibmdecisionoptimization.github.io/docplex-doc/mp/docplex.mp.model_reader.html
prefix = "\\Problem name:"
model_name = ""
with open(filename, encoding="utf8") as file:
for line in file:
if line.startswith(prefix):
model_name = line[len(prefix) :].strip()
if not line.startswith("\\"):
break
return model_name

# pylint: disable=cyclic-import
from ..translators.docplex_mp import from_docplex_mp
from ..translators.file_io import read_from_lp_file

model = ModelReader().read(filename, model_name=_parse_problem_name(filename))
other = from_docplex_mp(model)
self._copy_from(other, include_name=True)
self._copy_from(read_from_lp_file(filename), include_name=True)

@deprecate_func(
additional_msg=(
"Please use write_to_lp_file from qiskit_optimization.translators.file_io instead."
),
since="0.6.0",
pending=True,
)
def write_to_lp_file(self, filename: str) -> None:
"""Writes the quadratic program to an LP file.

Expand All @@ -969,11 +975,11 @@ def write_to_lp_file(self, filename: str) -> None:
OSError: If this cannot open a file.
DOcplexException: If filename is an empty string
"""

# pylint: disable=cyclic-import
from ..translators.docplex_mp import to_docplex_mp
from ..translators.file_io import write_to_lp_file

mdl = to_docplex_mp(self)
mdl.export_as_lp(filename)
write_to_lp_file(self, filename)

def substitute_variables(
self,
Expand Down
14 changes: 14 additions & 0 deletions qiskit_optimization/translators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@
"""

from .docplex_mp import from_docplex_mp, to_docplex_mp
from .file_io import (
Copy link
Member

@woodsp-ibm woodsp-ibm Feb 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should include these in the documentation as they are public methods we now expect a user to use. You can see the pre-existing list above in the docstring - maybe it makes sense to have another section that lists these - or perhaps the export ones go under Translators there and the others under "File loading and saving" ?

You can see what the current page looks like from here https://qiskit-community.github.io/qiskit-optimization/apidocs/qiskit_optimization.translators.html. To build docs locally runmake html in the project root, or make clean html which will wipe away whats there which sometimes is needed if the incremental build does not come out as expected - I find this more if I change the structure. One or more docstrings changed is pretty much ok. html will be in the _build folder that is created under docs

If you want to see how the docs come out in the build, if you go to build Details and Summary you can scroll down and see artifacts that the build creates. documentation is the docs built without running the tutorials as a quicker check. tutorials_3.x are jobs under that version of Python that also build the docs but run the notebooks too.

export_as_lp_string,
export_as_mps_string,
read_from_lp_file,
read_from_mps_file,
write_to_lp_file,
write_to_mps_file,
)
from .gurobipy import from_gurobipy, to_gurobipy
from .ising import from_ising, to_ising

Expand All @@ -44,4 +52,10 @@
"to_gurobipy",
"from_ising",
"to_ising",
"export_as_lp_string",
"export_as_mps_string",
"read_from_lp_file",
"read_from_mps_file",
"write_to_lp_file",
"write_to_mps_file",
]
Loading