Time-Dependent Drive Example#
Physics: Compile a Rabi-oscillation Hamiltonian with a time-dependent drive.
The Model
The classic Rabi problem combines a static qubit splitting with a resonant oscillating drive:
where:
\(\omega_0\) is the qubit transition frequency
\(\Omega\) is the drive Rabi frequency (drive strength)
\(\omega_d\) is the drive frequency
\(\sigma_x\) is the Pauli X operator (in-plane rotation)
The \(\cos(\omega_d t)\) envelope creates an oscillating drive
This is the foundational model for qubit gates in superconducting circuits, trapped ions, and other platforms.
What you’ll learn
How to write time-dependent envelopes in LaTeX (
\cos(\omega t),\sin(\omega t),\exp(-t), etc.)How the parser automatically detects time dependence
How to extract the time-dependent Hamiltonian and
argsdictionary for use with QuTiP’smesolve
Code
1# flake8: noqa
2"""
3Single-qubit drive with a time-dependent cosine envelope.
4
5What this shows:
6- Time-dependent scalar envelopes detected automatically from `t_name`.
7- The QuTiP backend returns an H-list suitable for `mesolve`.
8- How `time_dependent` is flagged on the compiled model.
9"""
10
11from __future__ import annotations
12
13import sys
14from pathlib import Path
15
16ROOT = Path(__file__).resolve().parents[1]
17if str(ROOT) not in sys.path:
18 sys.path.insert(0, str(ROOT))
19
20from latex_parser.latex_api import compile_model as compile_latex_model
21
22
23def main() -> None:
24 H_latex = r"\frac{\omega_0}{2} \sigma_{z,1} + A \cos(\omega t) \sigma_{x,1}"
25 params = {"omega_0": 2.0, "A": 0.3, "omega": 1.5}
26 model = compile_latex_model(H_latex=H_latex, params=params, qubits=1, t_name="t")
27 print("Time-dependent flag:", model.time_dependent)
28 print("H representation (QuTiP list for td):\n", model.H)
29
30
31if __name__ == "__main__":
32 main()
Run it
python examples/example_time_dependent_drive.py
What happens
The LaTeX includes the symbol
t(the time variable), so the parser marks this as time-dependentThe IR distinguishes between: - Static terms: \(\frac{\omega_0}{2} \sigma_z\) (depends on \(\omega_0\) only) - Time-dependent terms: \(\Omega \cos(\omega_d t) \sigma_x\) (depends on \(t\))
QuTiP receives the Hamiltonian in list form:
[H0, [H1, envelope_fn]]Each envelope is a callable
fn(t, args)that the solver evaluates at each time step
Example Output
Static part (H0):
[[0. 0. ]
[0. 1. ]]
Time-dependent part (H1):
[[0. 1.]
[1. 0.]]
Envelope function: <function ...>
# When mesolve evaluates at time t=1.5:
envelope_fn(1.5, {}) = 0.07073... (= cos(2*1.5))
Try this
Change the envelope to \(\sin(\omega_d t)\) in the LaTeX and re-run
Add exponential decay: \(\Omega \exp(-t/\tau) \cos(\omega_d t) \sigma_x\) (turn-off envelope)
Modify \(\omega_d\) to be off-resonance: change the parameter from
2.0to3.0
Numerical Simulation Example
To actually solve the Rabi equations:
from qutip import mesolve, basis
import numpy as np
# Compile the model (from the example)
# ... model = compile_model(...)
# Initial state: ground state
psi0 = basis(2, 0)
# Time points (0 to 2π / Ω ≈ 6.3 seconds for Rabi period)
times = np.linspace(0, 2*np.pi, 100)
# Solve the Schrödinger equation
result = mesolve(model.H, psi0, times, args=model.args)
# Analyze: Rabi oscillations between ground and excited states
excited_pop = [e[1] for e in result.expect[0]]
Next steps
See Collapse Operators (Open Systems) to add dissipation (decay channels)
Check JAX Autodiff Workflow for automatic differentiation of pulse sequences