Hamiltonian simulation
The HamiltonianSimulation algorithm in QDK/Chemistry simulates the time evolution of a quantum system under a time-dependent Hamiltonian and measures observable expectation values.
Following QDK/Chemistry’s algorithm design principles, it takes a TimeDependentQubitHamiltonian, a list of observable QubitOperator operators, and a state-preparation Circuit as input and returns a list of EnergyExpectationResult and MeasurementData pairs.
Overview
Hamiltonian simulation solves the time-dependent Schrödinger equation \(i\,\partial_t U = H(t)\,U\) on a quantum computer. For a Hamiltonian that changes with time — for example, a molecule driven by a laser pulse — the algorithm constructs a quantum circuit for the full evolution and then executes it to measure observable expectation values.
Circuit construction is delegated to an EvolutionCircuitBuilder, which handles time-stepping, propagation, and circuit-to-gates mapping. The simulation algorithm adds circuit execution and observable measurement on top.
For resource estimation (without circuit execution), use the EvolutionCircuitBuilder directly.
Using the HamiltonianSimulation
Note
This algorithm is currently available only in the Python API.
This section demonstrates how to create, configure, and run a Hamiltonian simulation.
The run method returns a list of tuples containing EnergyExpectationResult and MeasurementData objects — one per observable.
Input requirements
The HamiltonianSimulation requires the following inputs:
- TimeDependentQubitHamiltonian
A
TimeDependentQubitHamiltoniandescribing how the Hamiltonian varies with time.- Observables
A list of
QubitOperatoroperators to measure after evolution. Each observable must have the same number of qubits as the Hamiltonian.- State preparation circuit
A
Circuitthat prepares the initial state before time evolution. This is typically generated by the StatePreparation algorithm from aWavefunction.
Creating a simulation algorithm
from qdk_chemistry.algorithms import create
sim = create("hamiltonian_simulation", "euler_integrator")
Configuring settings
Settings vary by implementation. See Available implementations below for implementation-specific options.
from qdk_chemistry.data import AlgorithmRef
# Configure the nested evolution circuit builder
sim.settings().set(
"evolution_circuit_builder",
AlgorithmRef(
"evolution_circuit_builder",
"euler",
total_time=1.0,
dt=0.1,
propagator=AlgorithmRef("propagator", "magnus", order=1),
evolution_builder=AlgorithmRef(
"hamiltonian_unitary_builder", "trotter", order=4, num_divisions=2
),
),
)
Running the simulation
import numpy as np
from qdk_chemistry.algorithms import create
from qdk_chemistry.algorithms.state_preparation import identity_state_prep
from qdk_chemistry.data import AlgorithmRef, DrivenQubitHamiltonian, LatticeGraph
from qdk_chemistry.utils.model_hamiltonians import create_ising_hamiltonian
# 1. Build a driven Hamiltonian: H(t) = H0 + sin(2πt)·H1
lattice = LatticeGraph.chain(4)
h0 = create_ising_hamiltonian(lattice, j=1.0, h=0.0)
h1 = create_ising_hamiltonian(lattice, j=0.0, h=0.5)
td_hamiltonian = DrivenQubitHamiltonian(h0, h1, drive=lambda t: np.sin(2 * np.pi * t))
# 2. Configure simulation
sim = create("hamiltonian_simulation", "euler_integrator")
sim.settings().set(
"evolution_circuit_builder",
AlgorithmRef(
"evolution_circuit_builder",
"euler",
total_time=1.0,
dt=0.1,
propagator=AlgorithmRef("propagator", "magnus", order=1),
),
)
# 3. Run: evolve and measure observables
state_prep = identity_state_prep(num_qubits=td_hamiltonian.num_qubits)
observables = [h0] # Measure ZZ energy after evolution
results = sim.run(td_hamiltonian, observables, state_prep, shots=1000)
for energy_result, measurement_data in results:
print(f"Energy: {energy_result.energy_expectation_value:.4f}")
Available implementations
QDK/Chemistry’s HamiltonianSimulation provides a unified interface for time-dependent simulation methods.
You can discover available implementations programmatically:
from qdk_chemistry.algorithms import available
print(available("hamiltonian_simulation"))
Euler integrator
Factory name: "euler_integrator"
The Euler integrator delegates circuit construction to an EulerEvolutionCircuitBuilder, then executes the resulting circuit and measures each observable independently using the configured expectation estimator.
The circuit builder handles all time-stepping, propagation, and circuit mapping. See EvolutionCircuitBuilder for details on how the evolution circuit is constructed.
Settings
Direct settings on HamiltonianSimulationSettings:
Setting |
Type |
Description |
|---|---|---|
|
Evolution circuit builder used to construct the state-prep + evolution circuit. Default: |
|
|
Circuit executor used to run quantum circuits. Default: |
|
|
Estimator used to compute observable expectation values. Default: |
Nested algorithm configuration (via evolution_circuit_builder):
See EvolutionCircuitBuilder for configuring:
total_time— Total evolution timedt— Time step sizepropagator— Propagator for computing effective Hamiltoniansevolution_builder— Unitary builder (e.g., Trotter)circuit_mapper— Circuit compilation strategy
Further reading
The above examples can be downloaded as a complete Python script.
EvolutionCircuitBuilder: Time-evolution circuit composition
Propagator: Effective Hamiltonians for time-dependent evolution
HamiltonianUnitaryBuilder: Constructs the time-evolution unitary from the effective Hamiltonian
ExpectationEstimator: Observable expectation value estimation
CircuitExecutor: Quantum circuit execution backends
Settings: Configuration settings for algorithms
Factory Pattern: Understanding algorithm creation