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-arguments
import copy
import pennylane as qml
from pennylane.operation import Operation
from pennylane.queuing import QueuingManager
from pennylane.wires import Wires
[docs]class GQSP(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 = None
def __init__(self, unitary, angles, control, id=None):
total_wires = qml.wires.Wires(control) + unitary.wires
self._hyperparameters = {"unitary": unitary, "control": qml.wires.Wires(control)}
super().__init__(angles, *unitary.data, wires=total_wires, id=id)
def _flatten(self):
data = self.parameters
return data, (
self.hyperparameters["unitary"],
self.hyperparameters["control"],
)
@classmethod
def _unflatten(cls, data, metadata):
return cls(unitary=metadata[0], angles=data[0], control=metadata[1])
@classmethod
def _primitive_bind_call(cls, *args, **kwargs):
return cls._primitive.bind(*args, **kwargs)
[docs] def map_wires(self, wire_map: dict):
# pylint: disable=protected-access
new_op = copy.deepcopy(self)
new_op._wires = Wires([wire_map.get(wire, wire) for wire in self.wires])
new_op._hyperparameters["unitary"] = qml.map_wires(
new_op._hyperparameters["unitary"], wire_map
)
new_op._hyperparameters["control"] = tuple(
wire_map.get(w, w) for w in new_op._hyperparameters["control"]
)
return new_op
[docs] @staticmethod
def compute_decomposition(*parameters, **hyperparameters): # pylint: disable=arguments-differ
r"""
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))
for theta, phi, lamb in zip(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))
return op_list
[docs] def queue(self, context=QueuingManager):
context.remove(self.hyperparameters["unitary"])
context.append(self)
return self
_modules/pennylane/templates/subroutines/gqsp
Download Python script
Download Notebook
View on GitHub