Source code for qiskit_qryd_provider.pcp_gate

from cmath import exp
from typing import List
from typing import TYPE_CHECKING

from qiskit.circuit import Gate
from qiskit.circuit import Parameter
from qiskit.circuit import QuantumCircuit
from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary
from qiskit.circuit.library import CPhaseGate
from qiskit.quantum_info import Kraus

if TYPE_CHECKING:
    import qiskit


[docs]class PCPGate(Gate): r"""Implements the phase-shifted controlled-phase gate (PCP). This class implements an idealized version of a controlled-phase gate as it can potentially be realized by the Rydberg platform. Similarly to the :class:`PCZGate`, the gate is hereby only realized up to single-qubit phase gates. The phase shift :math:`\theta` depends on the phase :math:`\lambda` of the gate. Unitary matrix representation: .. math:: PCP = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & e^{i\theta(\lambda)} & 0 & 0 \\ 0 & 0 & e^{i\theta(\lambda)} & 0 \\ 0 & 0 & 0 & e^{i(2\theta(\lambda)+\lambda)} \end{pmatrix} Note that the :math:`\lambda`-dependence that is implemented in this class is only accurate for :math:`\lambda \leq \pi`. .. testcode:: from qiskit_qryd_provider import PCPGate import numpy as np assert np.round(PCPGate.get_theta(np.pi), 2) == 2.13 """
[docs] def __init__(self, lam: float, label: str = None) -> None: """Create a new PCP gate. Args: lam: Phase of the gate. label: Optional label for the gate. """ super().__init__("pcp", 2, [lam], label=label)
def _define(self) -> None: """Define the gate.""" qc = QuantumCircuit(2) lam = self.params[0] theta = self.get_theta(lam) qc.u(0, 0, theta, 0) qc.u(0, 0, theta, 1) qc.cp(lam, 0, 1) self.definition = qc
[docs] def to_matrix(self) -> List[List[complex]]: """Return the unitary matrix of the gate. Returns: A two-dimensional array for the gate unitary matrix. """ lam = self.params[0] theta = self.get_theta(lam) return [ [1, 0, 0, 0], [0, exp(1j * theta), 0, 0], [0, 0, exp(1j * theta), 0], [0, 0, 0, exp(2j * self._theta + 1j * lam)], ]
[docs] def to_kraus(self) -> "qiskit.circuit.Instruction": """Return the Kraus representation of the gate. Raises: NotImplementedError: If the Kraus representation is not set. Returns: An instruction encapsulating the Kraus representation. """ if self._kraus is None: raise NotImplementedError("The Kraus representation is not implemented.") return self._kraus
@classmethod def _init_theta(cls) -> None: r"""Initialize the :math:`\lambda`-dependent phase shift of the gate. Note that after the initialization, a decomposition of the PCP gate is stored to Qiskit's SessionEquivalenceLibrary. """ cls._lam = Parameter("lambda") cls._theta = ( 5.11382 - 0.32933 * ( 1.63085 * cls._lam * cls._lam * (2 * cls._lam).exp() + cls._lam + 0.02899 ).log() ) # Reset equivalence library default = [] for c in SessionEquivalenceLibrary.get_entry(CPhaseGate(cls._lam)): if not c.get_instructions("pcp"): default.append(c) SessionEquivalenceLibrary.set_entry(CPhaseGate(cls._lam), default) SessionEquivalenceLibrary.set_entry(PCPGate(cls._lam), []) # Attach new decomposition to the equivalence library def_pcp_cz = QuantumCircuit(2) def_pcp_cz.append(PCPGate(cls._lam), [0, 1]) def_pcp_cz.u(0, 0, -cls._theta, 0) def_pcp_cz.u(0, 0, -cls._theta, 1) SessionEquivalenceLibrary.add_equivalence(CPhaseGate(cls._lam), def_pcp_cz) def_cz_pcp = QuantumCircuit(2) def_cz_pcp.append(CPhaseGate(cls._lam), [0, 1]) def_cz_pcp.u(0, 0, cls._theta, 0) def_cz_pcp.u(0, 0, cls._theta, 1) SessionEquivalenceLibrary.add_equivalence(PCPGate(cls._lam), def_cz_pcp)
[docs] @classmethod def get_theta(cls, lam: float) -> float: r"""Get the phase shift of the gate for a given phase :math:`\lambda`. Args: lam: Phase of the gate. Returns: Angle of the phase shift. """ return float(cls._theta.assign(cls._lam, lam))
[docs] @classmethod def set_kraus(cls, kraus: List[List[List[complex]]] = None) -> None: """Set the Kraus representation of the gate. Args: kraus: A three-dimensional array encoding the Kraus representation of the gate. """ if kraus is not None: cls._kraus = Kraus(kraus).to_instruction() else: cls._kraus = None
PCPGate._init_theta() PCPGate.set_kraus(None)