Source code for pennylane.estimator.ops.op_math.controlled_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 controlled operations."""

from typing import Literal

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

# pylint: disable= arguments-differ, signature-differs


[docs] class CH(ResourceOperator): r"""Resource class for the CH gate. Args: wires (Sequence[int] | None): the wires the operation acts on Resources: 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 defined as two ``RY``, two ``Hadamard`` and one ``CNOT`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.CH`. **Example** The resources for this operation are computed using: >>> qml.estimator.CH.resource_decomp() [(2 x Hadamard), (2 x RY), (1 x CNOT)] """ num_wires = 2 def __init__(self, wires: WiresLike = None) -> None: if wires is not None and len(Wires(wires)) != self.num_wires: 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 the resources. Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: A compressed representation of the operator. """ return CompressedResourceOp(cls, cls.num_wires, {})
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list of ``GateCount`` objects representing the resources of the operator.. Resources: 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 defined as two ``RY``, two ``Hadamard`` and one ``CNOT`` gates. 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. """ ry = resource_rep(qre.RY) h = resource_rep(qre.Hadamard) cnot = resource_rep(CNOT) return [GateCount(h, 2), GateCount(ry, 2), GateCount(cnot, 1)]
[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 originial 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: The resources are expressed using the symbolic :class:`~.pennylane.estimator.ops.Controlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.pennylane.estimator.ops.Hadamard` class. Returns: list[:class:`~.pennylane.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. """ ctrl_h = resource_rep( qre.Controlled, { "base_cmpr_op": resource_rep(qre.Hadamard), "num_ctrl_wires": num_ctrl_wires + 1, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(ctrl_h)]
[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: This operation is self-inverse, thus when raised to even integer powers acts like the identity operator 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. """ return ( [GateCount(resource_rep(qre.Identity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep())] )
[docs] class CY(ResourceOperator): r"""Resource class for the CY gate. Args: wires (Sequence[int] | None): the wires the operation acts on Resources: The resources are derived from the following identity: .. math:: \hat{Y} = \hat{S} \cdot \hat{X} \cdot \hat{S}^{\dagger}. By replacing the ``X`` gate with a ``CNOT`` we obtain the controlled decomposition. Specifically, the resources are defined as a ``CNOT`` gate conjugated by a pair of ``S`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.CY`. **Example** The resources for this operation are computed using: >>> qml.estimator.CY.resource_decomp() [(1 x CNOT), (1 x S), (1 x Adjoint(S))] """ num_wires = 2 def __init__(self, wires: WiresLike = None) -> None: if wires is not None and len(Wires(wires)) != self.num_wires: 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 the resources. Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: A compressed representation of the operator. """ return CompressedResourceOp(cls, cls.num_wires, {})
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Resources: The resources are derived from the following identity: .. math:: \hat{Y} = \hat{S} \cdot \hat{X} \cdot \hat{S}^{\dagger}. By replacing the ``X`` gate with a ``CNOT`` we obtain the controlled decomposition. Specifically, the resources are defined as a ``CNOT`` gate conjugated by a pair of ``S`` gates. """ cnot = resource_rep(CNOT) s = resource_rep(qre.S) s_dag = resource_rep(qre.Adjoint, {"base_cmpr_op": s}) return [GateCount(cnot), GateCount(s), GateCount(s_dag)]
[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 originial 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: The resources are expressed using the symbolic :class:`~.pennylane.estimator.ops.Controlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.pennylane.estimator.ops.Y` class. Returns: list[:class:`~.pennylane.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. """ ctrl_y = resource_rep( qre.Controlled, { "base_cmpr_op": resource_rep(qre.Y), "num_ctrl_wires": num_ctrl_wires + 1, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(ctrl_y)]
[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: This operation is self-inverse, thus when raised to even integer powers acts like the identity operator 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. """ return ( [GateCount(resource_rep(qre.Identity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep())] )
[docs] class CZ(ResourceOperator): r"""Resource class for the CZ gate. Args: wires (Sequence[int] | None): the wires the operation acts on Resources: The resources are derived from the following identity: .. math:: \hat{Z} = \hat{H} \cdot \hat{X} \cdot \hat{H}. By replacing the ``X`` gate with a ``CNOT`` we obtain the controlled decomposition. Specifically, the resources are defined as a ``CNOT`` gate conjugated by a pair of ``Hadamard`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.CZ`. **Example** The resources for this operation are computed using: >>> qml.estimator.CZ.resource_decomp() [(1 x CNOT), (2 x Hadamard)] """ num_wires = 2 def __init__(self, wires: WiresLike = None) -> None: if wires is not None and len(Wires(wires)) != self.num_wires: 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 the resources. Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: A compressed representation of the operator. """ return CompressedResourceOp(cls, cls.num_wires, {})
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Resources: The resources are derived from the following identity: .. math:: \hat{Z} = \hat{H} \cdot \hat{X} \cdot \hat{H}. By replacing the ``X`` gate with a ``CNOT`` we obtain the controlled decomposition. Specifically, the resources are defined as a ``CNOT`` gate conjugated by a pair of ``Hadamard`` gates. 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. """ cnot = resource_rep(CNOT) h = resource_rep(qre.Hadamard) return [GateCount(cnot), GateCount(h, 2)]
[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: The resources are expressed using the symbolic :class:`~.pennylane.estimator.ops.Controlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.pennylane.estimator.ops.Z` class. Returns: list[:class:`~.pennylane.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 and num_zero_ctrl == 0: return [GateCount(resource_rep(CCZ))] ctrl_z = resource_rep( qre.Controlled, { "base_cmpr_op": resource_rep(qre.Z), "num_ctrl_wires": num_ctrl_wires + 1, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(ctrl_z)]
[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: This operation is self-inverse, thus when raised to even integer powers acts like the identity operator 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. """ return ( [GateCount(resource_rep(qre.Identity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep())] )
[docs] class CSWAP(ResourceOperator): r"""Resource class for the CSWAP gate. Args: wires (Sequence[int] | None): the wires the operation acts on Resources: The resources are taken from Figure 1d of `arXiv:2305.18128 <https://arxiv.org/abs/2305.18128>`_. The circuit which applies the SWAP operation on wires (1, 2) and controlled on wire (0) is defined as: .. code-block:: bash 0: ────╭●────┤ 1: ─╭X─├●─╭X─┤ 2: ─╰●─╰X─╰●─┤ .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.CSWAP`. **Example** The resources for this operation are computed using: >>> qml.estimator.CSWAP.resource_decomp() [(1 x Toffoli), (2 x CNOT)] """ num_wires = 3 def __init__(self, wires: WiresLike = None) -> None: if wires is not None and len(Wires(wires)) != self.num_wires: 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 the resources. Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: A compressed representation of the operator. """ return CompressedResourceOp(cls, cls.num_wires, {})
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Resources: The resources are taken from Figure 1d of `arXiv:2305.18128 <https://arxiv.org/abs/2305.18128>`_. The circuit which applies the SWAP operation on wires (1, 2) and controlled on wire (0) is defined as: .. code-block:: bash 0: ────╭●────┤ 1: ─╭X─├●─╭X─┤ 2: ─╰●─╰X─╰●─┤ 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. """ tof = resource_rep(Toffoli) cnot = resource_rep(CNOT) return [GateCount(tof), GateCount(cnot, 2)]
[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 originial 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: The resources are expressed using the symbolic :class:`~.pennylane.estimator.ops.Controlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.pennylane.estimator.ops.SWAP` class. Returns: list[:class:`~.pennylane.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. """ ctrl_swap = resource_rep( qre.Controlled, { "base_cmpr_op": resource_rep(qre.SWAP), "num_ctrl_wires": num_ctrl_wires + 1, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(ctrl_swap)]
[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: This operation is self-inverse, thus when raised to even integer powers acts like the identity operator 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. """ return ( [GateCount(resource_rep(qre.Identity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep())] )
[docs] class CCZ(ResourceOperator): r"""Resource class for the CCZ gate. Args: wires (Sequence[int] | None): the wire the operation acts on Resources: The resources are derived from the following identity: .. math:: \hat{Z} = \hat{H} \cdot \hat{X} \cdot \hat{H}. By replacing the ``X`` gate with a ``Toffoli`` we obtain the controlled decomposition. Specifically, the resources are defined as a ``Toffoli`` gate conjugated by a pair of ``Hadamard`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.CCZ`. **Example** The resources for this operation are computed using: >>> qml.estimator.CCZ.resource_decomp() [(1 x Toffoli), (2 x Hadamard)] """ num_wires = 3 def __init__(self, wires: WiresLike = None) -> None: if wires is not None and len(Wires(wires)) != self.num_wires: 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 the resources. Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: A compressed representation of the operator. """ return CompressedResourceOp(cls, cls.num_wires, {})
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Resources: The resources are derived from the following identity: .. math:: \hat{Z} = \hat{H} \cdot \hat{X} \cdot \hat{H}. By replacing the ``X`` gate with a ``Toffoli`` we obtain the controlled decomposition. Specifically, the resources are defined as a ``Toffoli`` gate conjugated by a pair of ``Hadamard`` gates. 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. """ toffoli = resource_rep(Toffoli) h = resource_rep(qre.Hadamard) return [GateCount(toffoli), GateCount(h, 2)]
[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 originial 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: The resources are expressed using the symbolic :class:`~.pennylane.estimator.ops.Controlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.pennylane.estimator.ops.Z` class. Returns: list[:class:`~.pennylane.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. """ ctrl_z = resource_rep( qre.Controlled, { "base_cmpr_op": resource_rep(qre.Z), "num_ctrl_wires": num_ctrl_wires + 2, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(ctrl_z)]
[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: This operation is self-inverse, thus when raised to even integer powers acts like the identity operator 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. """ return ( [GateCount(resource_rep(qre.Identity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep())] )
[docs] class CNOT(ResourceOperator): r"""Resource class for the CNOT gate. Args: wires (Sequence[int] | None): the wires the operation acts on Resources: The CNOT 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.CNOT`. """ num_wires = 2 def __init__(self, wires: WiresLike = None) -> None: if wires is not None and len(Wires(wires)) != self.num_wires: 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 the resources. Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: A compressed representation of the operator. """ return CompressedResourceOp(cls, cls.num_wires, {})
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Resources: The CNOT 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
[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 originial 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: The resources are expressed as one general :class:`~.pennylane.estimator.ops.MultiControlledX` gate. Returns: list[:class:`~.pennylane.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 and num_zero_ctrl == 0: return [GateCount(resource_rep(Toffoli))] mcx = resource_rep( MultiControlledX, { "num_ctrl_wires": num_ctrl_wires + 1, "num_zero_ctrl": num_zero_ctrl, }, ) return [ 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: This operation is self-inverse, thus when raised to even integer powers acts like the identity operator 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. """ return ( [GateCount(resource_rep(qre.Identity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep())] )
[docs] class TemporaryAND(ResourceOperator): r"""Resource class representing a `TemporaryAND` gate. Args: wires (Sequence[int] | None): the wires the operation acts on This gate was introduced in Fig 4 of `Babbush et al. (2018) <https://arxiv.org/pdf/1805.03662>`_ along with its adjoint. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.TemporaryAND`. **Example** The resources for this operation are computed using: >>> qml.estimator.TemporaryAND.resource_decomp() [(1 x Toffoli)] """ num_wires = 3 def __init__(self, wires: WiresLike = None) -> None: if wires is not None and len(Wires(wires)) != self.num_wires: 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 the resources. Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: A compressed representation of the operator. """ return CompressedResourceOp(cls, cls.num_wires, {})
[docs] @classmethod def resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Resources: The resources are obtained from Figure 4 of `Babbush et al. (2018) <https://arxiv.org/pdf/1805.03662>`_. 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. """ tof = resource_rep(Toffoli, {"elbow": "left"}) return [GateCount(tof)]
[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 resources are obtained from Figure 4 of `Babbush et al. (2018) <https://arxiv.org/pdf/1805.03662>`_. 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. """ h = resource_rep(qre.Hadamard) cz = resource_rep(CZ) return [GateCount(h), GateCount(cz)]
[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 resources are expressed as one general :class:`~.pennylane.estimator.ops.MultiControlledX` gate. Returns: list[:class:`~.pennylane.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. """ mcx = resource_rep( qre.MultiControlledX, { "num_ctrl_wires": num_ctrl_wires + 2, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(mcx)]
[docs] class Toffoli(ResourceOperator): r"""Resource class for the Toffoli gate. Args: wires (Sequence[int] | None): the subsystem the gate acts on elbow (str | None): String identifier to determine if this is a special type of Toffoli gate. Available options are `left`, `right`, and `None`. Resources: If `elbow` is provided, resources are obtained from Figure 4 of `Babbush et al. (2018) <https://arxiv.org/pdf/1805.03662>`_. If `elbow` is `None`, the resources are obtained from Figure 1 of `Jones (2012) <https://arxiv.org/pdf/1212.5069>`_. The circuit which applies the Toffoli gate on target wire 'target' with control wires ('c1', 'c2') is defined as: .. code-block:: bash c1: ─╭●────╭X──T†────────╭X────╭●───────────────╭●─┤ c2: ─│──╭X─│──╭●───T†─╭●─│──╭X─│────────────────╰Z─┤ aux1: ─╰X─│──│──╰X───T──╰X─│──│──╰X────────────────║─┤ aux2: ──H─╰●─╰●──T─────────╰●─╰●──H──S─╭●──H──┤↗├──║─┤ target: ─────────────────────────────────╰X──────║───║─┤ ╚═══╝ Specifically, the resources are defined as nine ``CNOT`` gates, three ``Hadamard`` gates, one ``CZ`` gate, one ``S`` gate, two ``T`` gates and two adjoint ``T`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.Toffoli`. **Example** The resources for this operation are computed using: >>> qml.estimator.Toffoli.resource_decomp() [Allocate(2), (9 x CNOT), (3 x Hadamard), (1 x S), (1 x CZ), (2 x T), (2 x Adjoint(T)), Deallocate(2)] """ num_wires = 3 resource_keys = {"elbow"} def __init__( self, elbow: Literal["left", "right"] | None = None, wires: WiresLike = None ) -> None: if wires is not None and len(Wires(wires)) != self.num_wires: raise ValueError(f"Expected {self.num_wires} wires, got {len(Wires(wires))}") self.elbow = elbow super().__init__(wires=wires)
[docs] @staticmethod def elbow_decomp(elbow: Literal["left", "right"] | None = "left"): """A function that prepares the resource decomposition obtained from Figure 4 of `Babbush et al. (2018) <https://arxiv.org/pdf/1805.03662>`_. Args: elbow (str | None): One of "left" or "right". Defaults to "left". Returns: list[:class:`~.estimator.resource_operator.GateCount`]: The resources of decomposing the elbow gates. """ gate_types = [] t = resource_rep(qre.T) t_dag = resource_rep( qre.Adjoint, {"base_cmpr_op": t}, ) h = resource_rep(qre.Hadamard) cnot = resource_rep(CNOT) s_dag = resource_rep( qre.Adjoint, {"base_cmpr_op": resource_rep(qre.S)}, ) cz = resource_rep(CZ) if elbow == "left": gate_types.append(GateCount(t, 2)) gate_types.append(GateCount(t_dag, 2)) gate_types.append(GateCount(cnot, 3)) gate_types.append(GateCount(s_dag)) if elbow == "right": gate_types.append(GateCount(h)) gate_types.append(GateCount(cz)) return gate_types
[docs] @classmethod def resource_decomp(cls, elbow: Literal["left", "right"] | None = None) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Resources: If `elbow` is provided, resources are obtained from Figure 4 of `arXiv:1805.03662 <https://arxiv.org/pdf/1805.03662>`_. If `elbow` is `None`, the resources are obtained from Figure 1 of `Jones (2012) <https://arxiv.org/pdf/1212.5069>`_. The circuit which applies the Toffoli gate on target wire 'target' with control wires ('c1', 'c2') is defined as: .. code-block:: bash c1: ─╭●────╭X──T†────────╭X────╭●───────────────╭●─┤ c2: ─│──╭X─│──╭●───T†─╭●─│──╭X─│────────────────╰Z─┤ aux1: ─╰X─│──│──╰X───T──╰X─│──│──╰X────────────────║─┤ aux2: ──H─╰●─╰●──T─────────╰●─╰●──H──S─╭●──H──┤↗├──║─┤ target: ─────────────────────────────────╰X──────║───║─┤ ╚═══╝ Specifically, the resources are defined as nine ``CNOT`` gates, three ``Hadamard`` gates, one ``CZ`` gate, one ``S`` gate, two ``T`` gates and two adjoint ``T`` gates. 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 elbow: return Toffoli.elbow_decomp(elbow) cnot = resource_rep(CNOT) t = resource_rep(qre.T) h = resource_rep(qre.Hadamard) s = resource_rep(qre.S) cz = resource_rep(CZ) t_dag = resource_rep(qre.Adjoint, {"base_cmpr_op": t}) return [ Allocate(2), GateCount(cnot, 9), GateCount(h, 3), GateCount(s), GateCount(cz), GateCount(t, 2), GateCount(t_dag, 2), Deallocate(2), ]
[docs] @classmethod def textbook_resource_decomp( cls, elbow: Literal["left", "right"] | None = None ) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Args: elbow (str | None): String identifier to determine if this is a special type of Toffoli gate (left or right elbow). Default value is `None`. Resources: If `elbow` is provided, resources are obtained from Figure 4 of `arXiv:1805.03662 <https://arxiv.org/pdf/1805.03662>`_. If `elbow` is `None`, the resources are taken from Figure 4.9 of `Nielsen, M. A., & Chuang, I. L. (2010) <https://www.cambridge.org/highereducation/books/quantum-computation-and-quantum-information/01E10196D0A682A6AEFFEA52D53BE9AE#overview>`_. The circuit is defined as: .. code-block:: bash 0: ───────────╭●───────────╭●────╭●──T──╭●─┤ 1: ────╭●─────│─────╭●─────│───T─╰X──T†─╰X─┤ 2: ──H─╰X──T†─╰X──T─╰X──T†─╰X──T──H────────┤ Specifically, the resources are defined as six :class:`~.CNOT` gates, two :class:`~.Hadamard` gates, four :class:`~.T` gates and three adjoint :class:`~.T` gates. 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 elbow: return Toffoli.elbow_decomp(elbow) cnot = resource_rep(CNOT) t = resource_rep(qre.T) h = resource_rep(qre.Hadamard) t_dag = resource_rep(qre.Adjoint, {"base_cmpr_op": t}) return [GateCount(cnot, 6), GateCount(h, 2), GateCount(t, 4), GateCount(t_dag, 3)]
@property def resource_params(self) -> dict: r"""Returns a dictionary containing the minimal information needed to compute the resources. Returns: A dictionary containing the resource parameters: * elbow (str | None): String identifier to determine if this is a special type of Toffoli gate (left or right elbow). """ return {"elbow": self.elbow}
[docs] @classmethod def resource_rep(cls, elbow: Literal["left", "right"] | None = None) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute the resources. Args: elbow (str | None): String identifier to determine if this is a special type of Toffoli gate (left or right elbow). Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: A compressed representation of the operator. """ return CompressedResourceOp(cls, cls.num_wires, {"elbow": elbow})
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict): 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 originial 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. """ elbow = target_resource_params.get("elbow") if elbow is None: return [GateCount(cls.resource_rep())] adj_elbow = "left" if elbow == "right" else "right" return [GateCount(cls.resource_rep(elbow=adj_elbow))]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict, ) -> 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): A dictionary containing the resource parameters of the target operator. Resources: The resources are expressed as one general :class:`~.pennylane.estimator.ops.MultiControlledX` gate. Returns: list[:class:`~.pennylane.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. """ mcx = resource_rep( qre.MultiControlledX, { "num_ctrl_wires": num_ctrl_wires + 2, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(mcx)]
[docs] @classmethod def pow_resource_decomp(cls, pow_z: int, target_resource_params: dict) -> 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): A dictionary containing the resource parameters of the target operator. Resources: This operation is self-inverse, thus when raised to even integer powers acts like the identity operator 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. """ elbow = target_resource_params.get("elbow") return ( [GateCount(resource_rep(qre.Identity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep(elbow=elbow))] )
[docs] class MultiControlledX(ResourceOperator): r"""Resource class for the MultiControlledX gate. Args: num_ctrl_wires (int | None): 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 wires (Sequence[int] | None): the wires this operation acts on Resources: The resources are obtained based on the unary iteration technique described in `Babbush et al. (2018) <https://arxiv.org/pdf/1805.03662>`_. Specifically, the resources are defined as the following rules: * If there are no control qubits, treat the operation as a :class:`~.pennylane.estimator.ops.X` gate. * If there is only one control qubit, treat the resources as a :class:`~.pennylane.estimator.ops.CNOT` gate. * If there are two control qubits, treat the resources as a :class:`~.pennylane.estimator.ops.Toffoli` gate. * If there are three or more control qubits (:math:`n`), the resources obtained based on the unary iteration technique described in `Babbush et al. (2018) <https://arxiv.org/pdf/1805.03662>`_. Specifically, it requires :math:`n - 2` clean qubits, and produces :math:`n - 2` elbow gates and a single :class:`~.pennylane.estimator.ops.Toffoli`. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.MultiControlledX`. **Example** The resources for this operation are computed using: >>> qml.estimator.MultiControlledX.resource_decomp(num_ctrl_wires=5, num_zero_ctrl=2) [(4 x X), Allocate(3), (3 x TemporaryAND), (3 x Adjoint(TemporaryAND)), (1 x Toffoli), Deallocate(3)] """ resource_keys = {"num_ctrl_wires", "num_zero_ctrl"} def __init__( self, num_ctrl_wires: int | None = None, num_zero_ctrl: int = 0, wires: WiresLike = None ) -> None: if num_ctrl_wires is None: if wires is None: raise ValueError("Must provide atleast one of `num_ctrl_wires` and `wires`.") num_ctrl_wires = len(wires) - 1 self.num_ctrl_wires = num_ctrl_wires self.num_zero_ctrl = num_zero_ctrl self.num_wires = num_ctrl_wires + 1 if wires is not None and len(Wires(wires)) != self.num_wires: 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: A dictionary containing the resource parameters: * 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 """ return { "num_ctrl_wires": self.num_ctrl_wires, "num_zero_ctrl": self.num_zero_ctrl, }
[docs] @classmethod def resource_rep(cls, num_ctrl_wires: int, num_zero_ctrl: int) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute the resources. 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 Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: the operator in a compressed representation """ num_wires = num_ctrl_wires + 1 return CompressedResourceOp( cls, num_wires, { "num_ctrl_wires": num_ctrl_wires, "num_zero_ctrl": num_zero_ctrl, }, )
[docs] @classmethod def resource_decomp(cls, num_ctrl_wires: int, num_zero_ctrl: int) -> list[GateCount]: r"""Returns a list representing the resources 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 Resources: The resources are obtained based on the unary iteration technique described in `Babbush et al. (2018) <https://arxiv.org/pdf/1805.03662>`_. Specifically, the resources are defined as the following rules: * If there are no control qubits, treat the operation as a :class:`~.pennylane.estimator.ops.X` gate. * If there is only one control qubit, treat the resources as a :class:`~.pennylane.estimator.ops.CNOT` gate. * If there are two control qubits, treat the resources as a :class:`~.pennylane.estimator.ops.Toffoli` gate. * If there are three or more control qubits (:math:`n`), the resources obtained based on the unary iteration technique described in `Babbush et al. (2018) <https://arxiv.org/pdf/1805.03662>`_. Specifically, it requires :math:`n - 2` clean qubits, and produces :math:`n - 2` elbow gates and a single :class:`~.pennylane.estimator.ops.Toffoli`. 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. """ gate_lst = [] x = resource_rep(qre.X) if num_ctrl_wires == 0: if num_zero_ctrl: return [] return [GateCount(x)] if num_zero_ctrl: gate_lst.append(GateCount(x, num_zero_ctrl * 2)) cnot = resource_rep(CNOT) if num_ctrl_wires == 1: gate_lst.append(GateCount(cnot)) return gate_lst toffoli = resource_rep(Toffoli) if num_ctrl_wires == 2: gate_lst.append(GateCount(toffoli)) return gate_lst l_elbow = resource_rep(TemporaryAND) r_elbow = resource_rep(qre.Adjoint, {"base_cmpr_op": l_elbow}) res = [ Allocate(num_ctrl_wires - 2), GateCount(l_elbow, num_ctrl_wires - 2), GateCount(r_elbow, num_ctrl_wires - 2), GateCount(toffoli, 1), Deallocate(num_ctrl_wires - 2), ] gate_lst.extend(res) return gate_lst
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict): 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 originial 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. """ num_ctrl_wires = target_resource_params.get("num_ctrl_wires") num_zero_ctrl = target_resource_params.get("num_zero_ctrl") return [GateCount(cls.resource_rep(num_ctrl_wires, num_zero_ctrl))]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: num_ctrl_wires (int): the number of control qubits of the operation num_zero_ctrl (int): The subset of control qubits of the operation, that are controlled when in the :math:`|0\rangle` state. target_resource_params (dict): A dictionary containing the resource parameters of the target operator. Resources: The resources are derived by combining the control qubits, control-values and into a single instance of ``MultiControlledX`` gate, controlled on the whole set of control-qubits. 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. """ base_ctrl_wires = target_resource_params.get("num_ctrl_wires") base_ctrl_zero = target_resource_params.get("num_zero_ctrl") return [ GateCount( cls.resource_rep( num_ctrl_wires + base_ctrl_wires, num_zero_ctrl + base_ctrl_zero, ) ) ]
[docs] @classmethod def pow_resource_decomp(cls, pow_z: int, target_resource_params: dict) -> 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): A dictionary containing the resource parameters of the target operator. Resources: This operation is self-inverse, thus when raised to even integer powers acts like the identity operator 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. """ num_ctrl_wires = target_resource_params.get("num_ctrl_wires") num_zero_ctrl = target_resource_params.get("num_zero_ctrl") return ( [GateCount(resource_rep(qre.Identity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep(num_ctrl_wires, num_zero_ctrl))] )
[docs] class CRX(ResourceOperator): r"""Resource class for the CRX gate. Args: wires (Sequence[int] | None): the wire the operation acts on precision (float | None): The error threshold for clifford plus T decomposition of the rotation gate. The default value is `None` which corresponds to using the precision stated in the config. Resources: The resources are taken from Figure 1b of `arXiv:2110.10292 <https://arxiv.org/abs/2110.10292>`_. In combination with the following identity: .. math:: \hat{RX} = \hat{H} \cdot \hat{RZ} \cdot \hat{H}, we can express the ``CRX`` gate as a ``CRZ`` gate conjugated by ``Hadamard`` gates. The expression for controlled-RZ gates is used as defined in the reference above. Specifically, the resources are defined as two ``CNOT`` gates, two ``Hadamard`` gates and two ``RZ`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.CRX`. **Example** The resources for this operation are computed using: >>> qml.estimator.CRX.resource_decomp() [(2 x CNOT), (2 x RZ), (2 x Hadamard)] """ resource_keys = {"precision"} num_wires = 2 def __init__(self, precision: float | None = None, wires: WiresLike = None) -> None: if wires is not None and len(Wires(wires)) != self.num_wires: raise ValueError(f"Expected {self.num_wires} wires, got {len(Wires(wires))}") self.precision = precision 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: A dictionary containing the resource parameters: * precision (float | None): the number of qubits the operation is controlled on """ return {"precision": self.precision}
[docs] @classmethod def resource_rep(cls, precision: float | None = None) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute the resources. Args: precision (float | None): The error threshold for the Clifford + T decomposition of this operation. Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: A compressed representation of the operator. """ return CompressedResourceOp(cls, cls.num_wires, {"precision": precision})
[docs] @classmethod def resource_decomp(cls, precision: float | None = None) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Args: precision (float | None): The error threshold for clifford plus T decomposition of the rotation gate. The default value is `None` which corresponds to using the epsilon stated in the config. Resources: The resources are taken from Figure 1b of `arXiv:2110.10292 <https://arxiv.org/abs/2110.10292>`_. In combination with the following identity: .. math:: \hat{RX} = \hat{H} \cdot \hat{RZ} \cdot \hat{H}, we can express the ``CRX`` gate as a ``CRZ`` gate conjugated by ``Hadamard`` gates. The expression for controlled-RZ gates is used as defined in the reference above. Specifically, the resources are defined as two ``CNOT`` gates, two ``Hadamard`` gates and two ``RZ`` gates. 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. """ h = resource_rep(qre.Hadamard) rz = resource_rep(qre.RZ, {"precision": precision}) cnot = resource_rep(CNOT) return [GateCount(cnot, 2), GateCount(rz, 2), GateCount(h, 2)]
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict): A dictionary containing the resource parameters of the target operator. Resources: The adjoint of a single qubit rotation changes the sign of the rotation angle, thus the resources of the adjoint operation result are same as the originial 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. """ precision = target_resource_params.get("precision") return [GateCount(cls.resource_rep(precision))]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict, ) -> 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): A dictionary containing the resource parameters of the target operator. Resources: The resources are expressed using the symbolic :class:`~.pennylane.estimator.ops.Controlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.pennylane.estimator.ops.RX` class. Returns: list[:class:`~.pennylane.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. """ precision = target_resource_params["precision"] ctrl_rx = resource_rep( qre.Controlled, { "base_cmpr_op": resource_rep(qre.RX, {"precision": precision}), "num_ctrl_wires": num_ctrl_wires + 1, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(ctrl_rx)]
[docs] @classmethod def pow_resource_decomp(cls, pow_z: int, target_resource_params: dict) -> 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): A dictionary containing the resource parameters of the target operator. Resources: Taking arbitrary powers of a single qubit rotation produces a sum of rotations. The resources simplify to just one total single qubit rotation. 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. """ precision = target_resource_params.get("precision") return [GateCount(cls.resource_rep(precision))]
[docs] class CRY(ResourceOperator): r"""Resource class for the CRY gate. Args: wires (Sequence[int] | None): the wire the operation acts on precision (float | None): The error threshold for clifford plus T decomposition of the rotation gate. The default value is `None` which corresponds to using the epsilon stated in the config. Resources: The resources are taken from Figure 1b of `arXiv:2110.10292 <https://arxiv.org/abs/2110.10292>`_. In combination with the following identity: .. math:: \hat{RY}(\theta) = \hat{X} \cdot \hat{RY}(- \theta) \cdot \hat{X}. By replacing the ``X`` gates with ``CNOT`` gates, we obtain a controlled-version of this identity. Thus we are able to constructively or destructively interfere the gates based on the value of the control qubit. Specifically, the resources are defined as two ``CNOT`` gates and two ``RY`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.CRY`. **Example** The resources for this operation are computed using: >>> qml.estimator.CRY.resource_decomp() [(2 x CNOT), (2 x RY)] """ resource_keys = {"precision"} num_wires = 2 def __init__(self, precision: float | None = None, wires: WiresLike = None) -> None: if wires is not None and len(Wires(wires)) != self.num_wires: raise ValueError(f"Expected {self.num_wires} wires, got {len(Wires(wires))}") self.precision = precision 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: A dictionary containing the resource parameters: * precision (float | None): the number of qubits the operation is controlled on """ return {"precision": self.precision}
[docs] @classmethod def resource_rep(cls, precision: float | None = None) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute the resources. Args: precision (float | None): The error threshold for the Clifford + T decomposition of this operation. Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: A compressed representation of the operator. """ return CompressedResourceOp(cls, cls.num_wires, {"precision": precision})
[docs] @classmethod def resource_decomp(cls, precision: float | None = None) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Args: precision (float | None): The error threshold for clifford plus T decomposition of the rotation gate. The default value is `None` which corresponds to using the epsilon stated in the config. Resources: The resources are taken from Figure 1b of `arXiv:2110.10292 <https://arxiv.org/abs/2110.10292>`_. In combination with the following identity: .. math:: \hat{RY}(\theta) = \hat{X} \cdot \hat{RY}(- \theta) \cdot \hat{X}. By replacing the ``X`` gates with ``CNOT`` gates, we obtain a controlled-version of this identity. Thus we are able to constructively or destructively interfere the gates based on the value of the control qubit. Specifically, the resources are defined as two ``CNOT`` gates and two ``RY`` gates. 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. """ cnot = resource_rep(CNOT) ry = resource_rep(qre.RY, {"precision": precision}) return [GateCount(cnot, 2), GateCount(ry, 2)]
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict): A dictionary containing the resource parameters of the target operator. Resources: The adjoint of a single qubit rotation changes the sign of the rotation angle, thus the resources of the adjoint operation result are same as the originial 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. """ precision = target_resource_params.get("precision") return [GateCount(cls.resource_rep(precision))]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict, ) -> 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): A dictionary containing the resource parameters of the target operator. Resources: The resources are expressed using the symbolic :class:`~.pennylane.estimator.ops.Controlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.pennylane.estimator.ops.RY` class. Returns: list[:class:`~.pennylane.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. """ precision = target_resource_params["precision"] ctrl_ry = resource_rep( qre.Controlled, { "base_cmpr_op": resource_rep(qre.RY, {"precision": precision}), "num_ctrl_wires": num_ctrl_wires + 1, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(ctrl_ry)]
[docs] @classmethod def pow_resource_decomp(cls, pow_z: int, target_resource_params: dict) -> 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): A dictionary containing the resource parameters of the target operator. Resources: Taking arbitrary powers of a single qubit rotation produces a sum of rotations. The resources simplify to just one total single qubit rotation. 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. """ precision = target_resource_params.get("precision") return [GateCount(cls.resource_rep(precision))]
[docs] class CRZ(ResourceOperator): r"""Resource class for the CRZ gate. Args: wires (Sequence[int] | None): the wire the operation acts on precision (float | None): The error threshold for clifford plus T decomposition of the rotation gate. The default value is `None` which corresponds to using the epsilon stated in the config. Resources: The resources are taken from Figure 1b of `arXiv:2110.10292 <https://arxiv.org/abs/2110.10292>`_. In combination with the following identity: .. math:: \hat{RZ}(\theta) = \hat{X} \cdot \hat{RZ}(- \theta) \cdot \hat{X}. By replacing the ``X`` gates with ``CNOT`` gates, we obtain a controlled-version of this identity. Thus we are able to constructively or destructively interfere the gates based on the value of the control qubit. Specifically, the resources are defined as two ``CNOT`` gates and two ``RZ`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.CRZ`. **Example** The resources for this operation are computed using: >>> qml.estimator.CRZ.resource_decomp() [(2 x CNOT), (2 x RZ)] """ resource_keys = {"precision"} num_wires = 2 def __init__(self, precision: float | None = None, wires: WiresLike = None) -> None: if wires is not None and len(Wires(wires)) != self.num_wires: raise ValueError(f"Expected {self.num_wires} wires, got {len(Wires(wires))}") self.precision = precision 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: A dictionary containing the resource parameters: * precision (float | None): the number of qubits the operation is controlled on """ return {"precision": self.precision}
[docs] @classmethod def resource_rep(cls, precision: float | None = None) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute the resources. Args: precision (float | None): The error threshold for the Clifford + T decomposition of this operation. Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: A compressed representation of the operator. """ return CompressedResourceOp(cls, cls.num_wires, {"precision": precision})
[docs] @classmethod def resource_decomp(cls, precision: float | None = None) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Args: precision (float | None): The error threshold for clifford plus T decomposition of the rotation gate. The default value is `None` which corresponds to using the epsilon stated in the config. Resources: The resources are taken from Figure 1b of `arXiv:2110.10292 <https://arxiv.org/abs/2110.10292>`_. In combination with the following identity: .. math:: \hat{RZ}(\theta) = \hat{X} \cdot \hat{RZ}(- \theta) \cdot \hat{X}. By replacing the ``X`` gates with ``CNOT`` gates, we obtain a controlled-version of this identity. Thus we are able to constructively or destructively interfere the gates based on the value of the control qubit. Specifically, the resources are defined as two ``CNOT`` gates and two ``RZ`` gates. 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. """ cnot = resource_rep(CNOT) rz = resource_rep(qre.RZ, {"precision": precision}) return [GateCount(cnot, 2), GateCount(rz, 2)]
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict): A dictionary containing the resource parameters of the target operator. Resources: The adjoint of a single qubit rotation changes the sign of the rotation angle, thus the resources of the adjoint operation result are same as the originial 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. """ precision = target_resource_params.get("precision") return [GateCount(cls.resource_rep(precision))]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict, ) -> 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): A dictionary containing the resource parameters of the target operator. Resources: The resources are expressed using the symbolic :class:`~.pennylane.estimator.ops.Controlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.pennylane.estimator.ops.RZ` class. Returns: list[:class:`~.pennylane.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. """ precision = target_resource_params["precision"] ctrl_rz = resource_rep( qre.Controlled, { "base_cmpr_op": resource_rep(qre.RZ, {"precision": precision}), "num_ctrl_wires": num_ctrl_wires + 1, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(ctrl_rz)]
[docs] @classmethod def pow_resource_decomp(cls, pow_z: int, target_resource_params: dict) -> 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): A dictionary containing the resource parameters of the target operator. Resources: Taking arbitrary powers of a single qubit rotation produces a sum of rotations. The resources simplify to just one total single qubit rotation. 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. """ precision = target_resource_params.get("precision") return [GateCount(cls.resource_rep(precision))]
[docs] class CRot(ResourceOperator): r"""Resource class for the CRot gate. Args: wires (Sequence[int] | None): the wire the operation acts on precision (float | None): The error threshold for Clifford + T decomposition of the rotation gate. The default value is `None` which corresponds to using the epsilon stated in the config. Resources: The resources are taken from Figure 1b of `arXiv:2110.10292 <https://arxiv.org/abs/2110.10292>`_. In combination with the following identity: .. math:: \begin{align} \hat{RZ}(\theta) = \hat{X} \cdot \hat{RZ}(- \theta) \cdot \hat{X}, \\ \hat{RY}(\theta) = \hat{X} \cdot \hat{RY}(- \theta) \cdot \hat{X}. \end{align} This identity is applied along with some clever choices for the angle values to combine rotation; the final circuit takes the form: .. code-block:: bash ctrl: ─────╭●─────────╭●─────────┤ trgt: ──RZ─╰X──RZ──RY─╰X──RY──RZ─┤ .. seealso:: The corresponding PennyLane operation :class:`~.CRot`. **Example** The resources for this operation are computed using: >>> qml.estimator.CRot.resource_decomp() [(2 x CNOT), (3 x RZ), (2 x RY)] """ resource_keys = {"precision"} num_wires = 2 def __init__(self, precision: float | None = None, wires: WiresLike = None) -> None: if wires is not None and len(Wires(wires)) != self.num_wires: raise ValueError(f"Expected {self.num_wires} wires, got {len(Wires(wires))}") self.precision = precision 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: A dictionary containing the resource parameters: * precision (float | None): the number of qubits the operation is controlled on """ return {"precision": self.precision}
[docs] @classmethod def resource_rep(cls, precision: float | None = None) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute the resources. Args: precision (float | None): The error threshold for the Clifford + T decomposition of this operation. Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: A compressed representation of the operator. """ return CompressedResourceOp(cls, cls.num_wires, {"precision": precision})
[docs] @classmethod def resource_decomp(cls, precision: float | None = None) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Args: precision (float | None): The error threshold for clifford plus T decomposition of the rotation gate. The default value is `None` which corresponds to using the epsilon stated in the config. Resources: The resources are taken from Figure 1b of `arXiv:2110.10292 <https://arxiv.org/abs/2110.10292>`_. In combination with the following identity: .. math:: \begin{align} \hat{RZ}(\theta) = \hat{X} \cdot \hat{RZ}(- \theta) \cdot \hat{X}, \\ \hat{RY}(\theta) = \hat{X} \cdot \hat{RY}(- \theta) \cdot \hat{X}. \end{align} This identity is applied along with some clever choices for the angle values to combine rotation; the final circuit takes the form: .. code-block:: bash ctrl: ─────╭●─────────╭●─────────┤ trgt: ──RZ─╰X──RZ──RY─╰X──RY──RZ─┤ 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. """ cnot = resource_rep(CNOT) rz = resource_rep(qre.RZ, {"precision": precision}) ry = resource_rep(qre.RY, {"precision": precision}) return [GateCount(cnot, 2), GateCount(rz, 3), GateCount(ry, 2)]
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict): A dictionary containing the resource parameters of the target operator. Resources: The adjoint of a general rotation flips the sign of the rotation angle, thus the resources of the adjoint operation result are same as the originial 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. """ precision = target_resource_params.get("precision") return [GateCount(cls.resource_rep(precision))]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict, ) -> 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): A dictionary containing the resource parameters of the target operator. Resources: The resources are expressed using the symbolic :class:`~.pennylane.estimator.ops.Controlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.pennylane.estimator.ops.Rot` class. Returns: list[:class:`~.pennylane.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. """ precision = target_resource_params["precision"] ctrl_rot = resource_rep( qre.Controlled, { "base_cmpr_op": resource_rep(qre.Rot, {"precision": precision}), "num_ctrl_wires": num_ctrl_wires + 1, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(ctrl_rot)]
[docs] @classmethod def pow_resource_decomp(cls, pow_z: int, target_resource_params: dict) -> 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): A dictionary containing the resource parameters of the target operator. Resources: Taking arbitrary powers of a general single qubit rotation produces a sum of rotations. The resources simplify to just one total single qubit rotation. 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. """ precision = target_resource_params.get("precision") return [GateCount(cls.resource_rep(precision))]
[docs] class ControlledPhaseShift(ResourceOperator): r"""Resource class for the ControlledPhaseShift gate. Args: wires (Sequence[int] | None): the wire the operation acts on precision (float | None): The error threshold for Clifford + T decomposition of the rotation gate. The default value is `None` which corresponds to using the epsilon stated in the config. Resources: The resources are derived using the fact that a ``PhaseShift`` gate is identical to the ``RZ`` gate up to some global phase. Furthermore, a controlled global phase simplifies to a ``PhaseShift`` gate. This gives rise to the following identity: .. math:: CR_\phi(\phi) = (R_\phi(\phi/2) \otimes I) \cdot CNOT \cdot (I \otimes R_\phi(-\phi/2)) \cdot CNOT \cdot (I \otimes R_\phi(\phi/2)) Specifically, the resources are defined as two ``CNOT`` gates and three ``RZ`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.ControlledPhaseShift`. **Example** The resources for this operation are computed using: >>> qml.estimator.ControlledPhaseShift.resource_decomp() [(2 x CNOT), (3 x RZ)] """ resource_keys = {"precision"} num_wires = 2 def __init__(self, precision: float | None = None, wires: WiresLike = None) -> None: if wires is not None and len(Wires(wires)) != self.num_wires: raise ValueError(f"Expected {self.num_wires} wires, got {len(Wires(wires))}") self.precision = precision super().__init__(wires=wires) @property def resource_params(self): r"""Returns a dictionary containing the minimal information needed to compute the resources. Returns: dict: A dictionary containing the resource parameters: * precision (float | None): the number of qubits the operation is controlled on """ return {"precision": self.precision}
[docs] @classmethod def resource_rep(cls, precision: float | None = None) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the operator that are needed to compute the resources. Args: precision (float | None): The error threshold for the Clifford + T decomposition of this operation. Returns: :class:`~.pennylane.estimator.resource_operator.CompressedResourceOp`: A compressed representation of the operator. """ return CompressedResourceOp(cls, cls.num_wires, {"precision": precision})
[docs] @classmethod def resource_decomp(cls, precision: float | None = None) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Args: precision (float | None): The error threshold for clifford plus T decomposition of the rotation gate. The default value is `None` which corresponds to using the epsilon stated in the config. Resources: The resources are derived using the fact that a ``PhaseShift`` gate is identical to the ``RZ`` gate up to some global phase. Furthermore, a controlled global phase simplifies to a ``PhaseShift`` gate. This gives rise to the following identity: .. math:: CR_\phi(\phi) = (R_\phi(\phi/2) \otimes I) \cdot CNOT \cdot (I \otimes R_\phi(-\phi/2)) \cdot CNOT \cdot (I \otimes R_\phi(\phi/2)) Specifically, the resources are defined as two ``CNOT`` gates and three ``RZ`` gates. .. seealso:: The corresponding PennyLane operation :class:`~.pennylane.ControlledPhaseShift`. 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. **Example** The resources for this operation are computed using: >>> qml.estimator.ControlledPhaseShift.resource_decomp() [(2 x CNOT), (3 x RZ)] """ cnot = resource_rep(CNOT) rz = resource_rep(qre.RZ, {"precision": precision}) return [GateCount(cnot, 2), GateCount(rz, 3)]
[docs] @classmethod def adjoint_resource_decomp(cls, target_resource_params: dict) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: target_resource_params (dict): A dictionary containing the resource parameters of the target operator. Resources: The adjoint of a phase shift just flips the sign of the phase angle, thus the resources of the adjoint operation result are same as the originial 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. """ precision = target_resource_params.get("precision") return [GateCount(cls.resource_rep(precision))]
[docs] @classmethod def controlled_resource_decomp( cls, num_ctrl_wires: int, num_zero_ctrl: int, target_resource_params: dict, ) -> 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): A dictionary containing the resource parameters of the target operator. Resources: The resources are expressed using the symbolic :class:`~.pennylane.estimator.ops.Controlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.pennylane.estimator.ops.PhaseShift` class. Returns: list[:class:`~.pennylane.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. """ precision = target_resource_params["precision"] ctrl_ps = resource_rep( qre.Controlled, { "base_cmpr_op": resource_rep(qre.PhaseShift, {"precision": precision}), "num_ctrl_wires": num_ctrl_wires + 1, "num_zero_ctrl": num_zero_ctrl, }, ) return [GateCount(ctrl_ps)]
[docs] @classmethod def pow_resource_decomp(cls, pow_z: int, target_resource_params: dict) -> 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): A dictionary containing the resource parameters of the target operator. Resources: Taking arbitrary powers of a phase shift produces a sum of shifts. The resources simplify to just one total phase shift operator. 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. """ precision = target_resource_params.get("precision") return [GateCount(cls.resource_rep(precision))]