Repository: Qiskit/qiskit

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_
            


Discussion:
I wasn't sure what to do with this function, since it has no docstring, and also due to the comment here: 
https://github.com/Qiskit/qiskit/blob/a234ff2dc717884fa9b1c3dce3e3d8c4c3eccbfb/qiskit/synthesis/two_qubit/two_qubit_decompose.py#L1531

Resolving patch:
diff --git a/qiskit/synthesis/__init__.py b/qiskit/synthesis/__init__.py
--- a/qiskit/synthesis/__init__.py
+++ b/qiskit/synthesis/__init__.py
@@ -118,6 +118,8 @@
    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
--- 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 @@ def __init_subclass__(cls, **kwargs):
 
     @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 @@ def __init__(self, unitary_matrix, fidelity=None):
             )
 
     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 @@ def _weyl_gate(self, simplify, circ: QuantumCircuit, atol):
             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 @@ def __repr__(self):
     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 @@ def __init__(
         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 @@ def traces(self, target):
 
     @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 @@ def decomp1(self, target):
         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 @@ def decomp2_supercontrolled(self, target):
         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 @@ def num_basis_gates(self, unitary):
 
 
 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.
+"""


Test patch: