Time Evolution
Hamiltonian Time Evolution
The TimeEvolution class simulates the evolution of a quantum state under a given Hamiltonian using Trotter-Suzuki decomposition. It supports multiple trotterization strategies, observable measurement, and multi-time-point trajectories.
Basic Usage
import pennylane as qml
from divi.qprog.algorithms import TimeEvolution
from divi.qprog._hamiltonians import ExactTrotterization
from divi import ParallelSimulator
# Define a Hamiltonian
coeffs = [1.0, 0.5, 0.3]
ops = [qml.PauliZ(0) @ qml.PauliZ(1), qml.PauliX(0), qml.PauliX(1)]
hamiltonian = qml.Hamiltonian(coeffs, ops)
# Evolve for time t=1.0 with 10 Trotter steps
sim = TimeEvolution(
hamiltonian=hamiltonian,
trotterization_strategy=ExactTrotterization(),
n_steps=10,
time=1.0,
shots=10000,
backend=ParallelSimulator(),
)
sim.run()Trotterization Strategies
Divi provides two built-in trotterization strategies:
ExactTrotterization (default)
Standard Trotter-Suzuki decomposition that applies all Hamiltonian terms in each time step:
from divi.qprog._hamiltonians import ExactTrotterization
strategy = ExactTrotterization()QDrift
Randomly samples Hamiltonian terms proportional to their coefficients, producing shallower circuits at the cost of introducing sampling noise:
from divi.qprog._hamiltonians import QDrift
strategy = QDrift(n_samples=50)QDrift is particularly useful for:
- Hamiltonians with many terms where exact Trotterization produces very deep circuits
- Near-term hardware where circuit depth is the limiting factor
- Cases where ensemble averaging can reduce sampling variance
Time Trajectories
Simulate evolution at multiple time points to observe dynamics:
import numpy as np
sim = TimeEvolution(
hamiltonian=hamiltonian,
time_points=np.linspace(0.1, 2.0, 20),
n_steps=10,
observable=qml.PauliZ(0),
backend=ParallelSimulator(),
)
sim.run()
# Access the trajectory of expectation values
for entry in sim.trajectory:
print(f"t={entry['time']:.2f}, <Z>={entry['expval']:.4f}")Observables
Measure expectation values of observables at each time point:
sim = TimeEvolution(
hamiltonian=hamiltonian,
time=1.0,
n_steps=10,
observable=qml.PauliZ(0) @ qml.PauliZ(1),
backend=ParallelSimulator(),
)When no observable is specified, the raw probability distribution is returned.
QDrift Ensemble Averaging
When using QDrift, you can run multiple independent circuit samples and average the results for improved accuracy:
sim = TimeEvolution(
hamiltonian=hamiltonian,
trotterization_strategy=QDrift(n_samples=30),
ensemble_size=10,
time=1.0,
n_steps=5,
observable=qml.PauliZ(0),
backend=ParallelSimulator(),
)
sim.run()Batched Execution
For large numbers of time points, use batch_size to control memory usage:
sim = TimeEvolution(
hamiltonian=hamiltonian,
time_points=np.linspace(0.01, 5.0, 500),
n_steps=20,
batch_size=50, # Process 50 time points at a time
backend=ParallelSimulator(),
)Initial States
Control the initial state before evolution:
| Value | Description |
|---|---|
"Zeros" |
All qubits in |0⟩ state (default) |
"Superposition" |
Equal superposition via Hadamard gates |
"Ones" |
All qubits in |1⟩ state |
"01+-..." |
Custom per-qubit state string |
Custom Initial State
You can specify the initial state of each qubit individually using a string of characters:
| Character | State |
|---|---|
0 |
|0⟩ |
1 |
|1⟩ |
+ |
|+⟩ = H|0⟩ |
- |
|−⟩ = HX|0⟩ |
The string length must match the number of qubits in the Hamiltonian:
# 4-qubit Hamiltonian: qubit 0 in |1⟩, qubit 1 in |+⟩, qubit 2 in |0⟩, qubit 3 in |−⟩
sim = TimeEvolution(
hamiltonian=hamiltonian,
initial_state="1+0-",
time=1.0,
n_steps=10,
backend=ParallelSimulator(),
)