qutip
Simulate and audit closed and open quantum-system models with QuTiP 5, including deterministic, trajectory, steady-state, spectral, and phase-space workflows. Use for local quantum-dynamics work where physical assumptions, dimensions, and numerical convergence must be explicit.
Works with
---
name: qutip
description: Simulate and audit closed and open quantum-system models with QuTiP 5, including deterministic, trajectory, steady-state, spectral, and phase-space workflows. Use for local quantum-dynamics work where physical assumptions, dimensions, and numerical convergence must be explicit.
license: MIT
---
# QuTiP 5
## Scope
Use QuTiP for finite-dimensional quantum mechanics, quantum optics, Lindblad
dynamics, trajectories, weak-coupling Bloch-Redfield models, and specialized
Floquet, HEOM, and permutational-invariance methods. It is not a hardware
execution SDK. Circuit and control functionality moved to separate QuTiP family
packages.
This skill targets **QuTiP 5.3.0**, released 2026-05-22. QuTiP 5.3 requires
Python 3.11 or newer. Its required distributions are NumPy (`>=1.23.2`), SciPy
(`>=1.9.2`, excluding `1.16.0` and `1.17.0`), and `packaging`.
## Reproducible uv snapshot
Create a dedicated environment and pin every direct distribution:
```bash
uv venv --python 3.11
uv pip install "qutip==5.3.0"
```
For plots:
```bash
uv pip install "qutip[graphics]==5.3.0"
```
Optional QuTiP family packages are independently versioned:
```bash
uv pip install "qutip-qip==0.4.2"
uv pip install "qutip-qtrl==0.2.0"
uv pip install "qutip-jax==0.1.1"
```
- `qutip-qip` 0.4.2 (2026-06-23) is the production/stable circuit, gate, and
noisy-device simulation package. Import from `qutip_qip`, not `qutip.qip`.
- `qutip-qtrl` 0.2.0 (2026-06-23) provides GRAPE and CRAB **quantum optimal
control**. It is not a trajectory viewer. Import from `qutip_qtrl`, not
`qutip.control`; PyPI still classifies it pre-alpha.
- `qutip-jax` 0.1.1 (2025-05-29) is the official JAX data backend for GPU and
automatic-differentiation experiments. It is explicitly pre-alpha.
- `qutip-cupy` is an official QuTiP-organization repository, but it has no PyPI
release and its own README says it is not officially released. Do not put an
unreleased Git install into a reproducible workflow.
Use a project lockfile or a hash-generating `uv pip compile` workflow when
transitive dependency identity must also be frozen.
## Non-negotiable model contract
Before solving, record:
1. **Units and convention.** QuTiP equations normally set \(\hbar=1\).
Hamiltonian entries are angular frequencies and rates have reciprocal-time
units. Convert cyclic frequency with \(2\pi f\); never mix Hz and rad/s.
2. **Subsystem order.** `tensor(A, B, C)` fixes subsystem indices `0, 1, 2`.
Preserve that order in every state, operator, collapse channel, and partial
trace. `obj.ptrace([0, 2])` keeps those subsystems; it does not trace them.
3. **State validity.** Check ket norm or density-matrix Hermiticity, unit trace,
and eigenvalues above a stated negative tolerance. Tiny negative values may
be numerical; material negativity invalidates a claimed state.
4. **Generator meaning.** A Lindblad channel with rate `gamma` is represented
by `sqrt(gamma) * A`, not `gamma * A`. Define what each rate measures. For
example, `sqrt(gamma_phi / 2) * sigmaz()` gives coherence decay
`exp(-gamma_phi * t)`.
5. **Approximations.** State rotating-wave, Born-Markov, secular, weak-coupling,
bath-equilibrium, truncation, symmetry, and initial-factorization assumptions
wherever used.
6. **Numerics.** Justify Hilbert truncation, output grid, integration method,
tolerances, trajectory count, and random seeds. Report `result.stats`.
7. **Convergence.** Sweep every artificial cutoff: Fock dimension, time/frequency
window and spacing, ODE tolerances, trajectories, Floquet harmonics, HEOM
depth and bath exponents, or PIQS representation as applicable.
## Qobj, dimensions, and tensor order
Prefer explicit imports and inspect both shape and structured dimensions:
```python
from qutip import basis, qeye, sigmaz, tensor
psi = tensor(basis(2, 0), basis(3, 1))
z_on_first = tensor(sigmaz(), qeye(3))
assert psi.shape == (6, 1)
assert psi.dims == [[2, 3], [1]]
assert z_on_first.dims == [[2, 3], [2, 3]]
rho_first = psi.proj().ptrace(0) # keep subsystem 0
```
Matrix shape alone is insufficient: two objects can both be 6-by-6 but encode
different tensor factorizations. Read `references/core_concepts.md` before
building composite, superoperator, or channel models.
## Choose the solver by physics
| Model | Current API | Required justification |
|---|---|---|
| Closed, pure, unitary | `sesolve` | Hermitian Hamiltonian; no dissipation |
| Lindblad/open or mixed | `mesolve` | Markovian completely positive model and channel rates |
| Quantum jumps | `mcsolve` | Unravelling, trajectory convergence, seeds |
| Microscopic weak bath | `brmesolve` | Born-Markov/weak coupling, spectra, secular choice |
| Diffusive measurement | `ssesolve`, `smesolve` | monitored versus unmonitored channels |
| Periodic drive | `FloquetBasis`, `fsesolve`, `fmmesolve` | verified period and Floquet convergence |
| Structured non-Markovian bath | `qutip.solver.heom` | bath expansion and hierarchy convergence |
| Symmetric spin ensemble | `qutip.piqs` | permutation symmetry and basis choice |
Do not select a more specialized solver merely because it exists.
## Deterministic open-system example
QuTiP 5.3 uses ordinary option dictionaries. Solver controls, `e_ops`, and
`args` are keyword-only; the old mutable options object is gone.
```python
import numpy as np
from qutip import basis, mesolve, sigmam, sigmaz
omega = 2.0
gamma = 0.15
tlist = np.linspace(0.0, 20.0, 401)
excited = basis(2, 0)
result = mesolve(
0.5 * omega * sigmaz(),
excited,
tlist,
c_ops=[np.sqrt(gamma) * sigmam()],
e_ops={"sigma_z": sigmaz(), "excited": excited.proj()},
options={
"method": "adams",
"atol": 1e-10,
"rtol": 1e-8,
"store_final_state": True,
"progress_bar": "",
},
)
population = np.asarray(result.e_data["excited"])
assert np.max(np.abs(population - np.exp(-gamma * tlist))) < 2e-6
assert isinstance(result.stats, dict)
```
If the problem is stiff, compare `bdf` or `lsoda`; do not change an integrator
without rerunning tolerance and invariant checks. QuTiP 5.3 also supports
`options={"matrix_form": True}` in `mesolve`; benchmark and validate it before
using it as a default.
## Time-dependent systems
Prefer trusted Pythonic callables or numeric coefficient arrays. Do not create
coefficient source strings from user input.
```python
import numpy as np
from qutip import QobjEvo, sigmax, sigmaz
def envelope(t, amplitude, center, width):
return amplitude * np.exp(-0.5 * ((t - center) / width) ** 2)
H = QobjEvo(
[0.5 * sigmaz(), [sigmax(), envelope]],
args={"amplitude": 0.2, "center": 5.0, "width": 1.0},
)
instantaneous_H = H(5.0)
H.arguments(amplitude=0.1)
```
The older `f(t, args)` coefficient signature is deprecated in 5.3 and is
scheduled for removal in 5.5. See `references/time_evolution.md`.
## Trajectories and stochastic solvers
```python
import numpy as np
from qutip import basis, mcsolve, sigmam, sigmaz
tlist = np.linspace(0.0, 10.0, 201)
result = mcsolve(
0.5 * sigmaz(),
basis(2, 0),
tlist,
[np.sqrt(0.2) * sigmam()],
e_ops=[basis(2, 0).proj()],
ntraj=400,
seeds=20260723,
options={"keep_runs_results": False, "progress_bar": ""},
)
```
Report `ntraj`, `result.seeds`, uncertainty or repeated-seed sensitivity, and
whether individual runs were retained. Reuse `seeds=previous_result.seeds` only
when paired trajectories are intentional. `ssesolve` and `smesolve` use the
boolean `heterodyne` argument, not legacy integer noise codes.
## Steady states, spectra, and phase space
```python
import numpy as np
from qutip import QFunc, liouvillian, operator_to_vector, qfunc, steadystate
rho_ss = steadystate(H, c_ops, method="direct")
residual = (liouvillian(H, c_ops) * operator_to_vector(rho_ss)).norm()
assert residual < 1e-9
xvec = np.linspace(-5.0, 5.0, 151)
Q_once = qfunc(rho_ss, xvec, xvec)
q_many = QFunc(xvec, xvec)
Q_again = q_many(rho_ss)
assert Q_once.shape == (len(xvec), len(xvec))
```
For `wigner`, `qfunc`, and `QFunc`, array element `[j, k]` corresponds to
`yvec[j]`, `xvec[k]`. In QuTiP 5.3, `QFunc` is initialized with fixed
coordinates and called with a state; it has no `.eval` method. This skill never
uses Python dynamic-code execution. Prefer `plot_wigner`, `Result.plot_expect`,
or explicit Matplotlib axes as documented in `references/visualization.md`.
Direct `spectrum` is a stationary steady-state spectrum. An FFT of a finite
correlation requires explicit checks for tail decay, timestep aliasing,
frequency resolution, window sensitivity, and transform convention. See
`references/analysis.md`.
## Advanced boundaries
- Import HEOM from `qutip.solver.heom`; the legacy QuTiP 4 nonmarkov HEOM
namespace is stale.
- Use `FloquetBasis` for modes and quasi-energies. Verify
`H(t + T) == H(t)` numerically and sweep basis/truncation choices.
- Access PIQS with `from qutip import piqs`. `Dicke.pisolve` is only the
optimized diagonal-state/diagonal-Hamiltonian route; general Dicke-basis
dynamics use the Liouvillian with `mesolve`.
- `brmesolve` can violate positivity, especially without secularization. Check
density-matrix eigenvalues over time.
- QIP and optimal control are extension-package concerns. Never present local
simulation as quantum-hardware execution.
See `references/advanced.md` for HEOM, Floquet, PIQS, stochastic, and extension
boundaries.
## Safe local CLIs
All bundled tools are local-only, emit strict JSON, reject non-finite JSON and
unknown keys, and never load pickle files or executable model code. Simulation
imports are lazy, so every `--help` works without QuTiP installed.
| Script | Purpose |
|---|---|
| `scripts/qobj_model_validator.py` | Validate bounded Qobj model JSON, dimensions, states, rates, and role compatibility |
| `scripts/two_level_simulation.py` | Run a bounded two-level Lindblad or jump simulation |
| `scripts/solver_config_planner.py` | Select a current solver and option/checklist plan |
| `scripts/convergence_sweep.py` | Sweep tolerances/grid size or trajectory count on a synthetic model |
| `scripts/result_audit.py` | Audit JSON output without deserializing Python objects |
| `scripts/steady_state_spectrum_planner.py` | Plan bounded steady-state and direct/FFT spectral checks |
Example:
```bash
python skills/qutip/scripts/two_level_simulation.py --help
python skills/qutip/scripts/two_level_simulation.py \
--decay-rate 0.2 --t-final 10 --time-points 201 \
--output two-level.json
python skills/qutip/scripts/result_audit.py two-level.json
```
## Completion checklist
- Record units, \(\hbar\), tensor order, initial state, channels, and model
assumptions.
- Validate Hermiticity, norm/trace, positivity, dimensions, and generator units.
- Pin QuTiP and direct extensions; record platform, Python, NumPy, and SciPy.
- Inspect result options and stats; do not assume states were stored.
- Perform cutoff, grid, tolerance/integrator, and stochastic convergence sweeps.
- Save portable numeric/configuration summaries as JSON or text. Do not load
untrusted QuTiP object/result files because object serialization can execute
code.
## References
- `references/core_concepts.md` — Qobj, dimensions, tensor products, states,
channels, and unit conventions
- `references/time_evolution.md` — current solver signatures, options, results,
QobjEvo, trajectories, and numerical controls
- `references/analysis.md` — physical-state audits, steady states,
correlations, spectra, and convergence
- `references/visualization.md` — Wigner, Q functions, `QFunc`, Bloch, result,
and matrix plots
- `references/advanced.md` — Bloch-Redfield, stochastic, Floquet, HEOM, PIQS,
and QuTiP family package boundaries
## Dated official sources
Verified **2026-07-23**:
- [QuTiP 5.3.0 PyPI metadata](https://pypi.org/project/qutip/)
- [QuTiP 5.3.0 release](https://github.com/qutip/qutip/releases/tag/v5.3.0)
- [QuTiP 5.3 changelog](https://qutip.readthedocs.io/en/stable/changelog.html)
- [QuTiP 5.3 API](https://qutip.readthedocs.io/en/stable/apidoc/apidoc.html)
- [QuTiP version-5 tutorials](https://github.com/qutip/qutip-tutorials/tree/main/tutorials-v5)
- [qutip-qip PyPI](https://pypi.org/project/qutip-qip/)
- [qutip-qtrl PyPI](https://pypi.org/project/qutip-qtrl/)
- [qutip-jax PyPI](https://pypi.org/project/qutip-jax/)
- [official unreleased qutip-cupy repository](https://github.com/qutip/qutip-cupy)More General & Other skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
grill-me
mattpocock/skills
A relentless interview to sharpen a plan or design.
grill-with-docs
mattpocock/skills
A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go.

