Source code for pennylane.estimator.ops.qubit.non_parametric_ops

# Copyright 2025 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.
r"""Resource operators for non parametric single qubit operations."""

import pennylane.estimator as qre
from pennylane.estimator.resource_operator import (
    CompressedResourceOp,
    GateCount,
    ResourceOperator,
    resource_rep,
)
from pennylane.exceptions import ResourcesUndefinedError
from pennylane.wires import Wires

# pylint: disable=arguments-differ


[docs] class Hadamard(ResourceOperator): r"""Resource class for the Hadamard gate. Args: wires (Sequence[int] | int | None): the wire the operation acts on Resources: The Hadamard gate is treated as a fundamental gate and thus it cannot be decomposed further. Requesting the resources of this gate raises a :class:`~.pennylane.exceptions.ResourcesUndefinedError` error. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.Hadamard`. """ num_wires = 1 def __init__(self, wires=None): """Initializes the ``Hadamard`` operator.""" if wires is not None and len(Wires(wires)) != 1: raise ValueError(f"Expected {self.num_wires} wires, got {len(Wires(wires))}") super().__init__(wires=wires)
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Each object represents a quantum gate and the number of times it occurs in the decomposition. Resources: The ``Hadamard`` gate is treated as a fundamental gate and thus it cannot be decomposed further. Requesting the resources of this gate raises a :class:`~.pennylane.exceptions.ResourcesUndefinedError` error. Raises: ResourcesUndefinedError: This gate is fundamental, no further decomposition defined. """ raise ResourcesUndefinedError
@property def resource_params(self) -> dict: r"""Returns a dictionary containing the minimal information needed to compute the resources. Returns: dict: Empty dictionary. The resources of this operation don't depend on any additional parameters. """ return {}
[docs] @classmethod def resource_rep(cls) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute the resources.""" return CompressedResourceOp(cls, num_wires=cls.num_wires, params={})
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict | None = None) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: This operation is self-adjoint, so the resources of the adjoint operation results are same as the original operation. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ return [GateCount(cls.resource_rep(), 1)]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict | None = None, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: num_ctrl_wires (int): the number of qubits the operation is controlled on num_zero_ctrl (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: For a single control wire, the cost is a single instance of ``CH``. Two additional ``X`` gates are used to flip the control qubit if it is zero-controlled. In the case where multiple controlled wires are provided, the resources are derived from the following identities: .. math:: \begin{align} \hat{H} &= \hat{R}_{y}(\frac{\pi}{4}) \cdot \hat{Z} \cdot \hat{R}_{y}(\frac{-\pi}{4}), \\ \hat{Z} &= \hat{H} \cdot \hat{X} \cdot \hat{H}. \end{align} Specifically, the resources are given by two ``RY`` gates, two ``Hadamard`` gates and a ``X`` gate. By replacing the ``X`` gate with ``MultiControlledX`` gate, we obtain a controlled-version of this identity. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ if num_ctrl_wires == 1: gate_lst = [GateCount(resource_rep(qre.CH))] if num_zero_ctrl: gate_lst.append(GateCount(resource_rep(X), 2)) return gate_lst gate_lst = [] ry = resource_rep(qre.RY) h = cls.resource_rep() mcx = resource_rep( qre.MultiControlledX, { "num_ctrl_wires": num_ctrl_wires, "num_zero_ctrl": num_zero_ctrl, }, ) gate_lst.append(GateCount(h, 2)) gate_lst.append(GateCount(ry, 2)) gate_lst.append(GateCount(mcx)) return gate_lst
[docs] @classmethod def pow_resource_decomp( cls, pow_z: int, target_resource_params: dict | None = None ) -> list[GateCount]: r"""Returns a list representing the resources for an operator raised to a power. Args: pow_z (int): the power that the operator is being raised to target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: The Hadamard gate raised to even powers produces identity and raised to odd powers it produces itself. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ if pow_z % 2 == 0: return [GateCount(resource_rep(qre.Identity))] return [GateCount(cls.resource_rep())]
[docs] class S(ResourceOperator): r"""Resource class for the S-gate. Args: wires (Sequence[int] | int | None): the wire the operation acts on Resources: The ``S`` gate decomposes into two ``T`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.S`. **Example** The resources for this operation are computed using: >>> qml.estimator.S.resource_decomp() [(2 x T)] """ num_wires = 1 def __init__(self, wires=None): """Initializes the ``S`` operator.""" if wires is not None and len(Wires(wires)) != 1: raise ValueError(f"Expected {self.num_wires} wires, got {len(Wires(wires))}") super().__init__(wires=wires)
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Each object represents a quantum gate and the number of times it occurs in the decomposition. Resources: The S-gate decomposes into two T-gates. """ t = resource_rep(T) return [GateCount(t, 2)]
@property def resource_params(self) -> dict: r"""Returns a dictionary containing the minimal information needed to compute the resources. Returns: dict: Empty dictionary. The resources of this operation don't depend on any additional parameters. """ return {}
[docs] @classmethod def resource_rep(cls) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute the resources.""" return CompressedResourceOp(cls, num_wires=cls.num_wires, params={})
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict | None = None) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: The adjoint of the ``S`` gate is equivalent to :math:`\hat{Z} \cdot \hat{S}`. The resources are defined as one instance of Z-gate, and one instance of S-gate. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ z = resource_rep(Z) return [GateCount(z, 1), GateCount(cls.resource_rep(), 1)]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict | None = None, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: num_ctrl_wires (int): the number of qubits the operation is controlled on num_zero_ctrl (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: The controlled-S gate decomposition is presented in (Fig. 5) `arXiv:1803.04933 <https://arxiv.org/pdf/1803.04933>`_. Given a single control wire, the cost is therefore two ``CNOT`` gates and three ``T`` gates. Two additional ``X`` gates are used to flip the control qubit if it is zero-controlled. In the case where multiple controlled wires are provided, we can collapse the control wires by introducing one auxiliary qubit in a `zeroed` state, which is reset at the end. In this case the cost increases by two additional ``MultiControlledX`` gates, as described in (Lemma 7.11) `Barenco et al. arXiv:quant-ph/9503016 <https://arxiv.org/abs/quant-ph/9503016>`_. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ if num_ctrl_wires == 1: gate_lst = [ GateCount(resource_rep(qre.CNOT), 2), GateCount(resource_rep(T), 2), GateCount(resource_rep(qre.Adjoint, {"base_cmpr_op": resource_rep(T)})), ] if num_zero_ctrl: gate_lst.append(GateCount(resource_rep(X), 2)) return gate_lst mcx = resource_rep( qre.MultiControlledX, { "num_ctrl_wires": num_ctrl_wires, "num_zero_ctrl": num_zero_ctrl, }, ) return [ GateCount(mcx, 2), GateCount(resource_rep(qre.CNOT), 2), GateCount(resource_rep(T), 2), GateCount(resource_rep(qre.Adjoint, {"base_cmpr_op": resource_rep(T)})), ]
[docs] @classmethod def pow_resource_decomp( cls, pow_z: int, target_resource_params: dict | None = None ) -> list[GateCount]: r"""Returns a list representing the resources for an operator raised to a power. Args: pow_z (int): the power that the operator is being raised to target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: - The S-gate, when raised to a power which is a multiple of four, produces identity. - The cost of raising to an arbitrary integer power :math:`z`, when :math:`z \mod 4` is equal to one, means one instance of the S-gate. - The cost of raising to an arbitrary integer power :math:`z`, when :math:`z \mod 4` is equal to two, means one instance of the Z-gate. - The cost of raising to an arbitrary integer power :math:`z`, when :math:`z \mod 4` is equal to three, means one instance of the Z-gate and one instance of S-gate. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ mod_4 = pow_z % 4 if mod_4 == 0: return [] if mod_4 == 1: return [GateCount(cls.resource_rep())] if mod_4 == 2: return [GateCount(resource_rep(Z))] return [GateCount(resource_rep(Z)), GateCount(cls.resource_rep())]
[docs] class SWAP(ResourceOperator): r"""Resource class for the SWAP gate. Args: wires (Sequence[int] | None): the wires the operation acts on Resources: The resources come from the following identity expressing SWAP as the product of three ``CNOT`` gates: .. math:: SWAP = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1 \end{bmatrix} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0 \end{bmatrix}. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.SWAP`. **Example** The resources for this operation are computed using: >>> qml.estimator.SWAP.resource_decomp() [(3 x CNOT)] """ num_wires = 2 def __init__(self, wires=None): """Initializes the ``SWAP`` operator.""" if wires is not None and len(Wires(wires)) != 2: raise ValueError(f"Expected {self.num_wires} wires, got {len(Wires(wires))}") super().__init__(wires=wires) @property def resource_params(self) -> dict: r"""Returns a dictionary containing the minimal information needed to compute the resources. Returns: dict: Empty dictionary. The resources of this operation don't depend on any additional parameters. """ return {}
[docs] @classmethod def resource_rep(cls) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute a resource estimation.""" return CompressedResourceOp(cls, num_wires=cls.num_wires, params={})
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Each object represents a quantum gate and the number of times it occurs in the decomposition. Resources: The resources come from the following identity expressing SWAP as the product of three ``CNOT`` gates: .. math:: SWAP = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1 \end{bmatrix} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0 \end{bmatrix}. """ return [GateCount(resource_rep(qre.CNOT), 3)]
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict | None = None) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: This operation is self-adjoint, so the resources of the adjoint operation are same as the original operation. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ return [GateCount(cls.resource_rep())]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict | None = None, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: num_ctrl_wires (int): the number of qubits the operation is controlled on num_zero_ctrl (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: For a single control wire, the cost is a single instance of ``CSWAP``. Two additional ``X`` gates are used to flip the control qubit if it is zero-controlled. In the case where multiple controlled wires are provided, the resources are given by two ``CNOT`` gates and one ``MultiControlledX`` gate. This is because of the symmetric resource decomposition of the SWAP gate. By controlling on the middle CNOT gate, we obtain the required controlled operation. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ if num_ctrl_wires == 1: gate_types = [GateCount(resource_rep(qre.CSWAP))] if num_zero_ctrl: gate_types.append(GateCount(resource_rep(X), 2)) return gate_types cnot = resource_rep(qre.CNOT) mcx = resource_rep( qre.MultiControlledX, { "num_ctrl_wires": num_ctrl_wires + 1, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(cnot, 2), GateCount(mcx)]
[docs] @classmethod def pow_resource_decomp( cls, pow_z: int, target_resource_params: dict | None = None ) -> list[GateCount]: r"""Returns a list representing the resources for an operator raised to a power. Args: pow_z (int): the power that the operator is being raised to target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: The ``SWAP`` gate raised to even powers produces identity and raised to odd powers it produces itself. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ if pow_z % 2 == 0: return [GateCount(resource_rep(qre.Identity))] return [GateCount(cls.resource_rep())]
[docs] class T(ResourceOperator): r"""Resource class for the T-gate. Args: wires (Sequence[int] | int | None): the wire the operation acts on Resources: The ``T`` gate is treated as a fundamental gate and thus it cannot be decomposed further. Requesting the resources of this gate raises a :class:`~.pennylane.exceptions.ResourcesUndefinedError` error. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.T`. """ num_wires = 1 def __init__(self, wires=None): """Initializes the ``T`` operator.""" if wires is not None and len(Wires(wires)) != 1: raise ValueError(f"Expected {self.num_wires} wires, got {len(Wires(wires))}") super().__init__(wires=wires)
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Each object represents a quantum gate and the number of times it occurs in the decomposition. Resources: The ``T`` gate is treated as a fundamental gate and thus it cannot be decomposed further. Requesting the resources of this gate raises a :class:`~.pennylane.exceptions.ResourcesUndefinedError` error. Raises: ResourcesUndefinedError: This gate is fundamental, no further decomposition defined. """ raise ResourcesUndefinedError
@property def resource_params(self) -> dict: r"""Returns a dictionary containing the minimal information needed to compute the resources. Returns: dict: Empty dictionary. The resources of this operation don't depend on any additional parameters. """ return {}
[docs] @classmethod def resource_rep(cls) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute the resources.""" return CompressedResourceOp(cls, num_wires=cls.num_wires, params={})
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict | None = None) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: The adjoint of the T-gate is equivalent to the T-gate raised to the 7th power. The resources are defined as one Z-gate (:math:`Z = T^{4}`), one S-gate (:math:`S = T^{2}`) and one T-gate. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ z = resource_rep(Z) s = resource_rep(S) return [GateCount(cls.resource_rep()), GateCount(s), GateCount(z)]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict | None = None ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: num_ctrl_wires (int): the number of qubits the operation is controlled on num_zero_ctrl (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: The T-gate is equivalent to the PhaseShift gate for some fixed phase. Given a single control wire, the cost is therefore a single instance of ``ControlledPhaseShift``. Two additional ``X`` gates are used to flip the control qubit if it is zero-controlled. In the case where multiple controlled wires are provided, we can collapse the control wires by introducing one auxiliary qubit in a `zeroed` state, which is reset at the end. In this case the cost increases by two additional ``MultiControlledX`` gates, as described in (Lemma 7.11) `Barenco et al. arXiv:quant-ph/9503016 <https://arxiv.org/abs/quant-ph/9503016>`_. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ if num_ctrl_wires == 1: gate_types = [GateCount(resource_rep(qre.ControlledPhaseShift))] if num_zero_ctrl: gate_types.append(GateCount(resource_rep(X), 2)) return gate_types ct = resource_rep(qre.ControlledPhaseShift) mcx = resource_rep( qre.MultiControlledX, { "num_ctrl_wires": num_ctrl_wires, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(ct), GateCount(mcx, 2)]
[docs] @classmethod def pow_resource_decomp( cls, pow_z: int, target_resource_params: dict | None = None ) -> list[GateCount]: r"""Returns a list representing the resources for an operator raised to a power. Args: pow_z (int): the power that the operator is being raised to target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: The ``T`` gate, when raised to a power which is a multiple of eight, produces identity. Consequently, for any integer power `z`, the effective quantum operation :math:`T^{z}` is equivalent to :math:`T^{z \pmod 8}`. The decomposition for :math:`T^{z}`, where :math:`z \pmod 8` is denoted as `z'`, is as follows: - If `z' = 0`: The operation is equivalent to the Identity gate (:math:`I`). - If `z' = 1`: The operation is equivalent to the T-gate (:math:`T`). - If `z' = 2`: The operation is equivalent to the S-gate (:math:`S`). - If `z' = 3`: The operation is equivalent to a composition of an S-gate and a T-gate (:math:`S \cdot T`). - If `z' = 4` : The operation is equivalent to the Z-gate (:math:`Z`). - If `z' = 5`: The operation is equivalent to a composition of a Z-gate and a T-gate (:math:`Z \cdot T`). - If `z' = 6`: The operation is equivalent to a composition of a Z-gate and an S-gate (:math:`Z \cdot S`). - If `z' = 7`: The operation is equivalent to a composition of a Z-gate, an S-gate and a T-gate. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ if (mod_8 := pow_z % 8) == 0: return [GateCount(resource_rep(qre.Identity))] gate_lst = [] if mod_8 >= 4: gate_lst.append(GateCount(resource_rep(Z))) mod_8 -= 4 if mod_8 >= 2: gate_lst.append(GateCount(resource_rep(S))) mod_8 -= 2 if mod_8 >= 1: gate_lst.append(GateCount(cls.resource_rep())) return gate_lst
[docs] class X(ResourceOperator): r"""Resource class for the X-gate. Args: wires (Sequence[int] | int | None): the wire the operation acts on Resources: The ``X`` gate can be decomposed according to the following identities: .. math:: \begin{align} \hat{X} &= \hat{H} \cdot \hat{Z} \cdot \hat{H}, \\ \hat{Z} &= \hat{S}^{2}. \end{align} Thus the resources for an X-gate are two ``S`` gates and two ``Hadamard`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.PauliX`. **Example** The resources for this operation are computed using: >>> qml.estimator.X.resource_decomp() [(2 x Hadamard), (2 x S)] """ num_wires = 1 def __init__(self, wires=None): """Initializes the ``X`` operator.""" if wires is not None and len(Wires(wires)) != 1: raise ValueError(f"Expected {self.num_wires} wires, got {len(Wires(wires))}") super().__init__(wires=wires)
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Each object represents a quantum gate and the number of times it occurs in the decomposition. Resources: The ``X`` gate can be decomposed according to the following identities: .. math:: \begin{align} \hat{X} &= \hat{H} \cdot \hat{Z} \cdot \hat{H}, \\ \hat{Z} &= \hat{S}^{2}. \end{align} Thus the resources for an X-gate are two ``S`` gates and two ``Hadamard`` gates. """ s = resource_rep(S) h = resource_rep(Hadamard) return [GateCount(h, 2), GateCount(s, 2)]
@property def resource_params(self) -> dict: r"""Returns a dictionary containing the minimal information needed to compute the resources. Returns: dict: Empty dictionary. The resources of this operation don't depend on any additional parameters. """ return {}
[docs] @classmethod def resource_rep(cls) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute the resources.""" return CompressedResourceOp(cls, num_wires=cls.num_wires, params={})
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict | None = None) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: This operation is self-adjoint, so the resources of the adjoint operation results are same as the original operation. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ return [GateCount(cls.resource_rep())]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict | None = None, ): r"""Returns a list representing the resources for a controlled version of the operator. Args: num_ctrl_wires (int): the number of qubits the operation is controlled on num_zero_ctrl (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: For one or two control wires, the cost is one of ``CNOT`` or ``Toffoli`` respectively. Two additional ``X`` gates per control qubit are used to flip the control qubits if they are zero-controlled. In the case where multiple controlled wires are provided, the cost is one general ``MultiControlledX`` gate. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ if num_ctrl_wires > 2: mcx = resource_rep( qre.MultiControlledX, { "num_ctrl_wires": num_ctrl_wires, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(mcx)] gate_lst = [] if num_zero_ctrl: gate_lst.append(GateCount(resource_rep(X), 2 * num_zero_ctrl)) if num_ctrl_wires == 0: gate_lst.append(GateCount(resource_rep(X))) elif num_ctrl_wires == 1: gate_lst.append(GateCount(resource_rep(qre.CNOT))) else: gate_lst.append(GateCount(resource_rep(qre.Toffoli))) return gate_lst
[docs] @classmethod def pow_resource_decomp( cls, pow_z: int, target_resource_params: dict | None = None ) -> list[GateCount]: r"""Returns a list representing the resources for an operator raised to a power. Args: pow_z (int): the power that the operator is being raised to target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: The X-gate raised to even powers produces identity and raised to odd powers it produces itself. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ if pow_z % 2 == 0: return [GateCount(resource_rep(qre.Identity))] return [GateCount(cls.resource_rep())]
[docs] class Y(ResourceOperator): r"""Resource class for the Y-gate. Args: wires (Sequence[int] | int | None): the wire the operation acts on Resources: The ``Y`` gate can be decomposed according to the following identities: .. math:: \begin{align} \hat{Y} &= \hat{S} \cdot \hat{X} \cdot \hat{S}^{\dagger}, \\ \hat{X} &= \hat{H} \cdot \hat{Z} \cdot \hat{H}, \\ \hat{S}^{\dagger} &= \hat{Z} \cdot \hat{S}. \\ \end{align} Thus the resources for a Y-gate are two ``S`` gates, two ``Z`` gates and two ``Hadamard`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.PauliY`. **Example** The resources for this operation are computed using: >>> qml.estimator.Y.resource_decomp() [(1 x S), (1 x Z), (1 x Adjoint(S)), (2 x Hadamard)] """ num_wires = 1 def __init__(self, wires=None): """Initializes the ``Y`` operator.""" if wires is not None and len(Wires(wires)) != 1: raise ValueError(f"Expected {self.num_wires} wires, got {len(Wires(wires))}") super().__init__(wires=wires)
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Each object represents a quantum gate and the number of times it occurs in the decomposition. Resources: The ``Y`` gate can be decomposed according to the following identities: .. math:: \begin{align} \hat{Y} &= \hat{S} \cdot \hat{X} \cdot \hat{S}^{\dagger}, \\ \hat{X} &= \hat{H} \cdot \hat{Z} \cdot \hat{H}, \\ \hat{S}^{\dagger} &= \hat{Z} \cdot \hat{S}. \\ \end{align} Thus the resources for a Y-gate are one S-gate, one Adjoint(S)-gate, one Z-gate and two Hadamard gates. """ z = resource_rep(Z) s = resource_rep(S) s_adj = resource_rep(qre.Adjoint, {"base_cmpr_op": s}) h = resource_rep(Hadamard) return [GateCount(s), GateCount(z), GateCount(s_adj), GateCount(h, 2)]
@property def resource_params(self) -> dict: r"""Returns a dictionary containing the minimal information needed to compute the resources. Returns: dict: Empty dictionary. The resources of this operation don't depend on any additional parameters. """ return {}
[docs] @classmethod def resource_rep(cls) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute the resources.""" return CompressedResourceOp(cls, num_wires=cls.num_wires, params={})
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict | None = None) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: This operation is self-adjoint, so the resources of the adjoint operation results are same as the original operation. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ return [GateCount(cls.resource_rep())]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict | None = None, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: num_ctrl_wires (int): the number of qubits the operation is controlled on num_zero_ctrl (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: For a single control wire, the cost is a single instance of ``CY``. Two additional ``X`` gates are used to flip the control qubit if it is zero-controlled. In the case where multiple controlled wires are provided, the resources are derived from the following identity: .. math:: \hat{Y} = \hat{S} \cdot \hat{X} \cdot \hat{S}^{\dagger}. Specifically, the resources are given by a ``X`` gate conjugated with a pair of ``S`` gates. By replacing the ``X`` gate with a ``MultiControlledX`` gate, we obtain a controlled-version of this identity. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ if num_ctrl_wires == 1: gate_types = [GateCount(resource_rep(qre.CY))] if num_zero_ctrl: gate_types.append(GateCount(resource_rep(X), 2)) return gate_types s = resource_rep(S) s_dagg = resource_rep(qre.Adjoint, {"base_cmpr_op": s}) mcx = resource_rep( qre.MultiControlledX, { "num_ctrl_wires": num_ctrl_wires, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(s), GateCount(s_dagg), GateCount(mcx)]
[docs] @classmethod def pow_resource_decomp( cls, pow_z: int, target_resource_params: dict | None = None ) -> list[GateCount]: r"""Returns a list representing the resources for an operator raised to a power. Args: pow_z (int): the power that the operator is being raised to target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: The ``Y`` gate raised to even powers produces identity and raised to odd powers it produces itself. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ if pow_z % 2 == 0: return [GateCount(resource_rep(qre.Identity))] return [GateCount(cls.resource_rep())]
[docs] class Z(ResourceOperator): r"""Resource class for the Z-gate. Args: wires (Sequence[int] | int | None): the wire the operation acts on Resources: The ``Z`` gate can be decomposed according to the following identities: .. math:: \hat{Z} = \hat{S}^{2}, thus the resources for a Z-gate are two ``S`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.PauliZ`. **Example** The resources for this operation are computed using: >>> qml.estimator.Z.resource_decomp() [(2 x S)] """ num_wires = 1 def __init__(self, wires=None): """Initializes the ``Z`` operator.""" if wires is not None and len(Wires(wires)) != 1: raise ValueError(f"Expected {self.num_wires} wires, got {len(Wires(wires))}") super().__init__(wires=wires)
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Each object represents a quantum gate and the number of times it occurs in the decomposition. Resources: The ``Z`` gate can be decomposed according to the following identities: .. math:: \hat{Z} = \hat{S}^{2}, thus the resources for a Z-gate are two ``S`` gates. """ s = resource_rep(S) return [GateCount(s, 2)]
@property def resource_params(self) -> dict: r"""Returns a dictionary containing the minimal information needed to compute the resources. Returns: dict: Empty dictionary. The resources of this operation don't depend on any additional parameters. """ return {}
[docs] @classmethod def resource_rep(cls) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute the resources.""" return CompressedResourceOp(cls, num_wires=cls.num_wires, params={})
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict | None = None) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: This operation is self-adjoint, so the resources of the adjoint operation results are same as the original operation. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ return [GateCount(cls.resource_rep())]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict | None = None, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: num_ctrl_wires (int): the number of qubits the operation is controlled on num_zero_ctrl (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: For one or two control wires, the cost is one of ``CZ`` or ``CCZ`` respectively. Two additional ``X`` gates per control qubit are used to flip the control qubits if they are zero-controlled. In the case where multiple controlled wires are provided, the resources are derived from the following identity: .. math:: \hat{Z} = \hat{H} \cdot \hat{X} \cdot \hat{H}. Specifically, the resources are given by a ``X`` gate conjugated with a pair of ``Hadamard`` gates. By replacing the ``X`` gate with a ``MultiControlledX`` gate, we obtain a controlled-version of this identity. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of GateCount objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ if num_ctrl_wires > 2: h = resource_rep(Hadamard) mcx = resource_rep( qre.MultiControlledX, { "num_ctrl_wires": num_ctrl_wires, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(h, 2), GateCount(mcx)] gate_list = [] if num_ctrl_wires == 1: gate_list.append(GateCount(resource_rep(qre.CZ))) if num_ctrl_wires == 2: gate_list.append(GateCount(resource_rep(qre.CCZ))) if num_zero_ctrl: gate_list.append(GateCount(resource_rep(X), 2 * num_zero_ctrl)) return gate_list
[docs] @classmethod def pow_resource_decomp( cls, pow_z: int, target_resource_params: dict | None = None ) -> list[GateCount]: r"""Returns a list representing the resources for an operator raised to a power. Args: pow_z (int): the power that the operator is being raised to target_resource_params (dict | None): A dictionary containing the resource parameters of the target operator. Resources: The ``Z`` gate raised to even powers produces identity and raised to odd powers it produces itself. Returns: list[:class:`~.estimator.resource_operator.GateCount`]: A list of ``GateCount`` objects, where each object represents a specific quantum gate and the number of times it appears in the decomposition. """ if pow_z % 2 == 0: return [GateCount(resource_rep(qre.Identity))] return [GateCount(cls.resource_rep())]