Source code for pennylane.labs.resource_estimation.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."""

import pennylane.labs.resource_estimation as re
from pennylane.labs.resource_estimation.qubit_manager import AllocWires, FreeWires
from pennylane.labs.resource_estimation.resource_operator import (
    CompressedResourceOp,
    GateCount,
    ResourceOperator,
    resource_rep,
)

# pylint: disable=arguments-differ,too-many-ancestors,too-many-arguments,too-many-positional-arguments,unused-argument


[docs] class ResourceCH(ResourceOperator): r"""Resource class for the CH gate. Args: wires (Sequence[int], optional): the wires the operation acts on Resources: The resources are derived from the following identities (as presented in this `blog post <https://quantumcomputing.stackexchange.com/questions/15734/how-to-construct-a-controlled-hadamard-gate-using-single-qubit-gates-and-control>`_): .. 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 :class:`~.ResourceRY`, two :class:`~.ResourceHadamard` and one :class:`~.ResourceCNOT` gates. .. seealso:: :class:`~.CH` **Example** The resources for this operation are computed using: >>> re.ResourceCH.resource_decomp() [(2 x Hadamard), (2 x RY), (1 x CNOT)] """ num_wires = 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, {})
[docs] @classmethod def default_resource_decomp(cls, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. Resources: The resources are derived from the following identities (as presented in this `blog post <https://quantumcomputing.stackexchange.com/questions/15734/how-to-construct-a-controlled-hadamard-gate-using-single-qubit-gates-and-control>`_): .. 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 :class:`~.ResourceRY`, two :class:`~.ResourceHadamard` and one :class:`~.ResourceCNOT` gates. """ ry = resource_rep(re.ResourceRY) h = resource_rep(re.ResourceHadamard) cnot = resource_rep(ResourceCNOT) return [GateCount(h, 2), GateCount(ry, 2), GateCount(cnot, 1)]
[docs] @classmethod def default_adjoint_resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Resources: This operation is self-adjoint, so the resources of the adjoint operation results in the original operation. Returns: list[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 default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): the number of qubits the operation is controlled on ctrl_num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state Resources: The resources are expressed using the symbolic :class:`~.ResourceControlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.ResourceHadamard` class. Returns: list[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( re.ResourceControlled, { "base_cmpr_op": resource_rep(re.ResourceHadamard), "num_ctrl_wires": ctrl_num_ctrl_wires + 1, "num_ctrl_values": ctrl_num_ctrl_values, }, ) return [GateCount(ctrl_h)]
[docs] @classmethod def default_pow_resource_decomp(cls, pow_z) -> 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 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[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(re.ResourceIdentity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep())] )
[docs] class ResourceCY(ResourceOperator): r"""Resource class for the CY gate. Args: wires (Sequence[int], optional): 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 :class:`~.ResourceX` gate with a :class:`~.ResourceCNOT` we obtain the controlled decomposition. Specifically, the resources are defined as a :class:`~.ResourceCNOT` gate conjugated by a pair of :class:`~.ResourceS` gates. .. seealso:: :class:`~.CY` **Example** The resources for this operation are computed using: >>> re.ResourceCY.resource_decomp() [(1 x CNOT), (1 x S), (1 x Adjoint(S))] """ num_wires = 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, {})
[docs] @classmethod def default_resource_decomp(cls, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. Resources: The resources are derived from the following identity: .. math:: \hat{Y} = \hat{S} \cdot \hat{X} \cdot \hat{S}^{\dagger}. By replacing the :class:`~.ResourceX` gate with a :class:`~.ResourceCNOT` we obtain the controlled decomposition. Specifically, the resources are defined as a :class:`~.ResourceCNOT` gate conjugated by a pair of :class:`~.ResourceS` gates. """ cnot = resource_rep(ResourceCNOT) s = resource_rep(re.ResourceS) s_dag = resource_rep(re.ResourceAdjoint, {"base_cmpr_op": s}) return [GateCount(cnot), GateCount(s), GateCount(s_dag)]
[docs] @classmethod def default_adjoint_resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Resources: This operation is self-adjoint, so the resources of the adjoint operation results in the original operation. Returns: list[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 default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): the number of qubits the operation is controlled on ctrl_num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state Resources: The resources are expressed using the symbolic :class:`~.ResourceControlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.ResourceY` class. Returns: list[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( re.ResourceControlled, { "base_cmpr_op": resource_rep(re.ResourceY), "num_ctrl_wires": ctrl_num_ctrl_wires + 1, "num_ctrl_values": ctrl_num_ctrl_values, }, ) return [GateCount(ctrl_y)]
[docs] @classmethod def default_pow_resource_decomp(cls, pow_z) -> 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 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[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(re.ResourceIdentity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep())] )
[docs] class ResourceCZ(ResourceOperator): r"""Resource class for the CZ gate. Args: wires (Sequence[int], optional): 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 :class:`~.ResourceX` gate with a :class:`~.ResourceCNOT` we obtain the controlled decomposition. Specifically, the resources are defined as a :class:`~.ResourceCNOT` gate conjugated by a pair of :class:`~.ResourceHadamard` gates. .. seealso:: :class:`~.CZ` **Example** The resources for this operation are computed using: >>> re.ResourceCZ.resource_decomp() [(1 x CNOT), (2 x Hadamard)] """ num_wires = 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, {})
[docs] @classmethod def default_resource_decomp(cls, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. Resources: The resources are derived from the following identity: .. math:: \hat{Z} = \hat{H} \cdot \hat{X} \cdot \hat{H}. By replacing the :class:`~.ResourceX` gate with a :class:`~.ResourceCNOT` we obtain the controlled decomposition. Specifically, the resources are defined as a :class:`~.ResourceCNOT` gate conjugated by a pair of :class:`~.ResourceHadamard` gates. """ cnot = resource_rep(ResourceCNOT) h = resource_rep(re.ResourceHadamard) return [GateCount(cnot), GateCount(h, 2)]
[docs] @classmethod def default_adjoint_resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Resources: This operation is self-adjoint, so the resources of the adjoint operation results in the original operation. Returns: list[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 default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): the number of qubits the operation is controlled on ctrl_num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state Resources: The resources are expressed using the symbolic :class:`~.ResourceControlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.ResourceZ` class. Returns: list[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 ctrl_num_ctrl_wires == 1 and ctrl_num_ctrl_values == 0: return [GateCount(resource_rep(re.ResourceCCZ))] ctrl_z = resource_rep( re.ResourceControlled, { "base_cmpr_op": resource_rep(re.ResourceZ), "num_ctrl_wires": ctrl_num_ctrl_wires + 1, "num_ctrl_values": ctrl_num_ctrl_values, }, ) return [GateCount(ctrl_z)]
[docs] @classmethod def default_pow_resource_decomp(cls, pow_z) -> 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 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[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(re.ResourceIdentity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep())] )
[docs] class ResourceCSWAP(ResourceOperator): r"""Resource class for the CSWAP gate. Args: wires (Sequence[int], optional): the wires the operation acts on Resources: The resources are taken from Figure 1d of `arXiv:2305.18128 <https://arxiv.org/pdf/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:: :class:`~.CSWAP` **Example** The resources for this operation are computed using: >>> re.ResourceCSWAP.resource_decomp() [(1 x Toffoli), (2 x CNOT)] """ num_wires = 3 @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, {})
[docs] @classmethod def default_resource_decomp(cls, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. Resources: The resources are taken from Figure 1d of `arXiv:2305.18128 <https://arxiv.org/pdf/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─╰●─┤ """ tof = resource_rep(ResourceToffoli) cnot = resource_rep(ResourceCNOT) return [GateCount(tof), GateCount(cnot, 2)]
[docs] @classmethod def default_adjoint_resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Resources: This operation is self-adjoint, so the resources of the adjoint operation results in the original operation. Returns: list[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 default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): the number of qubits the operation is controlled on ctrl_num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state Resources: The resources are expressed using the symbolic :class:`~.ResourceControlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.ResourceSWAP` class. Returns: list[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( re.ResourceControlled, { "base_cmpr_op": resource_rep(re.ResourceSWAP), "num_ctrl_wires": ctrl_num_ctrl_wires + 1, "num_ctrl_values": ctrl_num_ctrl_values, }, ) return [GateCount(ctrl_swap)]
[docs] @classmethod def default_pow_resource_decomp(cls, pow_z) -> 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 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[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(re.ResourceIdentity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep())] )
[docs] class ResourceCCZ(ResourceOperator): r"""Resource class for the CCZ gate. Args: wires (Sequence[int], optional): the subsystem the gate 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 :class:`~.ResourceX` gate with a :class:`~.ResourceToffoli` we obtain the controlled decomposition. Specifically, the resources are defined as a :class:`~.ResourceToffoli` gate conjugated by a pair of :class:`~.ResourceHadamard` gates. .. seealso:: :class:`~.CCZ` **Example** The resources for this operation are computed using: >>> re.ResourceCCZ.resource_decomp() [(1 x Toffoli), (2 x Hadamard)] """ num_wires = 3 @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, {})
[docs] @classmethod def default_resource_decomp(cls, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. Resources: The resources are derived from the following identity: .. math:: \hat{Z} = \hat{H} \cdot \hat{X} \cdot \hat{H}. By replacing the :class:`~.ResourceX` gate with a :class:`~.ResourceToffoli` we obtain the controlled decomposition. Specifically, the resources are defined as a :class:`~.ResourceToffoli` gate conjugated by a pair of :class:`~.ResourceHadamard` gates. """ toffoli = resource_rep(ResourceToffoli) h = resource_rep(re.ResourceHadamard) return [GateCount(toffoli), GateCount(h, 2)]
[docs] @classmethod def default_adjoint_resource_decomp(cls, **kwargs): r"""Returns a list representing the resources for the adjoint of the operator. Resources: This operation is self-adjoint, so the resources of the adjoint operation results in the original operation. Returns: list[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 default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): the number of qubits the operation is controlled on ctrl_num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state Resources: The resources are expressed using the symbolic :class:`~.ResourceControlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.ResourceZ` class. Returns: list[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( re.ResourceControlled, { "base_cmpr_op": resource_rep(re.ResourceZ), "num_ctrl_wires": ctrl_num_ctrl_wires + 2, "num_ctrl_values": ctrl_num_ctrl_values, }, ) return [GateCount(ctrl_z)]
[docs] @classmethod def default_pow_resource_decomp(cls, pow_z) -> 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 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[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(re.ResourceIdentity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep())] )
[docs] class ResourceCNOT(ResourceOperator): r"""Resource class for the CNOT gate. Args: wires (Sequence[int], optional): 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 :code:`ResourcesNotDefined` error. .. seealso:: :class:`~.CNOT` """ num_wires = 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, {})
[docs] @classmethod def default_resource_decomp(cls, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. 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 :code:`ResourcesNotDefined` error. Raises: ResourcesNotDefined: This gate is fundamental, no further decomposition defined. """ raise re.ResourcesNotDefined
[docs] @classmethod def default_adjoint_resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Resources: This operation is self-adjoint, so the resources of the adjoint operation results in the original operation. Returns: list[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 default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): the number of qubits the operation is controlled on ctrl_num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state Resources: The resources are expressed as one general :class:`~.ResourceMultiControlledX` gate. Returns: list[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 ctrl_num_ctrl_wires == 1 and ctrl_num_ctrl_values == 0: return [GateCount(resource_rep(ResourceToffoli))] mcx = resource_rep( ResourceMultiControlledX, { "num_ctrl_wires": ctrl_num_ctrl_wires + 1, "num_ctrl_values": ctrl_num_ctrl_values, }, ) return [ GateCount(mcx), ]
[docs] @classmethod def default_pow_resource_decomp(cls, pow_z) -> 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 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[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(re.ResourceIdentity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep())] )
[docs] class ResourceTempAND(ResourceOperator): r"""Resource class representing a temporary `AND`-gate. Args: wires (Sequence[int], optional): the wires the operation acts on This gate was introduced in Fig 4 of `Babbush 2018 <https://arxiv.org/pdf/1805.03662>`_ along with it's adjoint (uncompute). **Example** The resources for this operation are computed using: >>> re.ResourceTempAND.resource_decomp() [(1 x Toffoli)] """ num_wires = 3 @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, {})
[docs] @classmethod def default_resource_decomp(cls, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. Resources: The resources are obtained from Figure 4 of `Babbush 2018 <https://arxiv.org/pdf/1805.03662>`_. Returns: list[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(ResourceToffoli, {"elbow": "left"}) return [GateCount(tof)]
[docs] @classmethod def default_adjoint_resource_decomp(cls) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Resources: The resources are obtained from Figure 4 of `Babbush 2018 <https://arxiv.org/pdf/1805.03662>`_. Returns: list[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(re.ResourceHadamard) cz = resource_rep(ResourceCZ) return [GateCount(h), GateCount(cz)]
[docs] @classmethod def default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): the number of qubits the operation is controlled on ctrl_num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state Resources: The resources are expressed as one general :class:`~.ResourceMultiControlledX` gate. Returns: list[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( re.ResourceMultiControlledX, { "num_ctrl_wires": ctrl_num_ctrl_wires + 2, "num_ctrl_values": ctrl_num_ctrl_values, }, ) return [GateCount(mcx)]
[docs] class ResourceToffoli(ResourceOperator): r"""Resource class for the Toffoli gate. Args: wires (Sequence[int], optional): the subsystem the gate acts on elbow (Union[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 `Babbush 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 :class:`~.ResourceCNOT` gates, three :class:`~.ResourceHadamard` gates, one :class:`~.ResourceCZ` gate, one :class:`~.ResourceS` gate, two :class:`~.ResourceT` gates and two adjoint :class:`~.ResourceT` gates. .. seealso:: :class:`~.Toffoli` **Example** The resources for this operation are computed using: >>> re.ResourceToffoli.resource_decomp() [AllocWires(2), (9 x CNOT), (3 x Hadamard), (1 x S), (1 x CZ), (2 x T), (2 x Adjoint(T)), FreeWires(2)] """ num_wires = 3 resource_keys = {"elbow"} def __init__(self, elbow=None, wires=None) -> None: self.elbow = elbow super().__init__(wires=wires)
[docs] @staticmethod def elbow_decomp(elbow="left"): """A function that prepares the resource decomposition obtained from Figure 4 of `Babbush 2018 <https://arxiv.org/pdf/1805.03662>`_. Args: elbow (str, optional): One of "left" or "right". Defaults to "left". Returns: list[GateCount]: The resources of decomposing the elbow gates. """ gate_types = [] t = resource_rep(re.ResourceT) t_dag = resource_rep( re.ResourceAdjoint, {"base_cmpr_op": t}, ) h = resource_rep(re.ResourceHadamard) cnot = resource_rep(ResourceCNOT) s_dag = resource_rep( re.ResourceAdjoint, {"base_cmpr_op": resource_rep(re.ResourceS)}, ) cz = resource_rep(ResourceCZ) 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 default_resource_decomp(cls, elbow=None, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. 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 :class:`~.ResourceCNOT` gates, three :class:`~.ResourceHadamard` gates, one :class:`~.ResourceCZ` gate, one :class:`~.ResourceS` gate, two :class:`~.ResourceT` gates and two adjoint :class:`~.ResourceT` gates. """ if elbow: return ResourceToffoli.elbow_decomp(elbow) cnot = resource_rep(ResourceCNOT) t = resource_rep(re.ResourceT) h = resource_rep(re.ResourceHadamard) s = resource_rep(re.ResourceS) cz = resource_rep(ResourceCZ) t_dag = resource_rep( re.ResourceAdjoint, {"base_cmpr_op": t}, ) return [ AllocWires(2), GateCount(cnot, 9), GateCount(h, 3), GateCount(s), GateCount(cz), GateCount(t, 2), GateCount(t_dag, 2), FreeWires(2), ]
[docs] @classmethod def textbook_resource_decomp(cls, elbow=None, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. 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:`~.ResourceCNOT` gates, two :class:`~.ResourceHadamard` gates, four :class:`~.ResourceT` gates and three adjoint :class:`~.ResourceT` gates. """ if elbow: return ResourceToffoli.elbow_decomp(elbow) cnot = resource_rep(ResourceCNOT) t = resource_rep(re.ResourceT) h = resource_rep(re.ResourceHadamard) t_dag = resource_rep( re.ResourceAdjoint, {"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 (Union[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=None) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the Operator that are needed to compute the resources.""" return CompressedResourceOp(cls, {"elbow": elbow})
[docs] @classmethod def default_adjoint_resource_decomp(cls, elbow=None) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Resources: This operation is self-adjoint, so the resources of the adjoint operation results in the original operation. Returns: list[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 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 default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values, elbow=None, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): the number of qubits the operation is controlled on ctrl_num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state elbow (Union[str, None]): String identifier to determine if this is a special type of Toffoli gate (left or right elbow). Default value is `None`. Resources: The resources are expressed as one general :class:`~.ResourceMultiControlledX` gate. Returns: list[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( re.ResourceMultiControlledX, { "num_ctrl_wires": ctrl_num_ctrl_wires + 2, "num_ctrl_values": ctrl_num_ctrl_values, }, ) return [GateCount(mcx)]
[docs] @classmethod def default_pow_resource_decomp(cls, pow_z, elbow=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 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[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(re.ResourceIdentity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep(elbow=elbow))] )
[docs] class ResourceMultiControlledX(ResourceOperator): r"""Resource class for the MultiControlledX gate. Args: num_ctrl_wires (int): the number of qubits the operation is controlled on num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state wires (Sequence[int], optional): the wires this operation acts on Resources: The resources are obtained based on the unary iteration technique described in `Babbush 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:`~.labs.resource_estimation.ResourceX` gate. * If there is only one control qubit, treat the resources as a :class:`~.labs.resource_estimation.ResourceCNOT` gate. * If there are two control qubits, treat the resources as a :class:`~.labs.resource_estimation.ResourceToffoli` gate. * If there are three or more control qubits (:math:`n`), the resources obtained based on the unary iteration technique described in `Babbush 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:`~.labs.resource_estimation.ResourceToffoli`. .. seealso:: :class:`~.MultiControlledX` **Example** The resources for this operation are computed using: >>> re.ResourceMultiControlledX.resource_decomp(num_ctrl_wires=5, num_ctrl_values=2) [(4 x X), AllocWires(3), (3 x TempAND), (3 x Toffoli), (1 x Toffoli), FreeWires(3)] """ resource_keys = {"num_ctrl_wires", "num_ctrl_values"} def __init__(self, num_ctrl_wires, num_ctrl_values, wires=None) -> None: self.num_ctrl_wires = num_ctrl_wires self.num_ctrl_values = num_ctrl_values self.num_wires = num_ctrl_wires + 1 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_ctrl_values (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_ctrl_values": self.num_ctrl_values, }
[docs] @classmethod def resource_rep(cls, num_ctrl_wires, num_ctrl_values) -> 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_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state Returns: CompressedResourceOp: the operator in a compressed representation """ return CompressedResourceOp( cls, { "num_ctrl_wires": num_ctrl_wires, "num_ctrl_values": num_ctrl_values, }, )
[docs] @classmethod def default_resource_decomp( cls, num_ctrl_wires, num_ctrl_values, **kwargs, # pylint: disable=unused-argument ) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. Args: num_ctrl_wires (int): the number of qubits the operation is controlled on num_ctrl_values (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 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:`~.labs.resource_estimation.ResourceX` gate. * If there is only one control qubit, treat the resources as a :class:`~.labs.resource_estimation.ResourceCNOT` gate. * If there are two control qubits, treat the resources as a :class:`~.labs.resource_estimation.ResourceToffoli` gate. * If there are three or more control qubits (:math:`n`), the resources obtained based on the unary iteration technique described in `Babbush 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:`~.labs.resource_estimation.ResourceToffoli`. """ gate_lst = [] x = resource_rep(re.ResourceX) if num_ctrl_wires == 0: if num_ctrl_values: return [] return [GateCount(x)] if num_ctrl_values: gate_lst.append(GateCount(x, num_ctrl_values * 2)) cnot = resource_rep(ResourceCNOT) if num_ctrl_wires == 1: gate_lst.append(GateCount(cnot)) return gate_lst toffoli = resource_rep(ResourceToffoli) if num_ctrl_wires == 2: gate_lst.append(GateCount(toffoli)) return gate_lst l_elbow = resource_rep(ResourceTempAND) r_elbow = resource_rep(re.ResourceAdjoint, {"base_cmpr_op": l_elbow}) res = [ AllocWires(num_ctrl_wires - 2), GateCount(l_elbow, num_ctrl_wires - 2), GateCount(r_elbow, num_ctrl_wires - 2), GateCount(toffoli, 1), FreeWires(num_ctrl_wires - 2), ] gate_lst.extend(res) return gate_lst
[docs] @classmethod def default_adjoint_resource_decomp(cls, num_ctrl_wires, num_ctrl_values) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Args: num_ctrl_wires (int): the number of qubits the operation is controlled on num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state Resources: This operation is self-adjoint, so the resources of the adjoint operation results in the original operation. Returns: list[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(num_ctrl_wires, num_ctrl_values))]
[docs] @classmethod def default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values, num_ctrl_wires, num_ctrl_values, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): The number of control qubits to further control the base controlled operation upon. ctrl_num_ctrl_values (int): The subset of those control qubits, which further control the base controlled operation, which are controlled when in the :math:`|0\rangle` state. num_ctrl_wires (int): the number of control qubits of the operation num_ctrl_values (int): The subset of control qubits of the operation, that are controlled when in the :math:`|0\rangle` state. Resources: The resources are derived by combining the control qubits, control-values and into a single instance of :class:`~.ResourceMultiControlledX` gate, controlled on the whole set of control-qubits. Returns: list[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( ctrl_num_ctrl_wires + num_ctrl_wires, ctrl_num_ctrl_values + num_ctrl_values, ) ) ]
[docs] @classmethod def default_pow_resource_decomp(cls, pow_z, num_ctrl_wires, num_ctrl_values) -> 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 num_ctrl_wires (int): the number of qubits the operation is controlled on num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state 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[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(re.ResourceIdentity))] if pow_z % 2 == 0 else [GateCount(cls.resource_rep(num_ctrl_wires, num_ctrl_values))] )
[docs] class ResourceCRX(ResourceOperator): r"""Resource class for the CRX gate. Args: wires (Sequence[int], optional): the wire the operation acts on eps (float, optional): 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 `Gheorghiu, V., Mosca, M. & Mukhopadhyay <https://arxiv.org/pdf/2110.10292>`_. In combination with the following identity: .. math:: \hat{RX} = \hat{H} \cdot \hat{RZ} \cdot \hat{H}, we can express the :code:`CRX` gate as a :code:`CRZ` gate conjugated by :code:`Hadamard` gates. The expression for controlled-RZ gates is used as defined in the reference above. Specifically, the resources are defined as two :class:`~.ResourceCNOT` gates, two :class:`~.ResourceHadamard` gates and two :class:`~.ResourceRZ` gates. .. seealso:: :class:`~.CRX` **Example** The resources for this operation are computed using: >>> re.ResourceCRX.resource_decomp() [(2 x CNOT), (2 x RZ), (2 x Hadamard)] """ num_wires = 2 def __init__(self, eps=None, wires=None) -> None: self.eps = eps super().__init__(wires=wires) @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: * eps (Union[float, None]): error threshold for the approximation """ return {"eps": self.eps}
[docs] @classmethod def resource_rep(cls, eps=None) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the Operator that are needed to compute the resources.""" return CompressedResourceOp(cls, {"eps": eps})
[docs] @classmethod def default_resource_decomp(cls, eps=None, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. Args: eps (float, optional): 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 `Gheorghiu, V., Mosca, M. & Mukhopadhyay <https://arxiv.org/pdf/2110.10292>`_. In combination with the following identity: .. math:: \hat{RX} = \hat{H} \cdot \hat{RZ} \cdot \hat{H}, we can express the :code:`CRX` gate as a :code:`CRZ` gate conjugated by :code:`Hadamard` gates. The expression for controlled-RZ gates is used as defined in the reference above. Specifically, the resources are defined as two :class:`~.ResourceCNOT` gates, two :class:`~.ResourceHadamard` gates and two :class:`~.ResourceRZ` gates. """ h = resource_rep(re.ResourceHadamard) rz = resource_rep(re.ResourceRZ, {"eps": eps}) cnot = resource_rep(ResourceCNOT) return [GateCount(cnot, 2), GateCount(rz, 2), GateCount(h, 2)]
[docs] @classmethod def default_adjoint_resource_decomp(cls, eps=None) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Resources: The adjoint of a single qubit rotation changes the sign of the rotation angle, thus the resources of the adjoint operation result in the original operation. Returns: list[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(eps))]
[docs] @classmethod def default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values, eps=None, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): the number of qubits the operation is controlled on ctrl_num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state eps (float, optional): 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 expressed using the symbolic :class:`~.ResourceControlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.ResourceRX` class. Returns: list[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_rx = resource_rep( re.ResourceControlled, { "base_cmpr_op": resource_rep(re.ResourceRX, {"eps": eps}), "num_ctrl_wires": ctrl_num_ctrl_wires + 1, "num_ctrl_values": ctrl_num_ctrl_values, }, ) return [GateCount(ctrl_rx)]
[docs] @classmethod def default_pow_resource_decomp(cls, pow_z, eps=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 eps (float, optional): 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: 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[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(eps))]
[docs] class ResourceCRY(ResourceOperator): r"""Resource class for the CRY gate. Args: wires (Sequence[int], optional): the wire the operation acts on eps (float, optional): 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 `Gheorghiu, V., Mosca, M. & Mukhopadhyay <https://arxiv.org/pdf/2110.10292>`_. In combination with the following identity: .. math:: \hat{RY}(\theta) = \hat{X} \cdot \hat{RY}(- \theta) \cdot \hat{X}. By replacing the :class:`~.ResourceX` gates with :class:`~.ResourceCNOT` 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 :class:`~.ResourceCNOT` gates and two :class:`~.ResourceRY` gates. .. seealso:: :class:`~.CRY` **Example** The resources for this operation are computed using: >>> re.ResourceCRY.resource_decomp() [(2 x CNOT), (2 x RY)] """ num_wires = 2 def __init__(self, eps=None, wires=None) -> None: self.eps = eps super().__init__(wires=wires) @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: * eps (Union[float, None]): error threshold for the approximation """ return {"eps": self.eps}
[docs] @classmethod def resource_rep(cls, eps=None) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the Operator that are needed to compute the resources.""" return CompressedResourceOp(cls, {"eps": eps})
[docs] @classmethod def default_resource_decomp(cls, eps=None, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. Args: eps (float, optional): 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 `Gheorghiu, V., Mosca, M. & Mukhopadhyay <https://arxiv.org/pdf/2110.10292>`_. In combination with the following identity: .. math:: \hat{RY}(\theta) = \hat{X} \cdot \hat{RY}(- \theta) \cdot \hat{X}. By replacing the :code:`X` gates with :code:`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 :class:`~.ResourceCNOT` gates and two :class:`~.ResourceRY` gates. """ cnot = resource_rep(ResourceCNOT) ry = resource_rep(re.ResourceRY, {"eps": eps}) return [GateCount(cnot, 2), GateCount(ry, 2)]
[docs] @classmethod def default_adjoint_resource_decomp(cls, eps=None) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Resources: The adjoint of a single qubit rotation changes the sign of the rotation angle, thus the resources of the adjoint operation result in the original operation. Returns: list[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(eps))]
[docs] @classmethod def default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values, eps=None, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): the number of qubits the operation is controlled on ctrl_num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state eps (float, optional): 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 expressed using the symbolic :class:`~.ResourceControlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.ResourceRY` class. Returns: list[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_ry = resource_rep( re.ResourceControlled, { "base_cmpr_op": resource_rep(re.ResourceRY, {"eps": eps}), "num_ctrl_wires": ctrl_num_ctrl_wires + 1, "num_ctrl_values": ctrl_num_ctrl_values, }, ) return [GateCount(ctrl_ry)]
[docs] @classmethod def default_pow_resource_decomp(cls, pow_z, eps=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 eps (float, optional): 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: 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[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(eps))]
[docs] class ResourceCRZ(ResourceOperator): r"""Resource class for the CRZ gate. Args: wires (Sequence[int], optional): the wire the operation acts on eps (float, optional): 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 `Gheorghiu, V., Mosca, M. & Mukhopadhyay <https://arxiv.org/pdf/2110.10292>`_. In combination with the following identity: .. math:: \hat{RZ}(\theta) = \hat{X} \cdot \hat{RZ}(- \theta) \cdot \hat{X}. By replacing the :code:`X` gates with :code:`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 :class:`~.ResourceCNOT` gates and two :class:`~.ResourceRZ` gates. .. seealso:: :class:`~.CRZ` **Example** The resources for this operation are computed using: >>> re.ResourceCRZ.resource_decomp() [(2 x CNOT), (2 x RZ)] """ num_wires = 2 def __init__(self, eps=None, wires=None) -> None: self.eps = eps super().__init__(wires=wires) @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: * eps (Union[float, None]): error threshold for the approximation """ return {"eps": self.eps}
[docs] @classmethod def resource_rep(cls, eps=None) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the Operator that are needed to compute the resources.""" return CompressedResourceOp(cls, {"eps": eps})
[docs] @classmethod def default_resource_decomp(cls, eps=None, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. Args: eps (float, optional): 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 `Gheorghiu, V., Mosca, M. & Mukhopadhyay <https://arxiv.org/pdf/2110.10292>`_. In combination with the following identity: .. math:: \hat{RZ}(\theta) = \hat{X} \cdot \hat{RZ}(- \theta) \cdot \hat{X}. By replacing the :code:`X` gates with :code:`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 :class:`~.ResourceCNOT` gates and two :class:`~.ResourceRZ` gates. """ cnot = resource_rep(ResourceCNOT) rz = resource_rep(re.ResourceRZ, {"eps": eps}) return [GateCount(cnot, 2), GateCount(rz, 2)]
[docs] @classmethod def default_adjoint_resource_decomp(cls, eps=None) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Resources: The adjoint of a single qubit rotation changes the sign of the rotation angle, thus the resources of the adjoint operation result in the original operation. Returns: list[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(eps))]
[docs] @classmethod def default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values, eps=None, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): the number of qubits the operation is controlled on ctrl_num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state eps (float, optional): 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 expressed using the symbolic :class:`~.ResourceControlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.ResourceRZ` class. Returns: list[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_rz = resource_rep( re.ResourceControlled, { "base_cmpr_op": resource_rep(re.ResourceRZ, {"eps": eps}), "num_ctrl_wires": ctrl_num_ctrl_wires + 1, "num_ctrl_values": ctrl_num_ctrl_values, }, ) return [GateCount(ctrl_rz)]
[docs] @classmethod def default_pow_resource_decomp(cls, pow_z, eps=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 eps (float, optional): 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: 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[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(eps))]
[docs] class ResourceCRot(ResourceOperator): r"""Resource class for the CRot gate. Args: wires (Sequence[int], optional): the wire the operation acts on eps (float, optional): 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 `Gheorghiu, V., Mosca, M. & Mukhopadhyay <https://arxiv.org/pdf/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:: :class:`~.CRot` **Example** The resources for this operation are computed using: >>> re.ResourceCRot.resource_decomp() [(2 x CNOT), (3 x RZ), (2 x RY)] """ num_wires = 2 def __init__(self, eps=None, wires=None) -> None: self.eps = eps super().__init__(wires=wires) @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: * eps (Union[float, None]): error threshold for the approximation """ return {"eps": self.eps}
[docs] @classmethod def resource_rep(cls, eps=None) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the Operator that are needed to compute the resources.""" return CompressedResourceOp(cls, {"eps": eps})
[docs] @classmethod def default_resource_decomp(cls, eps=None, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Each GateCount object specifies a gate type and its total occurrence count. Args: eps (float, optional): 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 `Gheorghiu, V., Mosca, M. & Mukhopadhyay <https://arxiv.org/pdf/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─┤ """ cnot = resource_rep(ResourceCNOT) rz = resource_rep(re.ResourceRZ, {"eps": eps}) ry = resource_rep(re.ResourceRY, {"eps": eps}) return [GateCount(cnot, 2), GateCount(rz, 3), GateCount(ry, 2)]
[docs] @classmethod def default_adjoint_resource_decomp(cls, eps=None) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Resources: The adjoint of a general rotation flips the sign of the rotation angle, thus the resources of the adjoint operation result in the original operation. Returns: list[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(eps))]
[docs] @classmethod def default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values, eps=None, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): the number of qubits the operation is controlled on ctrl_num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state eps (float, optional): 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 expressed using the symbolic :class:`~.ResourceControlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.ResourceRot` class. Returns: list[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_rot = resource_rep( re.ResourceControlled, { "base_cmpr_op": resource_rep(re.ResourceRot, {"eps": eps}), "num_ctrl_wires": ctrl_num_ctrl_wires + 1, "num_ctrl_values": ctrl_num_ctrl_values, }, ) return [GateCount(ctrl_rot)]
[docs] @classmethod def default_pow_resource_decomp(cls, pow_z, eps=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 eps (float, optional): 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: 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[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(eps))]
[docs] class ResourceControlledPhaseShift(ResourceOperator): r"""Resource class for the ControlledPhaseShift gate. Args: wires (Sequence[int], optional): the wire the operation acts on eps (float, optional): 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 :class:`~.ResourcePhaseShift` gate is identical to the :class:`~.ResourceRZ` gate up to some global phase. Furthermore, a controlled global phase simplifies to a :class:`~.ResourcePhaseShift` 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 :class:`~.ResourceCNOT` gates and three :class:`~.ResourceRZ` gates. .. seealso:: :class:`~.ControlledPhaseShift` **Example** The resources for this operation are computed using: >>> re.ResourceControlledPhaseShift.resource_decomp() [(2 x CNOT), (3 x RZ)] """ num_wires = 2 def __init__(self, eps=None, wires=None) -> None: self.eps = eps super().__init__(wires=wires) @property def resource_params(self): r"""Returns a dictionary containing the minimal information needed to compute the resources. Returns: A dictionary containing the resource parameters: * eps (Union[float, None]): error threshold for the approximation """ return {"eps": self.eps}
[docs] @classmethod def resource_rep(cls, eps=None) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the Operator that are needed to compute the resources.""" return CompressedResourceOp(cls, {"eps": eps})
[docs] @classmethod def default_resource_decomp(cls, eps=None, **kwargs) -> list[GateCount]: r"""Returns a list of GateCount objects representing the resources of the operator. Args: eps (float, optional): 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 :class:`~.ResourcePhaseShift` gate is identical to the :class:`~.ResourceRZ` gate up to some global phase. Furthermore, a controlled global phase simplifies to a :class:`~.ResourcePhaseShift` 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 :class:`~.ResourceCNOT` gates and three :class:`~.ResourceRZ` gates. .. seealso:: :class:`~.ControlledPhaseShift` **Example** The resources for this operation are computed using: >>> re.ResourceControlledPhaseShift.resource_decomp() [(2 x CNOT), (3 x RZ)] """ cnot = resource_rep(ResourceCNOT) rz = resource_rep(re.ResourceRZ, {"eps": eps}) return [GateCount(cnot, 2), GateCount(rz, 3)]
[docs] @classmethod def default_adjoint_resource_decomp(cls, eps=None) -> list[GateCount]: r"""Returns a list representing the resources for the adjoint of the operator. Resources: The adjoint of a phase shift just flips the sign of the phase angle, thus the resources of the adjoint operation result in the original operation. Returns: list[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(eps))]
[docs] @classmethod def default_controlled_resource_decomp( cls, ctrl_num_ctrl_wires, ctrl_num_ctrl_values, eps=None, ) -> list[GateCount]: r"""Returns a list representing the resources for a controlled version of the operator. Args: ctrl_num_ctrl_wires (int): the number of qubits the operation is controlled on ctrl_num_ctrl_values (int): the number of control qubits, that are controlled when in the :math:`|0\rangle` state eps (float, optional): 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 expressed using the symbolic :class:`~.ResourceControlled`. The resources are computed according to the :code:`controlled_resource_decomp()` of the base :class:`~.ResourcePhaseShift` class. Returns: list[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_ps = resource_rep( re.ResourceControlled, { "base_cmpr_op": resource_rep(re.ResourcePhaseShift, {"eps": eps}), "num_ctrl_wires": ctrl_num_ctrl_wires + 1, "num_ctrl_values": ctrl_num_ctrl_values, }, ) return [GateCount(ctrl_ps)]
[docs] @classmethod def default_pow_resource_decomp(cls, pow_z, eps=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 eps (float, optional): 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: Taking arbitrary powers of a phase shift produces a sum of shifts. The resources simplify to just one total phase shift operator. Returns: list[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(eps))]