"""QDK/Chemistry phase estimation abstractions and utilities."""
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
from abc import abstractmethod
from qdk_chemistry.algorithms.base import Algorithm, AlgorithmFactory
from qdk_chemistry.algorithms.circuit_executor.base import CircuitExecutor
from qdk_chemistry.algorithms.time_evolution.builder.base import TimeEvolutionBuilder
from qdk_chemistry.algorithms.time_evolution.controlled_circuit_mapper.base import (
ControlledEvolutionCircuitMapper,
)
from qdk_chemistry.data import (
Circuit,
ControlledTimeEvolutionUnitary,
QpeResult,
QuantumErrorProfile,
QubitHamiltonian,
Settings,
TimeEvolutionUnitary,
)
__all__: list[str] = ["PhaseEstimation", "PhaseEstimationFactory", "PhaseEstimationSettings"]
[docs]
class PhaseEstimationSettings(Settings):
"""Settings for the Phase Estimation algorithm."""
[docs]
def __init__(self):
"""Initialize the settings for Phase Estimation.
Args:
num_bits: The number of phase bits to estimate. Default to -1; user needs to set a valid value.
evolution_time: Time parameter ``t`` used in the time-evolution unitary ``U = exp(-i H t)``,
defaults to 0.0; user needs to set a valid value. This setting is only applicable to
time evolution-based unitary builders such as Trotter.
"""
super().__init__()
self._set_default("num_bits", "int", -1, "The number of phase bits to estimate.")
self._set_default(
"evolution_time",
"float",
0.0,
"Time parameter ``t`` used in the time-evolution unitary ``U = exp(-i H t)``.",
)
[docs]
class PhaseEstimation(Algorithm):
"""Abstract base class for phase estimation algorithms."""
[docs]
def __init__(self, num_bits: int = -1, evolution_time: float = 0.0):
"""Initialize the PhaseEstimation with default settings.
Args:
num_bits: The number of phase bits to estimate. Default to -1; user needs to set a valid value.
evolution_time: Time parameter ``t`` used in the time-evolution unitary ``U = exp(-i H t)``,
defaults to 0.0; user needs to set a valid value.
"""
super().__init__()
self._settings = PhaseEstimationSettings()
self._settings.set("num_bits", num_bits)
self._settings.set("evolution_time", evolution_time)
[docs]
def type_name(self) -> str:
"""Return the algorithm type name as phase_estimation."""
return "phase_estimation"
@abstractmethod
def _run_impl(
self,
state_preparation: Circuit,
qubit_hamiltonian: QubitHamiltonian,
*,
evolution_builder: TimeEvolutionBuilder,
circuit_mapper: ControlledEvolutionCircuitMapper,
circuit_executor: CircuitExecutor,
noise: QuantumErrorProfile | None = None,
) -> QpeResult:
r"""Run the phase estimation algorithm with the given state preparation circuit and qubit Hamiltonian.
This method implements the quantum phase estimation procedure:
1. The state preparation circuit initializes the system in the desired quantum state.
2. The evolution_builder constructs a time evolution unitary :math:`U = \exp(-iHt)` from the qubit Hamiltonian.
3. The circuit_mapper transforms the time evolution unitary into controlled-U operations,
where the control qubits are ancilla qubits used for phase readout.
4. The circuit_executor runs the resulting quantum circuits on the target backend.
5. Measurement results are processed to extract the eigenvalue phase estimates.
Args:
state_preparation: The circuit that prepares the initial state.
qubit_hamiltonian: The qubit Hamiltonian for which to estimate eigenvalues.
evolution_builder: Builder that constructs time evolution unitaries from the Hamiltonian.
circuit_mapper: Maps controlled time evolution unitaries to circuit operations.
circuit_executor: The executor to run quantum circuits on a backend or simulator.
noise: The quantum error profile to simulate noise, defaults to None.
Returns:
A QpeResult object containing the estimated phases and associated metadata.
"""
def _create_time_evolution(
self, qubit_hamiltonian: QubitHamiltonian, time: float, evolution_builder: TimeEvolutionBuilder
) -> TimeEvolutionUnitary:
"""Create the time evolution circuit for the given Hamiltonian and power.
Args:
qubit_hamiltonian: The qubit Hamiltonian to evolve under.
time: The evolution time.
evolution_builder: The time evolution builder to use.
Returns:
The time evolution unitary circuit.
"""
return evolution_builder.run(qubit_hamiltonian, time)
def _create_ctrl_time_evol_circuit(
self,
controlled_evolution: ControlledTimeEvolutionUnitary,
power: int,
circuit_mapper: ControlledEvolutionCircuitMapper,
) -> Circuit:
"""Create the controlled time evolution circuit for the given Hamiltonian and power.
Args:
controlled_evolution: The controlled time evolution unitary.
power: The power to which the controlled unitary should be raised.
circuit_mapper: The controlled evolution circuit mapper to use.
Returns:
The controlled time evolution circuit.
"""
# Create a new instance of the mapper to avoid setting lock
circuit_mapper.settings().update("power", power) # Update the power setting
# Avoid lock settings
return circuit_mapper._run_impl(controlled_evolution=controlled_evolution) # noqa: SLF001
[docs]
class PhaseEstimationFactory(AlgorithmFactory):
"""Factory class for creating PhaseEstimation instances."""
[docs]
def __init__(self):
"""Initialize the PhaseEstimationFactory."""
super().__init__()
[docs]
def algorithm_type_name(self) -> str:
"""Return the algorithm type name as phase_estimation."""
return "phase_estimation"
[docs]
def default_algorithm_name(self) -> str:
"""Return the iterative as default algorithm name."""
return "iterative"