From 9a1d01b52ce8143c47fd6150a38f430aa8b68e9a Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 26 Sep 2023 13:58:40 -0400 Subject: [PATCH 1/4] 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). --- docs/getting_started.rst | 10 +- pyproject.toml | 3 +- qiskit/circuit/parameter.py | 27 +-- qiskit/circuit/parameterexpression.py | 160 ++++-------------- qiskit/pulse/library/symbolic_pulses.py | 58 +++---- qiskit/qpy/binary_io/schedules.py | 13 +- qiskit/qpy/binary_io/value.py | 16 +- .../platform-support-f7f693aaf5dec044.yaml | 28 +++ requirements.txt | 5 +- 9 files changed, 100 insertions(+), 220 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 3e347b0beac1..7f73a325fdc8 100644 --- a/qiskit/circuit/parameter.py +++ b/qiskit/circuit/parameter.py @@ -15,8 +15,9 @@ from uuid import uuid4 +import symengine + from qiskit.circuit.exceptions import CircuitError -from qiskit.utils import optionals as _optionals from .parameterexpression import ParameterExpression @@ -80,14 +81,7 @@ def __init__(self, name: str): be any unicode string, e.g. "ϕ". """ self._name = name - if not _optionals.HAS_SYMENGINE: - from sympy import Symbol - - symbol = Symbol(name) - else: - import symengine - - symbol = symengine.Symbol(name) + symbol = symengine.Symbol(name) super().__init__(symbol_map={self: symbol}, expr=symbol) def assign(self, parameter, value): @@ -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``.""" @@ -152,12 +142,5 @@ def __getstate__(self): def __setstate__(self, state): self._name = state["name"] - if not _optionals.HAS_SYMENGINE: - from sympy import Symbol - - symbol = Symbol(self._name) - else: - import symengine - - symbol = symengine.Symbol(self._name) + symbol = symengine.Symbol(self._name) super().__init__(symbol_map={self: symbol}, expr=symbol) diff --git a/qiskit/circuit/parameterexpression.py b/qiskit/circuit/parameterexpression.py index 71b9fb7761a5..23fc436015f3 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 @@ -66,14 +66,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": @@ -183,15 +178,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. @@ -304,15 +291,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. @@ -365,102 +344,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)})" @@ -492,24 +408,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 ({}) " @@ -528,14 +441,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""" @@ -553,12 +459,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 @@ -568,7 +471,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 @@ -579,9 +482,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 8c90777eae01..28d28fcd8edb 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 e4fd7363a4d4..98b617081ddb 100644 --- a/qiskit/qpy/binary_io/schedules.py +++ b/qiskit/qpy/binary_io/schedules.py @@ -19,6 +19,7 @@ from io import BytesIO import numpy as np +import symengine as sym from qiskit.exceptions import QiskitError from qiskit.pulse import library, channels, instructions @@ -26,14 +27,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) @@ -112,11 +107,7 @@ def _loads_symbolic_expr(expr_bytes): expr_txt = zlib.decompress(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): diff --git a/qiskit/qpy/binary_io/value.py b/qiskit/qpy/binary_io/value.py index 2edac6c81b52..04828bf1dd86 100644 --- a/qiskit/qpy/binary_io/value.py +++ b/qiskit/qpy/binary_io/value.py @@ -19,6 +19,7 @@ import uuid import numpy as np +import symengine from qiskit.circuit import CASE_DEFAULT, Clbit, ClassicalRegister from qiskit.circuit.classical import expr, types @@ -26,7 +27,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): @@ -224,12 +224,7 @@ def _read_parameter_expression(file_obj): ) from sympy.parsing.sympy_parser import parse_expr - if _optional.HAS_SYMENGINE: - import symengine - - expr_ = symengine.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( @@ -265,12 +260,7 @@ def _read_parameter_expression_v3(file_obj, vectors): ) from sympy.parsing.sympy_parser import parse_expr - if _optional.HAS_SYMENGINE: - import symengine - - expr_ = symengine.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_V3( diff --git a/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml b/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml new file mode 100644 index 000000000000..2f31d26035a4 --- /dev/null +++ b/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml @@ -0,0 +1,28 @@ +--- +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. This split requirements was resulting in increased + complexity as it was necessary to determine which libraries were installed + to debug an issue. By requiring symengine for all systems greatly decreases + the complexity and optimizes Qiskit for higher performance. However, for + 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 was required due to making + ``symengine`` required for all users and needing to install symengine from + source on these platforms. + - | + For macOS 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 d41eee50ce95..7620b00ee3ec 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,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 From 4bdcc20f530ea3e2d0061da3701eaaf5a84e618b Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 16 Nov 2023 17:47:30 -0500 Subject: [PATCH 2/4] Fix use_symengine ScheduleBlock --- qiskit/qpy/binary_io/schedules.py | 7 ++++--- releasenotes/notes/platform-support-f7f693aaf5dec044.yaml | 6 ++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/qiskit/qpy/binary_io/schedules.py b/qiskit/qpy/binary_io/schedules.py index b0615a3ce966..ce22702c89da 100644 --- a/qiskit/qpy/binary_io/schedules.py +++ b/qiskit/qpy/binary_io/schedules.py @@ -104,12 +104,13 @@ 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: - return 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) return sym.sympify(expr) @@ -472,7 +473,7 @@ def _dumps_operand(operand, use_symengine): def _write_element(file_obj, element, metadata_serializer, use_symengine): if isinstance(element, ScheduleBlock): common.write_type_key(file_obj, type_keys.Program.SCHEDULE_BLOCK) - write_schedule_block(file_obj, element, metadata_serializer) + write_schedule_block(file_obj, element, metadata_serializer, use_symengine) else: type_key = type_keys.ScheduleInstruction.assign(element) common.write_type_key(file_obj, type_key) diff --git a/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml b/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml index 2f31d26035a4..9894895e8467 100644 --- a/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml +++ b/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml @@ -26,3 +26,9 @@ upgrade: 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. + +fixes: + - | + Fixed an issue with :class:`.qpy.dump` which would cause the function to + potentially ignore the value of ``use_symengine`` when serializing a + :class:`.ScheduleBlock` object. From 36988cc6df1446218c1190844db4d665d93f38fb Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 20 Nov 2023 14:04:30 -0500 Subject: [PATCH 3/4] Remove duplicated release note --- releasenotes/notes/platform-support-f7f693aaf5dec044.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml b/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml index 9894895e8467..2f31d26035a4 100644 --- a/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml +++ b/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml @@ -26,9 +26,3 @@ upgrade: 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. - -fixes: - - | - Fixed an issue with :class:`.qpy.dump` which would cause the function to - potentially ignore the value of ``use_symengine`` when serializing a - :class:`.ScheduleBlock` object. From a7a6ceadfefdc75951e758e1538cb51d20edae04 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 21 Nov 2023 08:19:06 -0500 Subject: [PATCH 4/4] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- .../platform-support-f7f693aaf5dec044.yaml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml b/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml index 2f31d26035a4..f52aef82c80c 100644 --- a/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml +++ b/releasenotes/notes/platform-support-f7f693aaf5dec044.yaml @@ -4,20 +4,21 @@ 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. This split requirements was resulting in increased - complexity as it was necessary to determine which libraries were installed - to debug an issue. By requiring symengine for all systems greatly decreases - the complexity and optimizes Qiskit for higher performance. However, for + 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 was required due to making - ``symengine`` required for all users and needing to install symengine from - source on these platforms. + 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 the minimum version of macOS is now 10.12. Previously, the + 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 `__