# Copyright 2018-2021 Xanadu Quantum Technologies Inc.# Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at# http://www.apache.org/licenses/LICENSE-2.0# Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.# pylint: disable=too-many-argumentsr"""This module contains the available built-in continuous-variablequantum operations supported by PennyLane, as well as their conventions... todo:: Add gradient recipes for Gaussian state preparations.. todo:: The gradient computation assumes all parameters are real (floats), some docstrings here allow complex or even array parameter values. This includes :class:`~.DisplacedSqueezedState` and :class:`~.CatState`. Possible solution: disallow such operations to depend on free parameters, this way they won't be differentiated... note:: For the Heisenberg matrix representation of CV operations, we use the ordering :math:`(\hat{\mathbb{1}}, \hat{x}, \hat{p})` for single modes and :math:`(\hat{\mathbb{1}}, \hat{x}_1, \hat{p}_2, \hat{x}_1,\hat{p}_2)` for two modes ."""# As the qubit based ``decomposition``, ``_matrix``, ``diagonalizing_gates``# abstract methods are not defined in the CV case, disabling the related check# pylint: disable=abstract-methodimportmathimportnumpyasnpfromscipy.linalgimportblock_diagfrompennylaneimportmathasqml_mathfrompennylane.operationimportAnyWires,CVObservable,CVOperationfrom.identityimportI,Identity# pylint: disable=unused-importfrom.metaimportSnapshot# pylint: disable=unused-import_two_term_shift_rule=[[0.5,1,np.pi/2],[-0.5,1,-np.pi/2]]def_rotation(phi,bare=False):r"""Utility function, returns the Heisenberg transformation of a phase rotation gate. The transformation matrix returned is: .. math:: M = \begin{bmatrix} 1 & 0 & 0\\ 0 & \cos\phi & -\sin\phi\\ 0 & \sin\phi & \cos\phi \end{bmatrix} Args: phi (float): rotation angle. bare (bool): if True, return a simple 2d rotation matrix Returns: array[float]: transformation matrix """c=math.cos(phi)s=math.sin(phi)temp=np.array([[c,-s],[s,c]])ifbare:returntempreturnblock_diag(1,temp)# pylint: disable=no-member
[docs]classRotation(CVOperation):r""" Phase space rotation. .. math:: R(\phi) = \exp\left(i \phi \ad \a\right)=\exp\left(i \frac{\phi}{2} \left(\frac{\x^2+ \p^2}{\hbar}-\I\right)\right). **Details:** * Number of wires: 1 * Number of parameters: 1 * Gradient recipe: :math:`\frac{d}{dr}f(R(r)) = \frac{1}{2} \left[f(R(\phi+\pi/2)) - f(R(\phi-\pi/2))\right]` where :math:`f` is an expectation value depending on :math:`R(r)`. * Heisenberg representation: .. math:: M = \begin{bmatrix} 1 & 0 & 0\\ 0 & \cos\phi & -\sin\phi\\ 0 & \sin\phi & \cos\phi \end{bmatrix} Args: phi (float): the rotation angle wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=1num_wires=1grad_method="A"grad_recipe=(_two_term_shift_rule,)def__init__(self,phi,wires,id=None):super().__init__(phi,wires=wires,id=id)@staticmethoddef_heisenberg_rep(p):return_rotation(p[0])
[docs]classSqueezing(CVOperation):r""" Phase space squeezing. .. math:: S(z) = \exp\left(\frac{1}{2}(z^* \a^2 -z {\a^\dagger}^2)\right). where :math:`z = r e^{i\phi}`. **Details:** * Number of wires: 1 * Number of parameters: 2 * Gradient recipe: :math:`\frac{d}{dr}f(S(r,\phi)) = \frac{1}{2\sinh s} \left[f(S(r+s, \phi)) - f(S(r-s, \phi))\right]`, where :math:`s` is an arbitrary real number (:math:`0.1` by default) and :math:`f` is an expectation value depending on :math:`S(r,\phi)`. * Heisenberg representation: .. math:: M = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cosh r - \cos\phi \sinh r & -\sin\phi\sinh r \\ 0 & -\sin\phi\sinh r & \cosh r+\cos\phi\sinh r \end{bmatrix} Args: r (float): squeezing amount phi (float): squeezing phase angle :math:`\phi` wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=2num_wires=1grad_method="A"shift=0.1multiplier=0.5/math.sinh(shift)a=1grad_recipe=([[multiplier,a,shift],[-multiplier,a,-shift]],_two_term_shift_rule)def__init__(self,r,phi,wires,id=None):super().__init__(r,phi,wires=wires,id=id)@staticmethoddef_heisenberg_rep(p):R=_rotation(p[1]/2)returnR@np.diag([1,math.exp(-p[0]),math.exp(p[0])])@R.T
[docs]classDisplacement(CVOperation):r""" Phase space displacement. .. math:: D(a,\phi) = D(\alpha) = \exp(\alpha \ad -\alpha^* \a) = \exp\left(-i\sqrt{\frac{2}{\hbar}}(\re(\alpha) \hat{p} -\im(\alpha) \hat{x})\right). where :math:`\alpha = ae^{i\phi}` has magnitude :math:`a\geq 0` and phase :math:`\phi`. The result of applying a displacement to the vacuum is a coherent state :math:`D(\alpha)\ket{0} = \ket{\alpha}`. **Details:** * Number of wires: 1 * Number of parameters: 2 * Gradient recipe: :math:`\frac{d}{da}f(D(a,\phi)) = \frac{1}{2s} \left[f(D(a+s, \phi)) - f(D(a-s, \phi))\right]`, where :math:`s` is an arbitrary real number (:math:`0.1` by default) and :math:`f` is an expectation value depending on :math:`D(a,\phi)`. * Heisenberg representation: .. math:: M = \begin{bmatrix} 1 & 0 & 0 \\ 2a\cos\phi & 1 & 0 \\ 2a\sin\phi & 0 & 1\end{bmatrix} Args: a (float): displacement magnitude :math:`a=|\alpha|` phi (float): phase angle :math:`\phi` wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=2num_wires=1grad_method="A"shift=0.1multiplier=0.5/shifta=1grad_recipe=([[multiplier,a,shift],[-multiplier,a,-shift]],_two_term_shift_rule)def__init__(self,a,phi,wires,id=None):super().__init__(a,phi,wires=wires,id=id)@staticmethoddef_heisenberg_rep(p):c=math.cos(p[1])s=math.sin(p[1])scale=2# sqrt(2 * hbar)returnnp.array([[1,0,0],[scale*c*p[0],1,0],[scale*s*p[0],0,1]])
[docs]classTwoModeSqueezing(CVOperation):r""" Phase space two-mode squeezing. .. math:: S_2(z) = \exp\left(z^* \a \hat{b} -z \ad \hat{b}^\dagger \right) = \exp\left(r (e^{-i\phi} \a\hat{b} -e^{i\phi} \ad \hat{b}^\dagger \right). where :math:`z = r e^{i\phi}`. **Details:** * Number of wires: 2 * Number of parameters: 2 * Gradient recipe: :math:`\frac{d}{dr}f(S_2(r,\phi)) = \frac{1}{2\sinh s} \left[f(S_2(r+s, \phi)) - f(S_2(r-s, \phi))\right]`, where :math:`s` is an arbitrary real number (:math:`0.1` by default) and :math:`f` is an expectation value depending on :math:`S_2(r,\phi)`. * Heisenberg representation: .. math:: M = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 \\ 0 & \cosh r & 0 & \sinh r \cos \phi & \sinh r \sin \phi\\ 0 & 0 & \cosh r & \sinh r \sin \phi & -\sinh r \cos \phi\\ 0 & \sinh r \cos \phi & \sinh r \sin \phi & \cosh r & 0\\ 0 & \sinh r \sin \phi & -\sinh r \cos \phi & 0 & \cosh r \end{bmatrix} Args: r (float): squeezing amount phi (float): squeezing phase angle :math:`\phi` wires (Sequence[Any]): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=2num_wires=2grad_method="A"shift=0.1multiplier=0.5/math.sinh(shift)a=1grad_recipe=([[multiplier,a,shift],[-multiplier,a,-shift]],_two_term_shift_rule)def__init__(self,r,phi,wires,id=None):super().__init__(r,phi,wires=wires,id=id)@staticmethoddef_heisenberg_rep(p):R=_rotation(p[1],bare=True)S=math.sinh(p[0])*np.diag([1,-1])U=math.cosh(p[0])*np.identity(5)U[0,0]=1U[1:3,3:5]=S@R.TU[3:5,1:3]=S@R.TreturnU
[docs]classQuadraticPhase(CVOperation):r""" Quadratic phase shift. .. math:: P(s) = e^{i \frac{s}{2} \hat{x}^2/\hbar}. **Details:** * Number of wires: 1 * Number of parameters: 1 * Gradient recipe: :math:`\frac{d}{ds}f(P(s)) = \frac{1}{2 a} \left[f(P(s+a)) - f(P(s-a))\right]`, where :math:`a` is an arbitrary real number (:math:`0.1` by default) and :math:`f` is an expectation value depending on :math:`P(s)`. * Heisenberg representation: .. math:: M = \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & s & 1 \\ \end{bmatrix} Args: s (float): parameter wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=1num_wires=1grad_method="A"shift=0.1multiplier=0.5/shifta=1grad_recipe=([[multiplier,a,shift],[-multiplier,a,-shift]],)def__init__(self,s,wires,id=None):super().__init__(s,wires=wires,id=id)@staticmethoddef_heisenberg_rep(p):U=np.identity(3)U[2,1]=p[0]returnU
[docs]classKerr(CVOperation):r""" Kerr interaction. .. math:: K(\kappa) = e^{i \kappa \hat{n}^2}. **Details:** * Number of wires: 1 * Number of parameters: 1 * Gradient recipe: None (uses finite difference) Args: kappa (float): parameter wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=1num_wires=1grad_method="F"def__init__(self,kappa,wires,id=None):super().__init__(kappa,wires=wires,id=id)
[docs]classCrossKerr(CVOperation):r""" Cross-Kerr interaction. .. math:: CK(\kappa) = e^{i \kappa \hat{n}_1\hat{n}_2}. **Details:** * Number of wires: 2 * Number of parameters: 1 * Gradient recipe: None (uses finite difference) Args: kappa (float): parameter wires (Sequence[Any]): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=1num_wires=2grad_method="F"def__init__(self,kappa,wires,id=None):super().__init__(kappa,wires=wires,id=id)
[docs]classCubicPhase(CVOperation):r""" Cubic phase shift. .. math:: V(\gamma) = e^{i \frac{\gamma}{3} \hat{x}^3/\hbar}. **Details:** * Number of wires: 1 * Number of parameters: 1 * Gradient recipe: None (uses finite difference) Args: gamma (float): parameter wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=1num_wires=1grad_method="F"def__init__(self,gamma,wires,id=None):super().__init__(gamma,wires=wires,id=id)
[docs]classInterferometerUnitary(CVOperation):r""" A linear interferometer transforming the bosonic operators according to the unitary matrix :math:`U`. .. note:: This operation implements a **fixed** linear interferometer given a known unitary matrix. If you instead wish to parametrize the interferometer, and calculate the gradient/optimize with respect to these parameters, consider instead the :func:`pennylane.template.Interferometer` template, which constructs an interferometer from a combination of beamsplitters and rotation gates. **Details:** * Number of wires: Any * Number of parameters: 1 * Gradient recipe: None * Heisenberg representation: .. math:: M = \begin{bmatrix} 1 & 0\\ 0 & S\\ \end{bmatrix} where :math:`S` is the Gaussian symplectic transformation representing the interferometer. Args: U (array): A shape ``(len(wires), len(wires))`` complex unitary matrix wires (Sequence[Any] or Any): the wires the operation acts on id (str or None): String representing the operation (optional) """num_params=1num_wires=AnyWiresgrad_method=Nonegrad_recipe=Nonedef__init__(self,U,wires,id=None):super().__init__(U,wires=wires,id=id)@staticmethoddef_heisenberg_rep(p):N=len(p[0])A=p[0].realB=p[0].imagrows=np.arange(2*N).reshape(2,-1).T.flatten()S=np.vstack([np.hstack([A,-B]),np.hstack([B,A])])[:,rows][rows]M=np.eye(2*N+1)M[1:2*N+1,1:2*N+1]=SreturnM
# =============================================================================# State preparation# =============================================================================# TODO: put Heisenberg reps of state preparations in docstrings?
[docs]classCoherentState(CVOperation):r""" Prepares a coherent state. **Details:** * Number of wires: 1 * Number of parameters: 2 * Gradient recipe: None (uses finite difference) Args: a (float): displacement magnitude :math:`r=|\alpha|` phi (float): phase angle :math:`\phi` wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=2num_wires=1grad_method="F"def__init__(self,a,phi,wires,id=None):super().__init__(a,phi,wires=wires,id=id)
[docs]classSqueezedState(CVOperation):r""" Prepares a squeezed vacuum state. **Details:** * Number of wires: 1 * Number of parameters: 2 * Gradient recipe: None (uses finite difference) Args: r (float): squeezing magnitude phi (float): squeezing angle :math:`\phi` wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=2num_wires=1grad_method="F"def__init__(self,r,phi,wires,id=None):super().__init__(r,phi,wires=wires,id=id)
[docs]classDisplacedSqueezedState(CVOperation):r""" Prepares a displaced squeezed vacuum state. A displaced squeezed state is prepared by squeezing a vacuum state, and then applying a displacement operator, .. math:: \ket{\alpha,z} = D(\alpha)\ket{0,z} = D(\alpha)S(z)\ket{0}, with the displacement parameter :math:`\alpha=ae^{i\phi_a}` and the squeezing parameter :math:`z=re^{i\phi_r}`. **Details:** * Number of wires: 1 * Number of parameters: 4 * Gradient recipe: None (uses finite difference) Args: a (float): displacement magnitude :math:`a=|\alpha|` phi_a (float): displacement angle :math:`\phi_a` r (float): squeezing magnitude :math:`r=|z|` phi_r (float): squeezing angle :math:`\phi_r` wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=4num_wires=1grad_method="F"def__init__(self,a,phi_a,r,phi_r,wires,id=None):super().__init__(a,phi_a,r,phi_r,wires=wires,id=id)
[docs]classThermalState(CVOperation):r""" Prepares a thermal state. **Details:** * Number of wires: 1 * Number of parameters: 1 * Gradient recipe: None (uses finite difference) Args: nbar (float): mean thermal population of the mode wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=1num_wires=1grad_method="F"def__init__(self,nbar,wires,id=None):super().__init__(nbar,wires=wires,id=id)
[docs]classGaussianState(CVOperation):r""" Prepare subsystems in a given Gaussian state. **Details:** * Number of wires: Any * Number of parameters: 2 * Gradient recipe: None Args: V (array): the :math:`2N\times 2N` (real and positive definite) covariance matrix r (array): a length :math:`2N` vector of means, of the form :math:`(\x_0,\dots,\x_{N-1},\p_0,\dots,\p_{N-1})` wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=2num_wires=AnyWiresgrad_method="F"def__init__(self,V,r,wires,id=None):super().__init__(V,r,wires=wires,id=id)
[docs]classFockState(CVOperation):r""" Prepares a single Fock state. **Details:** * Number of wires: 1 * Number of parameters: 1 * Gradient recipe: None (not differentiable) Args: n (int): Fock state to prepare wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=1num_wires=1grad_method=Nonedef__init__(self,n,wires,id=None):super().__init__(n,wires=wires,id=id)
[docs]deflabel(self,decimals=None,base_label=None,cache=None):r"""A customizable string representation of the operator. Args: decimals=None (int): If ``None``, no parameters are included. Else, specifies how to round the parameters. base_label=None (str): overwrite the non-parameter component of the label cache=None (dict): dictionary that caries information between label calls in the same drawing Returns: str: label to use in drawings **Example:** >>> qml.FockState(7, wires=0).label() '|7⟩' """ifbase_labelisnotNone:ifdecimalsisNone:returnbase_labelp=format(qml_math.asarray(self.parameters[0]),".0f")returnbase_label+f"\n({p})"returnf"|{qml_math.asarray(self.parameters[0])}⟩"
[docs]classFockStateVector(CVOperation):r""" Prepare subsystems using the given ket vector in the Fock basis. **Details:** * Number of wires: Any * Number of parameters: 1 * Gradient recipe: None (uses finite difference) Args: state (array): a single ket vector, for single mode state preparation, or a multimode ket, with one array dimension per mode wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) .. details:: :title: Usage Details For a single mode with cutoff dimension :math:`N`, the input is a 1-dimensional vector of length :math:`N`. .. code-block:: dev_fock = qml.device("strawberryfields.fock", wires=4, cutoff_dim=4) state = np.array([0, 0, 1, 0]) @qml.qnode(dev_fock) def circuit(): qml.FockStateVector(state, wires=0) return qml.expval(qml.NumberOperator(wires=0)) For multiple modes, the input is the tensor product of single mode kets. For example, given a set of :math:`M` single mode vectors of length :math:`N`, the input should have shape ``(N, ) * M``. .. code-block:: used_wires = [0, 3] cutoff_dim = 5 dev_fock = qml.device("strawberryfields.fock", wires=4, cutoff_dim=cutoff_dim) state_1 = np.array([0, 1, 0, 0, 0]) state_2 = np.array([0, 0, 0, 1, 0]) combined_state = np.kron(state_1, state_2).reshape( (cutoff_dim, ) * len(used_wires) ) @qml.qnode(dev_fock) def circuit(): qml.FockStateVector(combined_state, wires=used_wires) return qml.expval(qml.NumberOperator(wires=0)) """num_params=1num_wires=AnyWiresgrad_method="F"def__init__(self,state,wires,id=None):super().__init__(state,wires=wires,id=id)
[docs]deflabel(self,decimals=None,base_label=None,cache=None):r"""A customizable string representation of the operator. Args: decimals=None (int): If ``None``, no parameters are included. Else, specifies how to round the parameters. base_label=None (str): overwrite the non-parameter component of the label cache=None (dict): dictionary that caries information between label calls in the same drawing Returns: str: label to use in drawings **Example:** >>> qml.FockStateVector([1,2,3], wires=(0,1,2)).label() '|123⟩' """ifbase_labelisnotNone:returnbase_labelbasis_string="".join(str(int(i))foriinself.parameters[0])returnf"|{basis_string}⟩"
[docs]classFockDensityMatrix(CVOperation):r""" Prepare subsystems using the given density matrix in the Fock basis. **Details:** * Number of wires: Any * Number of parameters: 1 * Gradient recipe: None (uses finite difference) Args: state (array): a single mode matrix :math:`\rho_{ij}`, or a multimode tensor :math:`\rho_{ij,kl,\dots,mn}`, with two indices per mode wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=1num_wires=AnyWiresgrad_method="F"def__init__(self,state,wires,id=None):super().__init__(state,wires=wires,id=id)
[docs]classCatState(CVOperation):r""" Prepares a cat state. A cat state is the coherent superposition of two coherent states, .. math:: \ket{\text{cat}(\alpha)} = \frac{1}{N} (\ket{\alpha} +e^{ip\pi} \ket{-\alpha}), where :math:`\ket{\pm\alpha} = D(\pm\alpha)\ket{0}` are coherent states with displacement parameters :math:`\pm\alpha=\pm ae^{i\phi}` and :math:`N = \sqrt{2 (1+\cos(p\pi)e^{-2|\alpha|^2})}` is the normalization factor. **Details:** * Number of wires: 1 * Number of parameters: 3 * Gradient recipe: None (uses finite difference) Args: a (float): displacement magnitude :math:`a=|\alpha|` phi (float): displacement angle :math:`\phi` p (float): parity, where :math:`p=0` corresponds to an even cat state, and :math:`p=1` an odd cat state. wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=3num_wires=1grad_method="F"def__init__(self,a,phi,p,wires,id=None):super().__init__(a,phi,p,wires=wires,id=id)
[docs]classNumberOperator(CVObservable):r""" The photon number observable :math:`\langle \hat{n}\rangle`. The number operator is defined as :math:`\hat{n} = \a^\dagger \a = \frac{1}{2\hbar}(\x^2 +\p^2) -\I/2`. When used with the :func:`~pennylane.expval` function, the mean photon number :math:`\braket{\hat{n}}` is returned. **Details:** * Number of wires: 1 * Number of parameters: 0 * Observable order: 2nd order in the quadrature operators * Heisenberg representation: .. math:: M = \frac{1}{2\hbar}\begin{bmatrix} -\hbar & 0 & 0\\ 0 & 1 & 0\\ 0 & 0 & 1 \end{bmatrix} Args: wires (Sequence[Any] or Any): the wire the operation acts on """num_params=0num_wires=1ev_order=2def__init__(self,wires):super().__init__(wires=wires)@staticmethoddef_heisenberg_rep(p):hbar=2returnnp.diag([-0.5,0.5/hbar,0.5/hbar])
[docs]classTensorN(CVObservable):r""" The tensor product of the :class:`~.NumberOperator` acting on different wires. If a single wire is defined, returns a :class:`~.NumberOperator` instance for convenient gradient computations. When used with the :func:`~pennylane.expval` function, the expectation value :math:`\langle \hat{n}_{i_0} \hat{n}_{i_1}\dots \hat{n}_{i_{N-1}}\rangle` for a (sub)set of modes :math:`[i_0, i_1, \dots, i_{N-1}]` of the system is returned. **Details:** * Number of wires: Any * Number of parameters: 0 Args: wires (Sequence[Any] or Any): the wire the operation acts on .. details:: :title: Usage Details Example for multiple modes: >>> cv_obs = qml.TensorN(wires=[0, 1]) >>> cv_obs TensorN(wires=[0, 1]) >>> cv_obs.ev_order is None True Example for a single mode (yields a :class:`~.NumberOperator`): >>> cv_obs = qml.TensorN(wires=[1]) >>> cv_obs NumberOperator(wires=[1]) >>> cv_obs.ev_order 2 """num_params=0num_wires=AnyWiresev_order=Nonedef__init__(self,wires):super().__init__(wires=wires)def__new__(cls,wires=None):# Custom definition for __new__ needed such that a NumberOperator can# be returned when a single mode is definedifwiresisnotNoneand(isinstance(wires,int)orlen(wires)==1):returnNumberOperator(wires=wires)returnsuper().__new__(cls)
[docs]classQuadX(CVObservable):r""" The position quadrature observable :math:`\hat{x}`. When used with the :func:`~pennylane.expval` function, the position expectation value :math:`\braket{\hat{x}}` is returned. This corresponds to the mean displacement in the phase space along the :math:`x` axis. **Details:** * Number of wires: 1 * Number of parameters: 0 * Observable order: 1st order in the quadrature operators * Heisenberg representation: .. math:: d = [0, 1, 0] Args: wires (Sequence[Any] or Any): the wire the operation acts on """num_params=0num_wires=1ev_order=1def__init__(self,wires):super().__init__(wires=wires)@staticmethoddef_heisenberg_rep(p):returnnp.array([0,1,0])
[docs]classQuadP(CVObservable):r""" The momentum quadrature observable :math:`\hat{p}`. When used with the :func:`~pennylane.expval` function, the momentum expectation value :math:`\braket{\hat{p}}` is returned. This corresponds to the mean displacement in the phase space along the :math:`p` axis. **Details:** * Number of wires: 1 * Number of parameters: 0 * Observable order: 1st order in the quadrature operators * Heisenberg representation: .. math:: d = [0, 0, 1] Args: wires (Sequence[Any] or Any): the wire the operation acts on """num_params=0num_wires=1ev_order=1def__init__(self,wires):super().__init__(wires=wires)@staticmethoddef_heisenberg_rep(p):returnnp.array([0,0,1])
[docs]classQuadOperator(CVObservable):r""" The generalized quadrature observable :math:`\x_\phi = \x cos\phi+\p\sin\phi`. When used with the :func:`~pennylane.expval` function, the expectation value :math:`\braket{\hat{\x_\phi}}` is returned. This corresponds to the mean displacement in the phase space along axis at angle :math:`\phi`. **Details:** * Number of wires: 1 * Number of parameters: 1 * Observable order: 1st order in the quadrature operators * Heisenberg representation: .. math:: d = [0, \cos\phi, \sin\phi] Args: phi (float): axis in the phase space at which to calculate the generalized quadrature observable wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=1num_wires=1grad_method="A"ev_order=1def__init__(self,phi,wires,id=None):super().__init__(phi,wires=wires,id=id)@staticmethoddef_heisenberg_rep(p):phi=p[0]returnnp.array([0,math.cos(phi),math.sin(phi)])# TODO check
[docs]deflabel(self,decimals=None,base_label=None,cache=None):r"""A customizable string representation of the operator. Args: decimals=None (int): If ``None``, no parameters are included. Else, specifies how to round the parameters. base_label=None (str): overwrite the non-parameter component of the label cache=None (dict): dictionary that caries information between label calls in the same drawing Returns: str: label to use in drawings **Example:** >>> op = qml.QuadOperator(1.234, wires=0) >>> op.label() 'cos(φ)x\n+sin(φ)p' >>> op.label(decimals=2) 'cos(1.23)x\n+sin(1.23)p' >>> op.label(base_label="Quad", decimals=2) 'Quad\n(1.23)' """ifbase_labelisnotNone:returnsuper().label(decimals=decimals,base_label=base_label,cache=cache)ifdecimalsisNone:p="φ"else:p=format(qml_math.array(self.parameters[0]),f".{decimals}f")returnf"cos({p})x\n+sin({p})p"
[docs]classPolyXP(CVObservable):r""" An arbitrary second-order polynomial observable. Represents an arbitrary observable :math:`P(\x,\p)` that is a second order polynomial in the basis :math:`\mathbf{r} = (\I, \x_0, \p_0, \x_1, \p_1, \ldots)`. For first-order observables the representation is a real vector :math:`\mathbf{d}` such that :math:`P(\x,\p) = \mathbf{d}^T \mathbf{r}`. For second-order observables the representation is a real symmetric matrix :math:`A` such that :math:`P(\x,\p) = \mathbf{r}^T A \mathbf{r}`. Used for evaluating arbitrary order-2 CV expectation values of :class:`~.pennylane.tape.CVParamShiftTape`. **Details:** * Number of wires: Any * Number of parameters: 1 * Observable order: 2nd order in the quadrature operators * Heisenberg representation: :math:`A` Args: q (array[float]): expansion coefficients wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=1num_wires=AnyWiresgrad_method="F"ev_order=2def__init__(self,q,wires,id=None):super().__init__(q,wires=wires,id=id)@staticmethoddef_heisenberg_rep(p):returnp[0]
[docs]classFockStateProjector(CVObservable):r""" The number state observable :math:`\ket{n}\bra{n}`. Represents the non-Gaussian number state observable .. math:: \ket{n}\bra{n} = \ket{n_0, n_1, \dots, n_P}\bra{n_0, n_1, \dots, n_P} where :math:`n_i` is the occupation number of the :math:`i` th wire. The expectation of this observable is .. math:: E[\ket{n}\bra{n}] = \text{Tr}(\ket{n}\bra{n}\rho) = \text{Tr}(\braketT{n}{\rho}{n}) = \braketT{n}{\rho}{n} corresponding to the probability of measuring the quantum state in the state :math:`\ket{n}=\ket{n_0, n_1, \dots, n_P}`. .. note:: If ``expval(FockStateProjector)`` is applied to a subset of wires, the unaffected wires are traced out prior to the expectation value calculation. **Details:** * Number of wires: Any * Number of parameters: 1 * Observable order: None (non-Gaussian) Args: n (array): Array of non-negative integers representing the number state observable :math:`\ket{n}\bra{n}=\ket{n_0, n_1, \dots, n_P}\bra{n_0, n_1, \dots, n_P}`. For example, to return the observable :math:`\ket{0,4,2}\bra{0,4,2}` acting on wires 0, 1, and 3 of a QNode, you would call ``FockStateProjector(np.array([0, 4, 2], wires=[0, 1, 3]))``. Note that ``len(n)==len(wires)``, and that ``len(n)`` cannot exceed the total number of wires in the QNode. wires (Sequence[Any] or Any): the wire the operation acts on id (str or None): String representing the operation (optional) """num_params=1num_wires=AnyWiresgrad_method=Noneev_order=Nonedef__init__(self,n,wires,id=None):super().__init__(n,wires=wires,id=id)
[docs]deflabel(self,decimals=None,base_label=None,cache=None):r"""A customizable string representation of the operator. Args: decimals=None (int): If ``None``, no parameters are included. Else, specifies how to round the parameters. base_label=None (str): overwrite the non-parameter component of the label cache=None (dict): dictionary that caries information between label calls in the same drawing Returns: str: label to use in drawings **Example:** >>> qml.FockStateProjector([1,2,3], wires=(0,1,2)).label() '|123⟩⟨123|' """ifbase_labelisnotNone:returnsuper().label(decimals=decimals,base_label=base_label,cache=cache)basis_string="".join(str(int(i))foriinself.parameters[0])returnf"|{basis_string}⟩⟨{basis_string}|"