Source code for pennylane.templates.subroutines.gqsp
# Copyright 2024 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."""Contains the GQSP template."""# pylint: disable=too-many-argumentsimportcopyimportpennylaneasqmlfrompennylane.operationimportOperationfrompennylane.queuingimportQueuingManagerfrompennylane.wiresimportWires
[docs]classGQSP(Operation):r""" Implements the generalized quantum signal processing (GQSP) circuit. This operation encodes a polynomial transformation of an input unitary operator following the algorithm described in `arXiv:2308.01501 <https://arxiv.org/abs/2308.01501>`__ as: .. math:: U \xrightarrow{GQSP} \begin{pmatrix} \text{poly}(U) & * \\ * & * \\ \end{pmatrix} The implementation requires one control qubit. Args: unitary (Operator): the operator to be encoded by the GQSP circuit angles (tensor[float]): array of angles defining the polynomial transformation. The shape of the array must be `(3, d+1)`, where `d` is the degree of the polynomial. control (Union[Wires, int, str]): control qubit used to encode the polynomial transformation .. note:: The :func:`~.poly_to_angles` function can be used to calculate the angles for a given polynomial. Example: .. code-block:: python # P(x) = 0.1 + 0.2j x + 0.3 x^2 poly = [0.1, 0.2j, 0.3] angles = qml.poly_to_angles(poly, "GQSP") @qml.prod # transforms the qfunc into an Operator def unitary(wires): qml.RX(0.3, wires) dev = qml.device("default.qubit") @qml.qnode(dev) def circuit(angles): qml.GQSP(unitary(wires = 1), angles, control = 0) return qml.state() matrix = qml.matrix(circuit, wire_order=[0, 1])(angles) .. code-block:: pycon >>> print(np.round(matrix,3)[:2, :2]) [[0.387+0.198j 0.03 -0.089j] [0.03 -0.089j 0.387+0.198j]] """grad_method=Nonedef__init__(self,unitary,angles,control,id=None):total_wires=qml.wires.Wires(control)+unitary.wiresself._hyperparameters={"unitary":unitary,"control":qml.wires.Wires(control)}super().__init__(angles,*unitary.data,wires=total_wires,id=id)def_flatten(self):data=self.parametersreturndata,(self.hyperparameters["unitary"],self.hyperparameters["control"],)@classmethoddef_unflatten(cls,data,metadata):returncls(unitary=metadata[0],angles=data[0],control=metadata[1])@classmethoddef_primitive_bind_call(cls,*args,**kwargs):returncls._primitive.bind(*args,**kwargs)
[docs]@staticmethoddefcompute_decomposition(*parameters,**hyperparameters):# pylint: disable=arguments-differr""" Representation of the operator as a product of other operators (static method). .. math:: O = O_1 O_2 \dots O_n. .. seealso:: :meth:`~.Operator.decomposition`. Args: *parameters (list): trainable parameters of the operator, as stored in the ``parameters`` attribute wires (Iterable[Any], Wires): wires that the operator acts on **hyperparams (dict): non-trainable hyperparameters of the operator, as stored in the ``hyperparameters`` attribute Returns: list[Operator]: decomposition of the operator """unitary=hyperparameters["unitary"]control=hyperparameters["control"]angles=parameters[0]thetas,phis,lambds=angles[0],angles[1],angles[2]op_list=[]# These four gates adapt PennyLane's qml.U3 to the chosen U3 format in the GQSP paper.op_list.append(qml.X(control))op_list.append(qml.U3(2*thetas[0],phis[0],lambds[0],wires=control))op_list.append(qml.X(control))op_list.append(qml.Z(control))fortheta,phi,lambinzip(thetas[1:],phis[1:],lambds[1:]):op_list.append(qml.ctrl(unitary,control=control,control_values=0))op_list.append(qml.X(control))op_list.append(qml.U3(2*theta,phi,lamb,wires=control))op_list.append(qml.X(control))op_list.append(qml.Z(control))returnop_list