From fbd0281c0c535136e1e898f2660cb020e4a2acdd Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 21 Nov 2023 09:44:52 -0500 Subject: [PATCH] Update platform support and require symengine (#10902) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update platform support and require symengine This commit updates our platform support matrix to reflect upcoming changes. The first is that in Rust 1.74 the Rust programming language is raising their minimum support macOS version to 10.12, so Qiskit is raising it's supported version of macOS to match this. The second change is making symengine a hard requirement. We previously had symengine as a requirement only on platforms that had precompiled packages available. But, the percentage of our user base that runs qiskit on those platforms is very small, and maintaining dual support for symengine and sympy adds a lot of complexity around managing the dependencies. This commit promotes symengine to a hard requirement for all users regardless of platform. As a result Linux i686 and 32 bit Windows for Python < 3.10 has been downgraded to tier 3 support as you'll need a C++ to install Qiskit on that platform now (regardless of Python version). * Fix use_symengine ScheduleBlock * Remove duplicated release note * Apply suggestions from code review Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --------- Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- docs/getting_started.rst | 10 +- pyproject.toml | 3 +- qiskit/circuit/parameter.py | 18 +- qiskit/circuit/parameterexpression.py | 160 ++++-------------- qiskit/pulse/library/symbolic_pulses.py | 58 +++---- qiskit/qpy/binary_io/schedules.py | 27 +-- qiskit/qpy/binary_io/value.py | 28 +-- qiskit/qpy/interface.py | 2 +- .../platform-support-f7f693aaf5dec044.yaml | 29 ++++ requirements.txt | 5 +- .../circuit/test_circuit_load_from_qpy.py | 20 --- test/python/qpy/test_block_load_from_qpy.py | 20 --- 12 files changed, 112 insertions(+), 268 deletions(-) create mode 100644 releasenotes/notes/platform-support-f7f693aaf5dec044.yaml diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 2b9f94d280fd..52e04ec7a990 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -198,7 +198,7 @@ Tier 1 platforms are currently: * Linux x86_64 (distributions compatible with the `manylinux 2014 `__ packaging specification). - * macOS x86_64 (10.9 or newer) + * macOS x86_64 (10.12 or newer) * Windows 64 bit Tier 2 @@ -211,10 +211,6 @@ functioning Python environment. Tier 2 platforms are currently: - * Linux i686 (distributions compatible with the - `manylinux 2014 `__ packaging - specification) for Python < 3.10 - * Windows 32 bit for Python < 3.10 * Linux aarch64 (distributions compatible with the `manylinux 2014 `__ packaging specification) @@ -240,8 +236,8 @@ Tier 3 platforms are currently: * macOS arm64 (10.15 or newer) * Linux i686 (distributions compatible with the `manylinux 2014 `__ packaging - specification) for Python >= 3.10 - * Windows 32 bit for Python >= 3.10 + specification) + * Windows 32 bit Ready to get going?... ====================== diff --git a/pyproject.toml b/pyproject.toml index 25ff0a5dade7..172c0625d25b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ target-version = ['py38', 'py39', 'py310', 'py311'] manylinux-x86_64-image = "manylinux2014" manylinux-i686-image = "manylinux2014" skip = "pp* cp36-* cp37-* *musllinux*" -test-skip = "cp310-win32 cp310-manylinux_i686 cp311-win32 cp311-manylinux_i686" +test-skip = "*win32 *linux_i686" test-command = "python {project}/examples/python/stochastic_swap.py" # We need to use pre-built versions of Numpy and Scipy in the tests; they have a # tendency to crash if they're installed from source by `pip install`, and since @@ -25,6 +25,7 @@ environment = 'PATH="$PATH:$HOME/.cargo/bin" CARGO_NET_GIT_FETCH_WITH_CLI="true" repair-wheel-command = "auditwheel repair -w {dest_dir} {wheel} && pipx run abi3audit --strict --report {wheel}" [tool.cibuildwheel.macos] +environment = "MACOSX_DEPLOYMENT_TARGET=10.12" repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel} && pipx run abi3audit --strict --report {wheel}" [tool.cibuildwheel.windows] diff --git a/qiskit/circuit/parameter.py b/qiskit/circuit/parameter.py index e354a708eace..42ffad5ebf0a 100644 --- a/qiskit/circuit/parameter.py +++ b/qiskit/circuit/parameter.py @@ -17,8 +17,9 @@ from uuid import uuid4, UUID +import symengine + from qiskit.circuit.exceptions import CircuitError -from qiskit.utils import optionals as _optionals from .parameterexpression import ParameterExpression @@ -75,14 +76,7 @@ def __init__( """ self._name = name self._uuid = uuid4() if uuid is None else uuid - if not _optionals.HAS_SYMENGINE: - from sympy import Symbol - - symbol = Symbol(name) - else: - import symengine - - symbol = symengine.Symbol(name) + symbol = symengine.Symbol(name) self._symbol_expr = symbol self._parameter_keys = frozenset((self._hash_key(),)) @@ -102,11 +96,7 @@ def assign(self, parameter, value): return value # This is the `super().bind` case, where we're required to return a `ParameterExpression`, # so we need to lift the given value to a symbolic expression. - if _optionals.HAS_SYMENGINE: - from symengine import sympify - else: - from sympy import sympify - return ParameterExpression({}, sympify(value)) + return ParameterExpression({}, symengine.sympify(value)) def subs(self, parameter_map: dict, allow_unknown_parameters: bool = False): """Substitute self with the corresponding parameter in ``parameter_map``.""" diff --git a/qiskit/circuit/parameterexpression.py b/qiskit/circuit/parameterexpression.py index 6b88cede34e1..790fc29b8135 100644 --- a/qiskit/circuit/parameterexpression.py +++ b/qiskit/circuit/parameterexpression.py @@ -20,9 +20,9 @@ import operator import numpy +import symengine from qiskit.circuit.exceptions import CircuitError -from qiskit.utils import optionals as _optionals # This type is redefined at the bottom to insert the full reference to "ParameterExpression", so it # can safely be used by runtime type-checkers like Sphinx. Mypy does not need this because it @@ -69,14 +69,9 @@ def _names(self) -> dict: def conjugate(self) -> "ParameterExpression": """Return the conjugate.""" - if _optionals.HAS_SYMENGINE: - import symengine - - conjugated = ParameterExpression( - self._parameter_symbols, symengine.conjugate(self._symbol_expr) - ) - else: - conjugated = ParameterExpression(self._parameter_symbols, self._symbol_expr.conjugate()) + conjugated = ParameterExpression( + self._parameter_symbols, symengine.conjugate(self._symbol_expr) + ) return conjugated def assign(self, parameter, value: ParameterValueType) -> "ParameterExpression": @@ -185,15 +180,7 @@ def subs( new_parameter_symbols = { p: s for p, s in self._parameter_symbols.items() if p not in parameter_map } - - if _optionals.HAS_SYMENGINE: - import symengine - - symbol_type = symengine.Symbol - else: - from sympy import Symbol - - symbol_type = Symbol + symbol_type = symengine.Symbol # If new_param is an expr, we'll need to construct a matching sympy expr # but with our sympy symbols instead of theirs. @@ -306,15 +293,7 @@ def gradient(self, param) -> Union["ParameterExpression", complex]: # Compute the gradient of the parameter expression w.r.t. param key = self._parameter_symbols[param] - if _optionals.HAS_SYMENGINE: - import symengine - - expr_grad = symengine.Derivative(self._symbol_expr, key) - else: - # TODO enable nth derivative - from sympy import Derivative - - expr_grad = Derivative(self._symbol_expr, key).doit() + expr_grad = symengine.Derivative(self._symbol_expr, key) # generate the new dictionary of symbols # this needs to be done since in the derivative some symbols might disappear (e.g. @@ -367,102 +346,39 @@ def _call(self, ufunc): def sin(self): """Sine of a ParameterExpression""" - if _optionals.HAS_SYMENGINE: - import symengine - - return self._call(symengine.sin) - else: - from sympy import sin as _sin - - return self._call(_sin) + return self._call(symengine.sin) def cos(self): """Cosine of a ParameterExpression""" - if _optionals.HAS_SYMENGINE: - import symengine - - return self._call(symengine.cos) - else: - from sympy import cos as _cos - - return self._call(_cos) + return self._call(symengine.cos) def tan(self): """Tangent of a ParameterExpression""" - if _optionals.HAS_SYMENGINE: - import symengine - - return self._call(symengine.tan) - else: - from sympy import tan as _tan - - return self._call(_tan) + return self._call(symengine.tan) def arcsin(self): """Arcsin of a ParameterExpression""" - if _optionals.HAS_SYMENGINE: - import symengine - - return self._call(symengine.asin) - else: - from sympy import asin as _asin - - return self._call(_asin) + return self._call(symengine.asin) def arccos(self): """Arccos of a ParameterExpression""" - if _optionals.HAS_SYMENGINE: - import symengine - - return self._call(symengine.acos) - else: - from sympy import acos as _acos - - return self._call(_acos) + return self._call(symengine.acos) def arctan(self): """Arctan of a ParameterExpression""" - if _optionals.HAS_SYMENGINE: - import symengine - - return self._call(symengine.atan) - else: - from sympy import atan as _atan - - return self._call(_atan) + return self._call(symengine.atan) def exp(self): """Exponential of a ParameterExpression""" - if _optionals.HAS_SYMENGINE: - import symengine - - return self._call(symengine.exp) - else: - from sympy import exp as _exp - - return self._call(_exp) + return self._call(symengine.exp) def log(self): """Logarithm of a ParameterExpression""" - if _optionals.HAS_SYMENGINE: - import symengine - - return self._call(symengine.log) - else: - from sympy import log as _log - - return self._call(_log) + return self._call(symengine.log) def sign(self): """Sign of a ParameterExpression""" - if _optionals.HAS_SYMENGINE: - import symengine - - return self._call(symengine.sign) - else: - from sympy import sign as _sign - - return self._call(_sign) + return self._call(symengine.sign) def __repr__(self): return f"{self.__class__.__name__}({str(self)})" @@ -494,24 +410,21 @@ def __float__(self): "ParameterExpression with unbound parameters ({}) " "cannot be cast to a float.".format(self.parameters) ) from None - try: - # In symengine, if an expression was complex at any time, its type is likely to have - # stayed "complex" even when the imaginary part symbolically (i.e. exactly) - # cancelled out. Sympy tends to more aggressively recognise these as symbolically - # real. This second attempt at a cast is a way of unifying the behaviour to the - # more expected form for our users. - cval = complex(self) - if cval.imag == 0.0: - return cval.real - except TypeError: - pass + # In symengine, if an expression was complex at any time, its type is likely to have + # stayed "complex" even when the imaginary part symbolically (i.e. exactly) + # cancelled out. Sympy tends to more aggressively recognise these as symbolically + # real. This second attempt at a cast is a way of unifying the behaviour to the + # more expected form for our users. + cval = complex(self) + if cval.imag == 0.0: + return cval.real raise TypeError("could not cast expression to float") from exc def __int__(self): try: return int(self._symbol_expr) - # TypeError is for sympy, RuntimeError for symengine - except (TypeError, RuntimeError) as exc: + # TypeError is for backwards compatibility, RuntimeError is raised by symengine + except RuntimeError as exc: if self.parameters: raise TypeError( "ParameterExpression with unbound parameters ({}) " @@ -530,14 +443,7 @@ def __deepcopy__(self, memo=None): def __abs__(self): """Absolute of a ParameterExpression""" - if _optionals.HAS_SYMENGINE: - import symengine - - return self._call(symengine.Abs) - else: - from sympy import Abs as _abs - - return self._call(_abs) + return self._call(symengine.Abs) def abs(self): """Absolute of a ParameterExpression""" @@ -555,12 +461,9 @@ def __eq__(self, other): if isinstance(other, ParameterExpression): if self.parameters != other.parameters: return False - if _optionals.HAS_SYMENGINE: - from sympy import sympify + from sympy import sympify - return sympify(self._symbol_expr).equals(sympify(other._symbol_expr)) - else: - return self._symbol_expr.equals(other._symbol_expr) + return sympify(self._symbol_expr).equals(sympify(other._symbol_expr)) elif isinstance(other, numbers.Number): return len(self.parameters) == 0 and complex(self._symbol_expr) == other return False @@ -570,7 +473,7 @@ def is_real(self): # workaround for symengine behavior that const * (0 + 1 * I) is not real # see https://github.com/symengine/symengine.py/issues/414 - if _optionals.HAS_SYMENGINE and self._symbol_expr.is_real is None: + if self._symbol_expr.is_real is None: symbol_expr = self._symbol_expr.evalf() else: symbol_expr = self._symbol_expr @@ -581,9 +484,8 @@ def is_real(self): # but the parameter will evaluate as real. Check that if the # expression's is_real attribute returns false that we have a # non-zero imaginary - if _optionals.HAS_SYMENGINE: - if symbol_expr.imag == 0.0: - return True + if symbol_expr.imag == 0.0: + return True return False return symbol_expr.is_real diff --git a/qiskit/pulse/library/symbolic_pulses.py b/qiskit/pulse/library/symbolic_pulses.py index 9bc18c9c7f13..a943bb1acf60 100644 --- a/qiskit/pulse/library/symbolic_pulses.py +++ b/qiskit/pulse/library/symbolic_pulses.py @@ -23,19 +23,14 @@ from copy import deepcopy import numpy as np +import symengine as sym from qiskit.circuit.parameterexpression import ParameterExpression, ParameterValueType from qiskit.pulse.exceptions import PulseError from qiskit.pulse.library.pulse import Pulse from qiskit.pulse.library.waveform import Waveform -from qiskit.utils import optionals as _optional from qiskit.utils.deprecation import deprecate_arg -if _optional.HAS_SYMENGINE: - import symengine as sym -else: - import sympy as sym - def _lifted_gaussian( t: sym.Symbol, @@ -183,34 +178,31 @@ def __set__(self, instance, value): continue params.append(p) - if _optional.HAS_SYMENGINE: - try: - lamb = sym.lambdify(params, [value], real=False) - - def _wrapped_lamb(*args): - if isinstance(args[0], np.ndarray): - # When the args[0] is a vector ("t"), tile other arguments args[1:] - # to prevent evaluation from looping over each element in t. - t = args[0] - args = np.hstack( - ( - t.reshape(t.size, 1), - np.tile(args[1:], t.size).reshape(t.size, len(args) - 1), - ) + try: + lamb = sym.lambdify(params, [value], real=False) + + def _wrapped_lamb(*args): + if isinstance(args[0], np.ndarray): + # When the args[0] is a vector ("t"), tile other arguments args[1:] + # to prevent evaluation from looping over each element in t. + t = args[0] + args = np.hstack( + ( + t.reshape(t.size, 1), + np.tile(args[1:], t.size).reshape(t.size, len(args) - 1), ) - return lamb(args) - - func = _wrapped_lamb - except RuntimeError: - # Currently symengine doesn't support complex_double version for - # several functions such as comparison operator and piecewise. - # If expression contains these function, it fall back to sympy lambdify. - # See https://github.com/symengine/symengine.py/issues/406 for details. - import sympy - - func = sympy.lambdify(params, value) - else: - func = sym.lambdify(params, value) + ) + return lamb(args) + + func = _wrapped_lamb + except RuntimeError: + # Currently symengine doesn't support complex_double version for + # several functions such as comparison operator and piecewise. + # If expression contains these function, it fall back to sympy lambdify. + # See https://github.com/symengine/symengine.py/issues/406 for details. + import sympy + + func = sympy.lambdify(params, value) self.lambda_funcs[key] = func diff --git a/qiskit/qpy/binary_io/schedules.py b/qiskit/qpy/binary_io/schedules.py index 25ca9388bb4e..ce22702c89da 100644 --- a/qiskit/qpy/binary_io/schedules.py +++ b/qiskit/qpy/binary_io/schedules.py @@ -19,6 +19,10 @@ from io import BytesIO import numpy as np +import symengine as sym +from symengine.lib.symengine_wrapper import ( # pylint: disable = no-name-in-module + load_basic, +) from qiskit.exceptions import QiskitError from qiskit.pulse import library, channels, instructions @@ -26,14 +30,8 @@ from qiskit.qpy import formats, common, type_keys from qiskit.qpy.binary_io import value from qiskit.qpy.exceptions import QpyError -from qiskit.utils import optionals as _optional from qiskit.pulse.configuration import Kernel, Discriminator -if _optional.HAS_SYMENGINE: - import symengine as sym -else: - import sympy as sym - def _read_channel(file_obj, version): type_key = common.read_type_key(file_obj) @@ -106,23 +104,15 @@ def _read_discriminator(file_obj, version): def _loads_symbolic_expr(expr_bytes, use_symengine=False): if expr_bytes == b"": return None + expr_bytes = zlib.decompress(expr_bytes) if use_symengine: - _optional.HAS_SYMENGINE.require_now("load a symengine expression") - from symengine.lib.symengine_wrapper import ( # pylint: disable = no-name-in-module - load_basic, - ) - - expr = load_basic(zlib.decompress(expr_bytes)) + return load_basic(expr_bytes) else: from sympy import parse_expr - expr_txt = zlib.decompress(expr_bytes).decode(common.ENCODE) + expr_txt = expr_bytes.decode(common.ENCODE) expr = parse_expr(expr_txt) - if _optional.HAS_SYMENGINE: - from symengine import sympify - - return sympify(expr) - return expr + return sym.sympify(expr) def _read_symbolic_pulse(file_obj, version): @@ -404,7 +394,6 @@ def _dumps_symbolic_expr(expr, use_symengine): if expr is None: return b"" if use_symengine: - _optional.HAS_SYMENGINE.require_now("dump a symengine expression") expr_bytes = expr.__reduce__()[1][0] else: from sympy import srepr, sympify diff --git a/qiskit/qpy/binary_io/value.py b/qiskit/qpy/binary_io/value.py index 7bae82c6911f..686e72c9a4e6 100644 --- a/qiskit/qpy/binary_io/value.py +++ b/qiskit/qpy/binary_io/value.py @@ -19,6 +19,11 @@ import uuid import numpy as np +import symengine +from symengine.lib.symengine_wrapper import ( # pylint: disable = no-name-in-module + load_basic, +) + from qiskit.circuit import CASE_DEFAULT, Clbit, ClassicalRegister from qiskit.circuit.classical import expr, types @@ -26,7 +31,6 @@ from qiskit.circuit.parameterexpression import ParameterExpression from qiskit.circuit.parametervector import ParameterVector, ParameterVectorElement from qiskit.qpy import common, formats, exceptions, type_keys -from qiskit.utils import optionals as _optional def _write_parameter(file_obj, obj): @@ -51,7 +55,6 @@ def _write_parameter_vec(file_obj, obj): def _write_parameter_expression(file_obj, obj, use_symengine): if use_symengine: - _optional.HAS_SYMENGINE.require_now("write_parameter_expression") expr_bytes = obj._symbol_expr.__reduce__()[1][0] else: from sympy import srepr, sympify @@ -224,13 +227,7 @@ def _read_parameter_expression(file_obj): ) from sympy.parsing.sympy_parser import parse_expr - if _optional.HAS_SYMENGINE: - from symengine import sympify - - expr_ = sympify(parse_expr(file_obj.read(data.expr_size).decode(common.ENCODE))) - else: - expr_ = parse_expr(file_obj.read(data.expr_size).decode(common.ENCODE)) - + expr_ = symengine.sympify(parse_expr(file_obj.read(data.expr_size).decode(common.ENCODE))) symbol_map = {} for _ in range(data.map_elements): elem_data = formats.PARAM_EXPR_MAP_ELEM( @@ -264,23 +261,14 @@ def _read_parameter_expression_v3(file_obj, vectors, use_symengine): data = formats.PARAMETER_EXPR( *struct.unpack(formats.PARAMETER_EXPR_PACK, file_obj.read(formats.PARAMETER_EXPR_SIZE)) ) - from sympy.parsing.sympy_parser import parse_expr payload = file_obj.read(data.expr_size) if use_symengine: - _optional.HAS_SYMENGINE.require_now("read_parameter_expression_v3") - from symengine.lib.symengine_wrapper import ( # pylint: disable = no-name-in-module - load_basic, - ) - expr_ = load_basic(payload) else: - if _optional.HAS_SYMENGINE: - from symengine import sympify + from sympy.parsing.sympy_parser import parse_expr - expr_ = sympify(parse_expr(payload.decode(common.ENCODE))) - else: - expr_ = parse_expr(payload.decode(common.ENCODE)) + expr_ = symengine.sympify(parse_expr(payload.decode(common.ENCODE))) symbol_map = {} for _ in range(data.map_elements): diff --git a/qiskit/qpy/interface.py b/qiskit/qpy/interface.py index f4a77ec14598..6de673afbc0f 100644 --- a/qiskit/qpy/interface.py +++ b/qiskit/qpy/interface.py @@ -75,7 +75,7 @@ def dump( programs: Union[List[QPY_SUPPORTED_TYPES], QPY_SUPPORTED_TYPES], file_obj: BinaryIO, metadata_serializer: Optional[Type[JSONEncoder]] = None, - use_symengine: bool = False, + use_symengine: bool = True, ): """Write QPY binary data to a file diff --git a/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml b/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml new file mode 100644 index 000000000000..f52aef82c80c --- /dev/null +++ b/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml @@ -0,0 +1,29 @@ +--- +upgrade: + - | + The ``symengine`` library is now a hard requirement for all platforms. + Previously, ``symengine`` was required only on platforms that had + pre-compiled packages available and ``sympy`` would be used as a fallback + if it wasn't installed. These split requirements were resulting in increased + complexity, as it was necessary to determine which libraries were installed + to debug an issue. Requiring ``symengine`` for all systems greatly decreases + the complexity and optimizes Qiskit for higher performance. However, + users on i686 Linux, 32 bit Windows, and s390x Linux (the platforms without + precompiled packages on PyPI) will need to build symengine from source. + - | + Support for 32 bit platforms, i686 Linux and 32 bit Windows, on + Python < 3.10 has been downgraded from Tier 2 to Tier 3, as documented in + the :ref:`platform_support` page. This is a consequence of making + ``symengine`` required for all users, as there is a lack of pre-compiled packages + available for these platforms, so users will need to build symengine from + source. + - | + For macOS users, the minimum version of macOS is now 10.12. Previously, the + precompiled binary wheel packages for macOS x86_64 were published with + support for >=10.9. However, because of changes in the + `support policy `__ + for the Rust programming language the minimum version needed to raised + to macOS 10.12. If you're using Qiskit on macOS 10.9 you can probably + build Qiskit from source while the Qiskit MSRV (minimum supported Rust + version) is < 1.74, but the precompiled binaries published to PyPI will + only be compatible with macOS >= 10.12. diff --git a/requirements.txt b/requirements.txt index 7ee82582862b..d283f06a2042 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,4 @@ dill>=0.3 python-dateutil>=2.8.0 stevedore>=3.0.0 typing-extensions; python_version<'3.11' -# symengine pinning needed due lowered precision handling complex -# multiplication in version 0.10 wich breaks parameter assignment test -# (can be removed once issue is fix) -symengine>=0.9, <0.10; platform_machine == 'x86_64' or platform_machine == 'aarch64' or platform_machine == 'ppc64le' or platform_machine == 'amd64' or platform_machine == 'arm64' +symengine>=0.9, <0.10 diff --git a/test/python/circuit/test_circuit_load_from_qpy.py b/test/python/circuit/test_circuit_load_from_qpy.py index 4f8523358dbd..5695a298f782 100644 --- a/test/python/circuit/test_circuit_load_from_qpy.py +++ b/test/python/circuit/test_circuit_load_from_qpy.py @@ -55,7 +55,6 @@ from qiskit.quantum_info.random import random_unitary from qiskit.circuit.controlledgate import ControlledGate from qiskit.utils import optionals -from qiskit.exceptions import MissingOptionalLibraryError @ddt.ddt @@ -1747,22 +1746,3 @@ def test_symengine_full_path(self): new_circ = load(qpy_file)[0] self.assertEqual(self.qc, new_circ) self.assertDeprecatedBitProperties(self.qc, new_circ) - - @unittest.skipIf(not optionals.HAS_SYMENGINE, "Install symengine to run this test.") - def test_dump_no_symengine(self): - """Test dump fails if symengine is not installed and use_symengine==True.""" - qpy_file = io.BytesIO() - with optionals.HAS_SYMENGINE.disable_locally(): - with self.assertRaises(MissingOptionalLibraryError): - dump(self.qc, qpy_file, use_symengine=True) - - @unittest.skipIf(not optionals.HAS_SYMENGINE, "Install symengine to run this test.") - def test_load_no_symengine(self): - """Test that load fails if symengine is not installed and the - file was created with use_symengine==True.""" - qpy_file = io.BytesIO() - dump(self.qc, qpy_file, use_symengine=True) - qpy_file.seek(0) - with optionals.HAS_SYMENGINE.disable_locally(): - with self.assertRaises(MissingOptionalLibraryError): - _ = load(qpy_file)[0] diff --git a/test/python/qpy/test_block_load_from_qpy.py b/test/python/qpy/test_block_load_from_qpy.py index 8137ef21a6bb..321e018d5a64 100644 --- a/test/python/qpy/test_block_load_from_qpy.py +++ b/test/python/qpy/test_block_load_from_qpy.py @@ -37,7 +37,6 @@ ) from qiskit.pulse.instructions import Play, TimeBlockade from qiskit.circuit import Parameter, QuantumCircuit, Gate -from qiskit.exceptions import MissingOptionalLibraryError from qiskit.test import QiskitTestCase from qiskit.qpy import dump, load from qiskit.utils import optionals as _optional @@ -460,22 +459,3 @@ def test_symengine_full_path(self): qpy_file.seek(0) new_sched = load(qpy_file)[0] self.assertEqual(self.test_sched, new_sched) - - @unittest.skipIf(not _optional.HAS_SYMENGINE, "Install symengine to run this test.") - def test_dump_no_symengine(self): - """Test dump fails if symengine is not installed and use_symengine==True.""" - qpy_file = io.BytesIO() - with _optional.HAS_SYMENGINE.disable_locally(): - with self.assertRaises(MissingOptionalLibraryError): - dump(self.test_sched, qpy_file, use_symengine=True) - - @unittest.skipIf(not _optional.HAS_SYMENGINE, "Install symengine to run this test.") - def test_load_no_symengine(self): - """Test that load fails if symengine is not installed and the - file was created with use_symengine==True.""" - qpy_file = io.BytesIO() - dump(self.test_sched, qpy_file, use_symengine=True) - qpy_file.seek(0) - with _optional.HAS_SYMENGINE.disable_locally(): - with self.assertRaises(MissingOptionalLibraryError): - _ = load(qpy_file)[0]