Source code for pennylane.labs.resource_estimation.ops.op_math.symbolic

# Copyright 2024 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
r"""Resource operators for symbolic operations."""
from collections import defaultdict
from typing import Dict

import pennylane.labs.resource_estimation as re
from pennylane.ops.op_math.adjoint import AdjointOperation
from pennylane.ops.op_math.controlled import ControlledOp
from pennylane.ops.op_math.pow import PowOperation

# pylint: disable=too-many-ancestors,arguments-differ,protected-access,too-many-arguments,too-many-positional-arguments


[docs]class ResourceAdjoint(AdjointOperation, re.ResourceOperator): """Resource class for the Adjoint symbolic operation.""" @classmethod def _resource_decomp( cls, base_class, base_params, **kwargs ) -> Dict[re.CompressedResourceOp, int]: try: return base_class.adjoint_resource_decomp(**base_params) except re.ResourcesNotDefined: gate_types = defaultdict(int) decomp = base_class.resources(**base_params, **kwargs) for gate, count in decomp.items(): rep = cls.resource_rep(gate.op_type, gate.params) gate_types[rep] = count return gate_types
[docs] def resource_params(self) -> dict: return {"base_class": type(self.base), "base_params": self.base.resource_params()}
[docs] @classmethod def resource_rep(cls, base_class, base_params) -> re.CompressedResourceOp: return re.CompressedResourceOp(cls, {"base_class": base_class, "base_params": base_params})
[docs] @staticmethod def adjoint_resource_decomp(base_class, base_params) -> Dict[re.CompressedResourceOp, int]: return {base_class.resource_rep(**base_params): 1}
[docs] @staticmethod def tracking_name(base_class, base_params) -> str: base_name = base_class.tracking_name(**base_params) return f"Adjoint({base_name})"
[docs]class ResourceControlled(ControlledOp, re.ResourceOperator): """Resource class for the Controlled symbolic operation.""" @classmethod def _resource_decomp( cls, base_class, base_params, num_ctrl_wires, num_ctrl_values, num_work_wires, **kwargs ) -> Dict[re.CompressedResourceOp, int]: try: return base_class.controlled_resource_decomp( num_ctrl_wires, num_ctrl_values, num_work_wires, **base_params ) except re.ResourcesNotDefined: pass gate_types = defaultdict(int) if num_ctrl_values == 0: decomp = base_class.resources(**base_params, **kwargs) for gate, count in decomp.items(): rep = cls.resource_rep(gate.op_type, gate.params, num_ctrl_wires, 0, num_work_wires) gate_types[rep] = count return gate_types no_control = cls.resource_rep(base_class, base_params, num_ctrl_wires, 0, num_work_wires) x = re.ResourceX.resource_rep() gate_types[no_control] = 1 gate_types[x] = 2 * num_ctrl_values return gate_types
[docs] def resource_params(self) -> dict: return { "base_class": type(self.base), "base_params": self.base.resource_params(), "num_ctrl_wires": len(self.control_wires), "num_ctrl_values": len([val for val in self.control_values if not val]), "num_work_wires": len(self.work_wires), }
[docs] @classmethod def resource_rep( cls, base_class, base_params, num_ctrl_wires, num_ctrl_values, num_work_wires ) -> re.CompressedResourceOp: return re.CompressedResourceOp( cls, { "base_class": base_class, "base_params": base_params, "num_ctrl_wires": num_ctrl_wires, "num_ctrl_values": num_ctrl_values, "num_work_wires": num_work_wires, }, )
[docs] @classmethod def controlled_resource_decomp( cls, outer_num_ctrl_wires, outer_num_ctrl_values, outer_num_work_wires, base_class, base_params, num_ctrl_wires, num_ctrl_values, num_work_wires, ) -> Dict[re.CompressedResourceOp, int]: return { cls.resource_rep( base_class, base_params, outer_num_ctrl_wires + num_ctrl_wires, outer_num_ctrl_values + num_ctrl_values, outer_num_work_wires + num_work_wires, ): 1 }
[docs] @staticmethod def tracking_name(base_class, base_params, num_ctrl_wires, num_ctrl_values, num_work_wires): base_name = base_class.tracking_name(**base_params) return f"C({base_name},{num_ctrl_wires},{num_ctrl_values},{num_work_wires})"
[docs]class ResourcePow(PowOperation, re.ResourceOperator): """Resource class for the Pow symbolic operation.""" @classmethod def _resource_decomp( cls, base_class, z, base_params, **kwargs ) -> Dict[re.CompressedResourceOp, int]: try: return base_class.pow_resource_decomp(z, **base_params) except re.ResourcesNotDefined: pass try: gate_types = defaultdict(int) decomp = base_class.resources(**base_params, **kwargs) for gate, count in decomp.items(): rep = cls.resource_rep(gate.op_type, z, gate.params) gate_types[rep] = count return gate_types except re.ResourcesNotDefined: pass return {base_class.resource_rep(**base_params): z}
[docs] def resource_params(self) -> dict: return { "base_class": type(self.base), "z": self.z, "base_params": self.base.resource_params(), }
[docs] @classmethod def resource_rep(cls, base_class, z, base_params) -> re.CompressedResourceOp: return re.CompressedResourceOp( cls, {"base_class": base_class, "z": z, "base_params": base_params} )
[docs] @classmethod def pow_resource_decomp( cls, z0, base_class, z, base_params ) -> Dict[re.CompressedResourceOp, int]: return {cls.resource_rep(base_class, z0 * z, base_params): 1}
[docs] @staticmethod def tracking_name(base_class, z, base_params) -> str: base_name = base_class.tracking_name(**base_params) return f"Pow({base_name}, {z})"