Source code for qdk_chemistry.algorithms.amplitude_amplification.amplitude_amplification

r"""QDK/Chemistry amplitude amplification."""

# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from typing import Any

from qdk_chemistry.algorithms.base import Algorithm, AlgorithmFactory
from qdk_chemistry.data import Circuit, Settings
from qdk_chemistry.data.circuit import QsharpFactoryData
from qdk_chemistry.utils import Logger
from qdk_chemistry.utils.qsharp import QSHARP_UTILS

__all__: list[str] = [
    "AmplitudeAmplification",
    "AmplitudeAmplificationFactory",
    "AmplitudeAmplificationSettings",
]


[docs] class AmplitudeAmplificationSettings(Settings): r"""Settings for amplitude amplification."""
[docs] def __init__(self): """Initialize the settings for amplitude amplification.""" super().__init__() self._set_default( "rounds", "int", 1, "Number of Grover amplitude amplification rounds.", )
[docs] class AmplitudeAmplification(Algorithm): r"""Build an amplitude-amplified circuit. Each round flips a flag on the good subspace and reflects about the prepared state, taking probability :math:`a` to :math:`\sin^2((2k+1)\arcsin\sqrt{a})` after :math:`k` rounds. That falls again past the first maximum, so pick ``rounds`` from an estimate of :math:`a`. Reference: L. Lin, *Lecture Notes on Quantum Algorithms for Scientific Computation*, arXiv:2201.08309, Chapter 2. """
[docs] def __init__(self): """Initialize amplitude amplification.""" Logger.trace_entering() super().__init__() self._settings = AmplitudeAmplificationSettings()
[docs] def type_name(self) -> str: """Return the algorithm type name as amplitude_amplification.""" return "amplitude_amplification"
[docs] def name(self) -> str: """Return the algorithm name as qdk_base.""" return "qdk_base"
def _run_impl( self, state_prep_oracle: Circuit, good_state_oracle: Circuit, ) -> Circuit: r"""Build an amplitude-amplified circuit. Args: state_prep_oracle: Prepares the initial state. Must carry an adjointable Q# operation. good_state_oracle: Flips a flag qubit on the good subspace. Must carry an adjointable Q# operation. Returns: The amplified circuit, measuring the whole register. Its ``qsharp_op`` is the same amplification without measurement, for callers that append their own. Raises: TypeError: If either circuit carries no adjointable Q# operation. ValueError: If the ``rounds`` setting is negative. RuntimeError: If the state preparation cannot be resource estimated for its width. """ Logger.trace_entering() operation = state_prep_oracle._qsharp_op # noqa: SLF001 if operation is None: raise TypeError("Amplitude amplification requires a state prep oracle qsharp operation.") good_state_operation = good_state_oracle._qsharp_op # noqa: SLF001 if good_state_operation is None: raise TypeError("Amplitude amplification requires a good state oracle qsharp operation.") num_qubits = state_prep_oracle.num_qubits if num_qubits is None: try: num_qubits = int(state_prep_oracle.estimate().logical_counts["numQubits"]) except Exception as error: raise RuntimeError( "Could not read the register width from a resource estimate of the state prep oracle." ) from error rounds = int(self._settings.get("rounds")) if rounds < 0: raise ValueError(f"rounds must be nonnegative. Got {rounds}.") amplification = QSHARP_UTILS.AmplitudeAmplification parameters: dict[str, Any] = { "statePrepOracle": operation, "goodStateOracle": good_state_operation, "rounds": rounds, "numQubits": num_qubits, } Logger.info(f"Amplified circuit uses {2 * rounds + 1} state preparations.") return Circuit( qsharp_factory=QsharpFactoryData(program=amplification.MakeAmplifiedCircuit, parameter=parameters), qsharp_op=amplification.MakeAmplifiedStateOp(operation, good_state_operation, rounds), )
[docs] class AmplitudeAmplificationFactory(AlgorithmFactory): """Factory class for creating AmplitudeAmplification instances."""
[docs] def __init__(self): """Initialize the AmplitudeAmplificationFactory.""" super().__init__()
[docs] def algorithm_type_name(self) -> str: """Return the algorithm type name as amplitude_amplification.""" return "amplitude_amplification"
[docs] def default_algorithm_name(self) -> str: """Return qdk_base as the default algorithm name.""" return "qdk_base"