Source code for pennylane.labs.resource_estimation.templates.stateprep

# 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 state preparation templates."""
import math

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


# pylint: disable=arguments-differ, unused-argument
[docs] class ResourceUniformStatePrep(ResourceOperator): r"""Resource class for preparing a uniform superposition. This operation prepares a uniform superposition over a given number of basis states. The uniform superposition is defined as: .. math:: \frac{1}{\sqrt{l}} \sum_{i=0}^{l} |i\rangle where :math:`l` is the number of states. This operation uses ``Hadamard`` gates to create the uniform superposition when the number of states is a power of two. If the number of states is not a power of two, amplitude amplification technique defined in `arXiv:1805.03662 <https://arxiv.org/pdf/1805.03662>`_ is used. Args: num_states (int): the number of states in the uniform superposition wires (Sequence[int], optional): the wires the operation acts on Resources: The resources are obtained from Figure 12 in `arXiv:1805.03662 <https://arxiv.org/pdf/1805.03662>`_. The circuit uses amplitude amplification to prepare a uniform superposition over :math:`l` basis states. **Example** The resources for this operation are computed using: >>> unif_state_prep = plre.ResourceUniformStatePrep(10) >>> print(plre.estimate_resources(unif_state_prep)) --- Resources: --- Total qubits: 5 Total gates : 124 Qubit breakdown: clean qubits: 1, dirty qubits: 0, algorithmic qubits: 4 Gate breakdown: {'Hadamard': 16, 'X': 12, 'CNOT': 4, 'Toffoli': 4, 'T': 88} """ resource_keys = {"num_states"} def __init__(self, num_states, wires=None): self.num_states = num_states k = (num_states & -num_states).bit_length() - 1 L = num_states // (2**k) if L == 1: self.num_wires = k else: self.num_wires = k + int(math.ceil(math.log2(L))) 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: * num_states (int): the number of states over which the uniform superposition is being prepared """ return {"num_states": self.num_states}
[docs] @classmethod def resource_rep(cls, num_states: int) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the Operator that are needed to compute the resources. Returns: CompressedResourceOp: the operator in a compressed representation """ return CompressedResourceOp(cls, {"num_states": num_states})
[docs] @classmethod def default_resource_decomp(cls, num_states, **kwargs): r"""Returns a list representing the resources of the operator. Each object in the list represents a gate and the number of times it occurs in the circuit. Args: num_states (int): the number of states over which the uniform superposition is being prepared Resources: The resources are obtained from Figure 12 in `arXiv:1805.03662 <https://arxiv.org/pdf/1805.03662>`_. The circuit uses amplitude amplification to prepare a uniform superposition over :math:`l` basis states. 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. """ gate_lst = [] k = (num_states & -num_states).bit_length() - 1 L = num_states // (2**k) if L == 1: gate_lst.append(GateCount(resource_rep(plre.ResourceHadamard), k)) return gate_lst logl = int(math.ceil(math.log2(L))) gate_lst.append(GateCount(resource_rep(plre.ResourceHadamard), k + 3 * logl)) gate_lst.append( GateCount( resource_rep(plre.ResourceIntegerComparator, {"value": L, "register_size": logl}), 1 ) ) gate_lst.append(GateCount(resource_rep(plre.ResourceRZ), 2)) gate_lst.append( GateCount( resource_rep( plre.ResourceAdjoint, { "base_cmpr_op": resource_rep( plre.ResourceIntegerComparator, {"value": L, "register_size": logl} ) }, ), 1, ) ) return gate_lst
[docs] class ResourceAliasSampling(ResourceOperator): r"""Resource class for preparing a state using coherent alias sampling. Args: num_coeffs (int): the number of unique coefficients in the state precision (float): the precision with which the coefficients are loaded wires (Sequence[int], optional): the wires the operation acts on Resources: The resources are obtained from Section III D in `arXiv:1805.03662 <https://arxiv.org/pdf/1805.03662>`_. The circuit uses coherent alias sampling to prepare a state with the given coefficients. **Example** The resources for this operation are computed using: >>> alias_sampling = plre.ResourceAliasSampling(num_coeffs=100) >>> print(plre.estimate_resources(alias_sampling)) --- Resources: --- Total qubits: 81 Total gates : 6.157E+3 Qubit breakdown: clean qubits: 6, dirty qubits: 68, algorithmic qubits: 7 Gate breakdown: {'Hadamard': 730, 'X': 479, 'CNOT': 4.530E+3, 'Toffoli': 330, 'T': 88} """ resource_keys = {"num_coeffs", "precision"} def __init__(self, num_coeffs, precision=None, wires=None): self.num_coeffs = num_coeffs self.precision = precision self.num_wires = int(math.ceil(math.log2(num_coeffs))) 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: * num_coeffs (int): the number of unique coefficients in the state * precision (float): the precision with which the coefficients are loaded """ return {"num_coeffs": self.num_coeffs, "precision": self.precision}
[docs] @classmethod def resource_rep(cls, num_coeffs, precision=None) -> CompressedResourceOp: r"""Returns a compressed representation containing only the parameters of the Operator that are needed to compute the resources. Returns: CompressedResourceOp: the operator in a compressed representation """ return CompressedResourceOp(cls, {"num_coeffs": num_coeffs, "precision": precision})
[docs] @classmethod def default_resource_decomp(cls, num_coeffs, precision=None, **kwargs) -> list[GateCount]: r"""Returns a list representing the resources of the operator. Each object in the list represents a gate and the number of times it occurs in the circuit. Args: num_coeffs (int): the number of unique coefficients in the state precision (float): the precision with which the coefficients are loaded Resources: The resources are obtained from Section III D in `arXiv:1805.03662 <https://arxiv.org/pdf/1805.03662>`_. The circuit uses coherent alias sampling to prepare a state with the given coefficients. 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. """ gate_lst = [] logl = int(math.ceil(math.log2(num_coeffs))) precision = precision or kwargs["config"]["precision_alias_sampling"] num_prec_wires = abs(math.floor(math.log2(precision))) gate_lst.append(AllocWires(logl + 2 * num_prec_wires + 1)) gate_lst.append( GateCount(resource_rep(plre.ResourceUniformStatePrep, {"num_states": num_coeffs}), 1) ) gate_lst.append(GateCount(resource_rep(plre.ResourceHadamard), num_prec_wires)) gate_lst.append( GateCount( resource_rep( plre.ResourceQROM, {"num_bitstrings": num_coeffs, "size_bitstring": logl + num_prec_wires}, ), 1, ) ) gate_lst.append( GateCount( resource_rep( plre.ResourceRegisterComparator, {"first_register": num_prec_wires, "second_register": num_prec_wires}, ), 1, ) ) gate_lst.append(GateCount(resource_rep(plre.ResourceCSWAP), logl)) return gate_lst