Source code for qdk_chemistry.algorithms.time_evolution.hamiltonian_simulation.base

"""QDK/Chemistry Hamiltonian simulation 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.data import (
    AlgorithmRef,
    Circuit,
    EnergyExpectationResult,
    MeasurementData,
    QuantumErrorProfile,
    QubitOperator,
    Settings,
    TimeDependentQubitHamiltonian,
)

__all__: list[str] = ["HamiltonianSimulation", "HamiltonianSimulationFactory", "HamiltonianSimulationSettings"]


[docs] class HamiltonianSimulationSettings(Settings): """Settings for Hamiltonian simulation."""
[docs] def __init__(self): """Initialize defaults for Hamiltonian simulation.""" super().__init__() self._set_default( "evolution_circuit_builder", "algorithm_ref", AlgorithmRef("evolution_circuit_builder", "euler"), "Evolution circuit builder used to construct the state-prep + evolution circuit.", ) self._set_default( "circuit_executor", "algorithm_ref", AlgorithmRef("circuit_executor", "qdk_sparse_state_simulator"), "Circuit executor used to run quantum circuits.", ) self._set_default( "observable_estimator", "algorithm_ref", AlgorithmRef("expectation_estimator", "qdk"), "Estimator used to compute observable expectation values.", )
[docs] class HamiltonianSimulation(Algorithm): """Abstract base class for Hamiltonian evolution and observable measurement."""
[docs] def __init__(self): """Initialize the Hamiltonian simulation settings.""" super().__init__() self._settings = HamiltonianSimulationSettings()
[docs] def type_name(self) -> str: """Return the algorithm type name as hamiltonian_simulation.""" return "hamiltonian_simulation"
@abstractmethod def _run_impl( self, hamiltonian: TimeDependentQubitHamiltonian, observables: list[QubitOperator], state_prep: Circuit, shots: int = 1000, *, noise: QuantumErrorProfile | None = None, ) -> list[tuple[EnergyExpectationResult, MeasurementData]]: r"""Run Hamiltonian simulation. This method implements a quantum ODE integrator for the Schrödinger equation :math:`i\\partial_t U = H(t)\\,U`. The time-dependent Hamiltonian is discretized into steps, each step is Trotterized into a quantum circuit, and the resulting circuit is executed to measure observable expectation values. The evolution builder, circuit mapper, circuit executor, and observable estimator are resolved from the algorithm's settings via ``AlgorithmRef``. Args: hamiltonian: Time-dependent Hamiltonian specifying the evolution schedule. observables: Observable Hamiltonians to measure after evolution; each returns its own expectation value. state_prep: Circuit that prepares the initial state before time evolution. shots: Number of measurement shots per observable. Defaults to 1000. noise: Optional noise profile. Returns: A list of tuples containing ``EnergyExpectationResult`` and ``MeasurementData`` objects. """ def _build_evolution_circuit( self, hamiltonian: TimeDependentQubitHamiltonian, state_prep: Circuit, ) -> Circuit: """Construct the evolution circuit using the configured circuit builder. Args: hamiltonian: Time-dependent Hamiltonian. state_prep: Circuit that prepares the initial state. Returns: The combined state-prep + evolution circuit. """ from qdk_chemistry.algorithms.time_evolution.evolution_circuit_builder.base import ( # noqa: PLC0415 EvolutionCircuitBuilder, ) circuit_builder = self._create_nested("evolution_circuit_builder") if not isinstance(circuit_builder, EvolutionCircuitBuilder): raise TypeError( f"evolution_circuit_builder must be an EvolutionCircuitBuilder, got {type(circuit_builder).__name__}." ) return circuit_builder.run(hamiltonian, state_prep) def _measure_observable( self, circuit: Circuit, observable: QubitOperator, shots: int = 1000, noise: QuantumErrorProfile | None = None, ) -> tuple[EnergyExpectationResult, MeasurementData]: """Measure a qubit observable on the provided circuit state.""" expectation_estimator = self._create_nested("observable_estimator") # Propagate this algorithm's circuit_executor setting to the energy estimator expectation_estimator.settings().set("circuit_executor", self._settings.get("circuit_executor")) energy_result, measurement_data = expectation_estimator.run( circuit, observable, total_shots=shots, noise_model=noise, ) return energy_result, measurement_data
[docs] class HamiltonianSimulationFactory(AlgorithmFactory): """Factory class for creating Hamiltonian simulation algorithm instances."""
[docs] def algorithm_type_name(self) -> str: """Return the algorithm type name as hamiltonian_simulation.""" return "hamiltonian_simulation"
[docs] def default_algorithm_name(self) -> str: """Return euler_integrator as the default algorithm name.""" return "euler_integrator"