Repository: Qiskit/qiskit (python)

Issue:
Add `two_qubit_cnot_decompose` to `qiskit.synthesis` docstring
I think this `two_qubit_cnot_decompose` is missing an `.. autofunction::` in the docstring?  If it's meant to be there, let's take a note to add it after rc1 - no need to hold up the PR over a documentation thing.

_Originally posted by @jakelishman in https://github.com/Qiskit/qiskit/pull/11687#discussion_r1475028459_
            

Pull request:
Additions and fixes to qiskit synthesis docs and release notes
<!--
⚠️ If you do not respect this template, your pull request will be closed.
⚠️ Your pull request title should be short detailed and understandable for all.
⚠️ Also, please add a release note file using reno if the change needs to be
  documented in the release notes.
⚠️ If your pull request fixes an open issue, please link to the issue.

- [ ] I have added the tests to cover my changes.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the CONTRIBUTING document.
-->

### Summary
close #11709 


### Details and comments




Patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index f1d26d808..2e065022d 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -9,3 +9,19 @@ updates:
     directory: "/" # Location of package manifests
     schedule:
       interval: "daily"
+    labels:
+      - "Rust"
+      - "dependencies"
+      - "Changelog: None"
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    groups:
+      GitHub_Actions:
+        patterns:
+          - "*"  # Group all Actions updates into a single larger pull request
+    schedule:
+      interval: weekly
+    labels:
+      - "type: qa"
+      - "dependencies"
+      - "Changelog: None"
diff --git a/Cargo.lock b/Cargo.lock
index b46246630..157c40807 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -810,9 +810,9 @@ dependencies = [
 
 [[package]]
 name = "num-complex"
-version = "0.4.4"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
+checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6"
 dependencies = [
  "bytemuck",
  "num-traits",
@@ -830,9 +830,9 @@ dependencies = [
 
 [[package]]
 name = "num-traits"
-version = "0.2.17"
+version = "0.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
 dependencies = [
  "autocfg 1.1.0",
  "libm",
diff --git a/SECURITY.md b/SECURITY.md
index 68fb4be58..4d7f1ecbd 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -2,7 +2,7 @@
 
 ## Supported Versions
 
-Qiskit (and `qiskit-terra`) supports one minor version release at a time, both for bug and
+Qiskit supports one minor version release at a time, both for bug and
 security fixes. For example, if the most recent release is 0.12.1, then the 0.12.x
 release series is currently supported.
 
@@ -11,7 +11,7 @@ release series is currently supported.
 To report vulnerabilities, you can privately report a potential security issue
 via the Github security vulnerabilities feature. This can be done here:
 
-https://github.com/Qiskit/qiskit-terra/security/advisories
+https://github.com/Qiskit/qiskit/security/advisories
 
 Please do **not** open a public issue about a potential security vulnerability.
 
diff --git a/asv.conf.json b/asv.conf.json
index 0dcff7ef5..70dd3b760 100644
--- a/asv.conf.json
+++ b/asv.conf.json
@@ -4,7 +4,7 @@
     "project_url": "https://qiskit.org",
     "repo": ".",
     "install_command": [
-        "in-dir={env_dir} python -m pip install {wheel_file}[all] python-constraint"
+        "in-dir={env_dir} python -m pip install {wheel_file}[csp-layout-pass]"
       ],
     "uninstall_command": [
         "return-code=any python -m pip uninstall -y qiskit qiskit-terra"
diff --git a/qiskit/compiler/transpiler.py b/qiskit/compiler/transpiler.py
index eaed6744f..dd6758acc 100644
--- a/qiskit/compiler/transpiler.py
+++ b/qiskit/compiler/transpiler.py
@@ -232,7 +232,7 @@ def transpile(  # pylint: disable=too-many-return-statements
             default this setting will have no effect as the default unitary
             synthesis method does not take custom configuration. This should
             only be necessary when a unitary synthesis plugin is specified with
-            the ``unitary_synthesis`` argument. As this is custom for each
+            the ``unitary_synthesis_method`` argument. As this is custom for each
             unitary synthesis plugin refer to the plugin documentation for how
             to use this option.
         target: A backend transpiler target. Normally this is specified as part of
diff --git a/qiskit/primitives/containers/primitive_result.py b/qiskit/primitives/containers/primitive_result.py
index b383f4e11..f154519df 100644
--- a/qiskit/primitives/containers/primitive_result.py
+++ b/qiskit/primitives/containers/primitive_result.py
@@ -29,7 +29,8 @@ class PrimitiveResult(Generic[T]):
         """
         Args:
             pub_results: Pub results.
-            metadata: Any metadata that doesn't make sense to put inside of pub results.
+            metadata: Metadata that is common to all pub results; metadata specific to particular
+                pubs should be placed in their metadata fields. Keys are expected to be strings.
         """
         self._pub_results = list(pub_results)
         self._metadata = metadata or {}
diff --git a/qiskit/primitives/containers/pub_result.py b/qiskit/primitives/containers/pub_result.py
index 07f99ef0b..369179e46 100644
--- a/qiskit/primitives/containers/pub_result.py
+++ b/qiskit/primitives/containers/pub_result.py
@@ -16,6 +16,8 @@ Base Pub class
 
 from __future__ import annotations
 
+from typing import Any
+
 from .data_bin import DataBin
 
 
@@ -24,19 +26,19 @@ class PubResult:
 
     __slots__ = ("_data", "_metadata")
 
-    def __init__(self, data: DataBin, metadata: dict | None = None):
+    def __init__(self, data: DataBin, metadata: dict[str, Any] | None = None):
         """Initialize a pub result.
 
         Args:
-            data: result data bin.
-            metadata: metadata dictionary.
+            data: Result data.
+            metadata: Metadata specific to this pub. Keys are expected to be strings.
         """
         self._data = data
         self._metadata = metadata or {}
 
     def __repr__(self):
         metadata = f", metadata={self.metadata}" if self.metadata else ""
-        return f"{type(self).__name__}({self._data}{metadata})"
+        return f"{type(self).__name__}(data={self._data}{metadata})"
 
     @property
     def data(self) -> DataBin:
diff --git a/qiskit/qpy/type_keys.py b/qiskit/qpy/type_keys.py
index 506963dbd..dd0e7fe22 100644
--- a/qiskit/qpy/type_keys.py
+++ b/qiskit/qpy/type_keys.py
@@ -541,7 +541,7 @@ class SymExprEncoding(TypeKeyBase):
 
     @classmethod
     def assign(cls, obj):
-        if obj is True:
+        if obj:
             return cls.SYMENGINE
         else:
             return cls.SYMPY
diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py
index 29adb1b3e..90d40b93c 100644
--- a/qiskit/quantum_info/operators/operator.py
+++ b/qiskit/quantum_info/operators/operator.py
@@ -21,7 +21,6 @@ import re
 from numbers import Number
 from typing import TYPE_CHECKING
 
-import scipy.linalg
 import numpy as np
 
 from qiskit.circuit.instruction import Instruction
@@ -528,6 +527,8 @@ class Operator(LinearOp):
         if isinstance(n, int):
             ret._data = np.linalg.matrix_power(self.data, n)
         else:
+            import scipy.linalg
+
             # Experimentally, for fractional powers this seems to be 3x faster than
             # calling scipy.linalg.fractional_matrix_power(self.data, n)
             decomposition, unitary = scipy.linalg.schur(self.data, output="complex")
diff --git a/qiskit/synthesis/__init__.py b/qiskit/synthesis/__init__.py
index 92b466d22..a22c967bc 100644
--- a/qiskit/synthesis/__init__.py
+++ b/qiskit/synthesis/__init__.py
@@ -118,6 +118,8 @@ Two-Qubit Synthesis
    XXDecomposer
    TwoQubitWeylDecomposition
 
+.. autofunction:: two_qubit_cnot_decompose
+
 """
 
 from .evolution import (
diff --git a/qiskit/synthesis/two_qubit/two_qubit_decompose.py b/qiskit/synthesis/two_qubit/two_qubit_decompose.py
index 5ae445606..bd67fc901 100644
--- a/qiskit/synthesis/two_qubit/two_qubit_decompose.py
+++ b/qiskit/synthesis/two_qubit/two_qubit_decompose.py
@@ -98,7 +98,7 @@ class TwoQubitWeylDecomposition:
 
     .. math::
 
-        U = ({K_1}^l \otimes {K_1}^r) \dot e^{(i a XX + i b YY + i c ZZ)} \dot ({K_2}^l \otimes {K_2}^r)
+        U = ({K_1}^l \otimes {K_1}^r) e^{(i a XX + i b YY + i c ZZ)} ({K_2}^l \otimes {K_2}^r)
 
     where
 
@@ -121,10 +121,15 @@ class TwoQubitWeylDecomposition:
     Passing non-None fidelity to specializations is treated as an assertion, raising QiskitError if
     forcing the specialization is more approximate than asserted.
 
-    Reference:
+    References:
         1. Cross, A. W., Bishop, L. S., Sheldon, S., Nation, P. D. & Gambetta, J. M.,
            *Validating quantum computers using randomized model circuits*,
            `arXiv:1811.12926 [quant-ph] <https://arxiv.org/abs/1811.12926>`_
+        2. B. Kraus, J. I. Cirac, *Optimal Creation of Entanglement Using a Two-Qubit Gate*,
+           `arXiv:0011050 [quant-ph] <https://arxiv.org/abs/quant-ph/0011050>`_
+        3. B. Drury, P. J. Love, *Constructive Quantum Shannon Decomposition from Cartan
+           Involutions*, `arXiv:0806.4015 [quant-ph] <https://arxiv.org/abs/0806.4015>`_
+
     """
 
     # The parameters of the decomposition:
@@ -157,17 +162,17 @@ class TwoQubitWeylDecomposition:
 
     @staticmethod
     def __new__(cls, unitary_matrix, *, fidelity=(1.0 - 1.0e-9), _unpickling=False):
-        """Perform the Weyl chamber decomposition, and optionally choose a specialized subclass.
-
-        The flip into the Weyl Chamber is described in B. Kraus and J. I. Cirac, Phys. Rev. A 63,
-        062309 (2001).
+        """Perform the Weyl chamber decomposition, and optionally choose a specialized subclass."""
 
-        FIXME: There's a cleaner-seeming method based on choosing branch cuts carefully, in Andrew
-        M. Childs, Henry L. Haselgrove, and Michael A. Nielsen, Phys. Rev. A 68, 052311, but I
-        wasn't able to get that to work.
+        # The flip into the Weyl Chamber is described in B. Kraus and J. I. Cirac, Phys. Rev. A 63,
+        # 062309 (2001).
+        #
+        # FIXME: There's a cleaner-seeming method based on choosing branch cuts carefully, in Andrew
+        # M. Childs, Henry L. Haselgrove, and Michael A. Nielsen, Phys. Rev. A 68, 052311, but I
+        # wasn't able to get that to work.
+        #
+        # The overall decomposition scheme is taken from Drury and Love, arXiv:0806.4015 [quant-ph].
 
-        The overall decomposition scheme is taken from Drury and Love, arXiv:0806.4015 [quant-ph].
-        """
         if _unpickling:
             return super().__new__(cls)
 
@@ -384,19 +389,19 @@ class TwoQubitWeylDecomposition:
             )
 
     def specialize(self):
-        """Make changes to the decomposition to comply with any specialization.
+        """Make changes to the decomposition to comply with any specialization."""
 
-        Do update a, b, c, k1l, k1r, k2l, k2r, _is_flipped_from_original to round to the
-        specialization. Do not update the global phase, since this gets done in generic
-        __init__()"""
+        # Do update a, b, c, k1l, k1r, k2l, k2r, _is_flipped_from_original to round to the
+        # specialization. Do not update the global phase, since this gets done in generic
+        # __init__()
         raise NotImplementedError
 
     def circuit(
         self, *, euler_basis: str | None = None, simplify=False, atol=DEFAULT_ATOL
     ) -> QuantumCircuit:
-        """Returns Weyl decomposition in circuit form.
+        """Returns Weyl decomposition in circuit form."""
 
-        simplify, atol arguments are passed to OneQubitEulerDecomposer"""
+        # simplify, atol arguments are passed to OneQubitEulerDecomposer
         if euler_basis is None:
             euler_basis = self._default_1q_basis
         oneq_decompose = OneQubitEulerDecomposer(euler_basis)
@@ -424,7 +429,7 @@ class TwoQubitWeylDecomposition:
             circ.rzz(-self.c * 2, 0, 1)
 
     def actual_fidelity(self, **kwargs) -> float:
-        """Calculates the actual fidelity of the decomposed circuit to the input unitary"""
+        """Calculates the actual fidelity of the decomposed circuit to the input unitary."""
         circ = self.circuit(**kwargs)
         trace = np.trace(Operator(circ).data.T.conj() @ self.unitary_matrix)
         return trace_to_fid(trace)
@@ -459,7 +464,8 @@ class TwoQubitWeylDecomposition:
     def from_bytes(
         cls, bytes_in: bytes, *, requested_fidelity: float, **kwargs
     ) -> "TwoQubitWeylDecomposition":
-        """Decode bytes into TwoQubitWeylDecomposition. Used by __repr__"""
+        """Decode bytes into :class:`.TwoQubitWeylDecomposition`."""
+        # Used by __repr__
         del kwargs  # Unused (just for display)
         b64 = base64.decodebytes(bytes_in)
         with io.BytesIO(b64) as f:
@@ -854,7 +860,7 @@ def Ud(a, b, c):
 
 
 def trace_to_fid(trace):
-    """Average gate fidelity is :math:`Fbar = (d + |Tr (Utarget \\cdot U^dag)|^2) / d(d+1)`
+    r"""Average gate fidelity is :math:`Fbar = (d + |Tr (U_{target} \cdot U^{\dag})|^2) / d(d+1)`
     M. Horodecki, P. Horodecki and R. Horodecki, PRA 60, 1888 (1999)"""
     return (4 + abs(trace) ** 2) / 20
 
@@ -1018,8 +1024,10 @@ class TwoQubitBasisDecomposer:
         self._rqc = None
 
     def traces(self, target):
-        """Give the expected traces :math:`|Tr(U \\cdot Utarget^dag)|` for different number of
-        basis gates."""
+        r"""
+        Give the expected traces :math:`|Tr(U \cdot U_{target}^{\dag})|` for different number of
+        basis gates.
+        """
         # Future gotcha: extending this to non-supercontrolled basis.
         # Careful: closest distance between a1,b1,c1 and a2,b2,c2 may be between reflections.
         # This doesn't come up if either c1==0 or c2==0 but otherwise be careful.
@@ -1042,21 +1050,29 @@ class TwoQubitBasisDecomposer:
 
     @staticmethod
     def decomp0(target):
-        """Decompose target ~Ud(x, y, z) with 0 uses of the basis gate.
-        Result Ur has trace:
-        :math:`|Tr(Ur.Utarget^dag)| = 4|(cos(x)cos(y)cos(z)+ j sin(x)sin(y)sin(z)|`,
-        which is optimal for all targets and bases"""
+        r"""
+        Decompose target :math:`~Ud(x, y, z)` with 0 uses of the basis gate.
+        Result :math:`Ur` has trace:
+
+        .. math::
+
+            |Tr(Ur.U_{target}^{\dag})| = 4|(cos(x)cos(y)cos(z)+ j sin(x)sin(y)sin(z)|
+
+        which is optimal for all targets and bases
+        """
 
         U0l = target.K1l.dot(target.K2l)
         U0r = target.K1r.dot(target.K2r)
         return U0r, U0l
 
     def decomp1(self, target):
-        """Decompose target ~Ud(x, y, z) with 1 uses of the basis gate ~Ud(a, b, c).
-        Result Ur has trace:
+        r"""
+        Decompose target :math:`~Ud(x, y, z)` with 1 uses of the basis gate :math:`~Ud(a, b, c)`.
+        Result :math:`Ur` has trace:
+
         .. math::
 
-            |Tr(Ur.Utarget^dag)| = 4|cos(x-a)cos(y-b)cos(z-c) + j sin(x-a)sin(y-b)sin(z-c)|
+            |Tr(Ur.U_{target}^{\dag})| = 4|cos(x-a)cos(y-b)cos(z-c) + j sin(x-a)sin(y-b)sin(z-c)|
 
         which is optimal for all targets and bases with z==0 or c==0"""
         # FIXME: fix for z!=0 and c!=0 using closest reflection (not always in the Weyl chamber)
@@ -1068,18 +1084,20 @@ class TwoQubitBasisDecomposer:
         return U1r, U1l, U0r, U0l
 
     def decomp2_supercontrolled(self, target):
-        """Decompose target ~Ud(x, y, z) with 2 uses of the basis gate.
+        r"""
+        Decompose target :math:`~Ud(x, y, z)` with 2 uses of the basis gate.
+
+        For supercontrolled basis :math:`~Ud(\pi/4, b, 0)`, all b, result :math:`Ur` has trace
 
-        For supercontrolled basis ~Ud(pi/4, b, 0), all b, result Ur has trace
         .. math::
 
-            |Tr(Ur.Utarget^dag)| = 4cos(z)
+            |Tr(Ur.U_{target}^{\dag})| = 4cos(z)
 
-        which is the optimal approximation for basis of CNOT-class ``~Ud(pi/4, 0, 0)``
-        or DCNOT-class ``~Ud(pi/4, pi/4, 0)`` and any target.
+        which is the optimal approximation for basis of CNOT-class :math:`~Ud(\pi/4, 0, 0)`
+        or DCNOT-class :math:`~Ud(\pi/4, \pi/4, 0)` and any target.
         May be sub-optimal for b!=0 (e.g. there exists exact decomposition for any target using B
-        ``B~Ud(pi/4, pi/8, 0)``, but not this decomposition.)
-        This is an exact decomposition for supercontrolled basis and target ``~Ud(x, y, 0)``.
+        :math:`B \sim Ud(\pi/4, \pi/8, 0)`, but not this decomposition.)
+        This is an exact decomposition for supercontrolled basis and target :math:`~Ud(x, y, 0)`.
         No guarantees for non-supercontrolled basis.
         """
 
@@ -1093,9 +1111,11 @@ class TwoQubitBasisDecomposer:
         return U2r, U2l, U1r, U1l, U0r, U0l
 
     def decomp3_supercontrolled(self, target):
-        """Decompose target with 3 uses of the basis.
-        This is an exact decomposition for supercontrolled basis ~Ud(pi/4, b, 0), all b,
-        and any target. No guarantees for non-supercontrolled basis."""
+        r"""
+        Decompose target with 3 uses of the basis.
+        This is an exact decomposition for supercontrolled basis :math:`~Ud(\pi/4, b, 0)`, all b,
+        and any target. No guarantees for non-supercontrolled basis.
+        """
 
         U0l = target.K1l.dot(self.u0l)
         U0r = target.K1r.dot(self.u0r)
@@ -1572,3 +1592,16 @@ class _LazyTwoQubitCXDecomposer(TwoQubitBasisDecomposer):
 
 
 two_qubit_cnot_decompose = _LazyTwoQubitCXDecomposer()
+"""
+This is an instance of :class:`.TwoQubitBasisDecomposer` that always uses
+``cx`` as the KAK gate for the basis decomposition. You can use this function
+as a quick access to ``cx``-based 2-qubit decompositions.
+
+Args:
+    unitary (Operator or np.ndarray): The 4x4 unitary to synthesize.
+    basis_fidelity (float or None): If given the assumed fidelity for applications of :class:`.CXGate`.
+    approximate (bool): If ``True`` approximate if ``basis_fidelity`` is less than 1.0.
+
+Returns:
+    QuantumCircuit: The synthesized circuit of the input unitary.
+"""
diff --git a/qiskit/synthesis/unitary/aqc/aqc.py b/qiskit/synthesis/unitary/aqc/aqc.py
index 4ced39a7e..37dea933f 100644
--- a/qiskit/synthesis/unitary/aqc/aqc.py
+++ b/qiskit/synthesis/unitary/aqc/aqc.py
@@ -12,18 +12,21 @@
 """A generic implementation of Approximate Quantum Compiler."""
 from __future__ import annotations
 
+import typing
 from functools import partial
 
 from collections.abc import Callable
 from typing import Protocol
 
 import numpy as np
-from scipy.optimize import OptimizeResult, minimize
 
 from qiskit.quantum_info import Operator
 
 from .approximate import ApproximateCircuit, ApproximatingObjective
 
+if typing.TYPE_CHECKING:
+    import scipy.optimize
+
 
 class Minimizer(Protocol):
     """Callable Protocol for minimizer.
@@ -52,7 +55,7 @@ class Minimizer(Protocol):
         x0: np.ndarray,  # pylint: disable=invalid-name
         jac: Callable[[np.ndarray], np.ndarray] | None = None,
         bounds: list[tuple[float, float]] | None = None,
-    ) -> OptimizeResult:
+    ) -> scipy.optimize.OptimizeResult:
         """Minimize the objective function.
 
         This interface is based on `SciPy's optimize module <https://docs.scipy.org/doc
@@ -112,9 +115,11 @@ class AQC:
                 ``L-BFGS-B`` method is used with max iterations set to 1000.
             seed: a seed value to be used by a random number generator.
         """
+        import scipy.optimize
+
         super().__init__()
         self._optimizer = optimizer or partial(
-            minimize, args=(), method="L-BFGS-B", options={"maxiter": 1000}
+            scipy.optimize.minimize, args=(), method="L-BFGS-B", options={"maxiter": 1000}
         )
 
         self._seed = seed
diff --git a/qiskit/transpiler/passes/basis/basis_translator.py b/qiskit/transpiler/passes/basis/basis_translator.py
index 74e564ccd..f004fb2e5 100644
--- a/qiskit/transpiler/passes/basis/basis_translator.py
+++ b/qiskit/transpiler/passes/basis/basis_translator.py
@@ -158,6 +158,11 @@ class BasisTranslator(TransformationPass):
             source_basis, qargs_local_source_basis = self._extract_basis_target(dag, qarg_indices)
 
         target_basis = set(target_basis).union(basic_instrs)
+        # If the source basis is a subset of the target basis and we have no circuit
+        # instructions on qargs that have non-global operations there is nothing to
+        # translate and we can exit early.
+        if source_basis.issubset(target_basis) and not qargs_local_source_basis:
+            return dag
 
         logger.info(
             "Begin BasisTranslator from source basis %s to target basis %s.",
diff --git a/qiskit/transpiler/preset_passmanagers/__init__.py b/qiskit/transpiler/preset_passmanagers/__init__.py
index 6a8dab2ba..f19b82fb3 100644
--- a/qiskit/transpiler/preset_passmanagers/__init__.py
+++ b/qiskit/transpiler/preset_passmanagers/__init__.py
@@ -179,7 +179,7 @@ def generate_preset_pass_manager(
             default this setting will have no effect as the default unitary
             synthesis method does not take custom configuration. This should
             only be necessary when a unitary synthesis plugin is specified with
-            the ``unitary_synthesis`` argument. As this is custom for each
+            the ``unitary_synthesis_method`` argument. As this is custom for each
             unitary synthesis plugin refer to the plugin documentation for how
             to use this option.
         hls_config (HLSConfig): An optional configuration class :class:`~.HLSConfig`
diff --git a/qiskit/utils/parallel.py b/qiskit/utils/parallel.py
index 3b3d9638b..d46036a47 100644
--- a/qiskit/utils/parallel.py
+++ b/qiskit/utils/parallel.py
@@ -1,6 +1,6 @@
 # This code is part of Qiskit.
 #
-# (C) Copyright IBM 2017, 2018.
+# (C) Copyright IBM 2017, 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
@@ -129,11 +129,6 @@ def parallel_map(  # pylint: disable=dangerous-default-value
     Raises:
         QiskitError: If user interrupts via keyboard.
 
-    Events:
-        terra.parallel.start: The collection of parallel tasks are about to start.
-        terra.parallel.update: One of the parallel task has finished.
-        terra.parallel.finish: All the parallel tasks have finished.
-
     Examples:
 
         .. code-block:: python
diff --git a/releasenotes/notes/fix-qpy-use-symengine-bool-like-d17550057a58abf2.yaml b/releasenotes/notes/fix-qpy-use-symengine-bool-like-d17550057a58abf2.yaml
new file mode 100644
index 000000000..ae966ecfa
--- /dev/null
+++ b/releasenotes/notes/fix-qpy-use-symengine-bool-like-d17550057a58abf2.yaml
@@ -0,0 +1,9 @@
+---
+fixes:
+  - |
+    Fixed an issue with the :func:`.qpy.dump` function, when the
+    ``use_symengine`` flag was set to a truthy object that evaluated to
+    ``True`` but was not actually the boolean ``True`` the generated QPY
+    payload would be corrupt. For example, if you set ``use_symengine`` to
+    :obj:`.HAS_SYMENGINE` which evaluates to ``True`` when cast as a bool,
+    but isn't actually ``True``.
diff --git a/releasenotes/notes/remove_qinfo_synthesis-1917c7ccfcc62180.yaml b/releasenotes/notes/remove_qinfo_synthesis-1917c7ccfcc62180.yaml
index bd335e7fb..30d0a6476 100644
--- a/releasenotes/notes/remove_qinfo_synthesis-1917c7ccfcc62180.yaml
+++ b/releasenotes/notes/remove_qinfo_synthesis-1917c7ccfcc62180.yaml
@@ -1,4 +1,9 @@
 ---
+features:
+  - |
+    A new class, :class:`~.TwoQubitWeylDecomposition`, has been added to :mod:`qiskit.synthesis`.
+    This class allows to apply the Weyl decomposition of two-qubit unitaries.
+
 upgrade:
   - |
     Removed the ``qiskit.quantum_info.synthesis`` module, which has been deprecated since the 0.46 release.
@@ -11,3 +16,7 @@ upgrade:
 
     This function was removed, since it has already been deprecated in the 0.46 release:
     * ``cnot_rxx_decompose``
+
+    These functions were removed, since they have already been deprecated in a previous release:
+    * ``decompose_clifford`` (use :func:`.qiskit.synthesis.synth_clifford_full` instead)
+    * ``decompose_cnotdihedral`` (use :func:`.qiskit.synthesis.synth_cnotdihedral_full` instead)
diff --git a/requirements-dev.txt b/requirements-dev.txt
index 393925b6f..f590c7c60 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -39,5 +39,5 @@ ddt>=1.2.0,!=1.4.0,!=1.4.3
 # consume it properly.
 Sphinx>=6.0,<7.2
 # TODO: switch to stable release when 4.1 is released
-reno @ git+https://github.com/openstack/reno.git@81587f616f17904336cdc431e25c42b46cd75b8f
+reno @ git+https://github.com/openstack/reno.git@85b9a9bb52c8f9ce4a5e66fa8d9eba7fde90bf6d
 sphinxcontrib-katex==0.9.9
diff --git a/tools/find_optional_imports.py b/tools/find_optional_imports.py
index 1a7e0862e..58062cdfa 100755
--- a/tools/find_optional_imports.py
+++ b/tools/find_optional_imports.py
@@ -27,6 +27,8 @@ def _main():
         "pydot",
         "pygments",
         "ipywidgets",
+        "scipy.linalg",
+        "scipy.optimize",
         "scipy.stats",
         "matplotlib",
         "qiskit_aer",
diff --git a/tox.ini b/tox.ini
index 19c76214c..6d0f79717 100644
--- a/tox.ini
+++ b/tox.ini
@@ -42,7 +42,7 @@ commands =
   python {toxinidir}/tools/verify_headers.py qiskit test tools examples
   python {toxinidir}/tools/find_optional_imports.py
   python {toxinidir}/tools/find_stray_release_notes.py
-  reno lint
+  reno -q lint
 
 [testenv:lint-incr]
 basepython = python3
@@ -56,7 +56,7 @@ commands =
   python {toxinidir}/tools/verify_headers.py qiskit test tools examples
   python {toxinidir}/tools/find_optional_imports.py
   python {toxinidir}/tools/find_stray_release_notes.py
-  reno lint
+  reno -q lint
 
 [testenv:black]
 skip_install = true


Test patch:
diff --git a/test/python/primitives/containers/test_primitive_result.py b/test/python/primitives/containers/test_primitive_result.py
index 79200d2cb..93e563379 100644
--- a/test/python/primitives/containers/test_primitive_result.py
+++ b/test/python/primitives/containers/test_primitive_result.py
@@ -36,9 +36,10 @@ class PrimitiveResultCase(QiskitTestCase):
             PubResult(data_bin_cls(alpha, beta)),
             PubResult(data_bin_cls(alpha, beta)),
         ]
-        result = PrimitiveResult(pub_results, {1: 2})
+        result = PrimitiveResult(pub_results, {"x": 2})
 
         self.assertTrue(result[0] is pub_results[0])
         self.assertTrue(result[1] is pub_results[1])
         self.assertTrue(list(result)[0] is pub_results[0])
         self.assertEqual(len(result), 2)
+        self.assertEqual(result.metadata, {"x": 2})
diff --git a/test/python/qpy/test_circuit_load_from_qpy.py b/test/python/qpy/test_circuit_load_from_qpy.py
index 696e39051..a050a70ca 100644
--- a/test/python/qpy/test_circuit_load_from_qpy.py
+++ b/test/python/qpy/test_circuit_load_from_qpy.py
@@ -25,16 +25,21 @@ from qiskit.qpy.common import QPY_VERSION
 from qiskit.transpiler import PassManager, TranspileLayout
 from qiskit.transpiler import passes
 from qiskit.compiler import transpile
+from qiskit.utils import optionals
+from qiskit.qpy.formats import FILE_HEADER_V10_PACK, FILE_HEADER_V10, FILE_HEADER_V10_SIZE
 from test import QiskitTestCase  # pylint: disable=wrong-import-order
 
 
 class QpyCircuitTestCase(QiskitTestCase):
     """QPY schedule testing platform."""
 
-    def assert_roundtrip_equal(self, circuit, version=None):
+    def assert_roundtrip_equal(self, circuit, version=None, use_symengine=None):
         """QPY roundtrip equal test."""
         qpy_file = io.BytesIO()
-        dump(circuit, qpy_file, version=version)
+        if use_symengine is None:
+            dump(circuit, qpy_file, version=version)
+        else:
+            dump(circuit, qpy_file, version=version, use_symengine=use_symengine)
         qpy_file.seek(0)
         new_circuit = load(qpy_file)[0]
 
@@ -296,3 +301,29 @@ class TestVersionArg(QpyCircuitTestCase):
         qc.cx(0, 1)
         qc.measure_all()
         self.assert_roundtrip_equal(qc, version=QPY_COMPATIBILITY_VERSION)
+
+
+class TestUseSymengineFlag(QpyCircuitTestCase):
+    """Test that the symengine flag works correctly."""
+
+    def test_use_symengine_with_bool_like(self):
+        """Test that the use_symengine flag is set correctly with a bool-like input."""
+        theta = Parameter("theta")
+        two_theta = 2 * theta
+        qc = QuantumCircuit(1)
+        qc.rx(two_theta, 0)
+        qc.measure_all()
+        # Assert Roundtrip works
+        self.assert_roundtrip_equal(qc, use_symengine=optionals.HAS_SYMENGINE, version=10)
+        # Also check the qpy symbolic expression encoding is correct in the
+        # payload
+        with io.BytesIO() as file_obj:
+            dump(qc, file_obj, use_symengine=optionals.HAS_SYMENGINE)
+            file_obj.seek(0)
+            header_data = FILE_HEADER_V10._make(
+                struct.unpack(
+                    FILE_HEADER_V10_PACK,
+                    file_obj.read(FILE_HEADER_V10_SIZE),
+                )
+            )
+            self.assertEqual(header_data.symbolic_encoding, b"e")