Lindblad Master Equation Solver

July 13, 2026 · View on GitHub

scpn_quantum_control.phase.lindblad

Open-system dynamics for the Kuramoto-XY Hamiltonian via the Lindblad master equation. Solves for the full density matrix under amplitude damping and dephasing channels.

Caveat: Full density matrix evolution scales as O(4n)O(4^n) in memory. For n>10n > 10, consider the MCWF method or MPS/DMRG instead.


Theory

The Lindblad Master Equation

A closed quantum system evolves unitarily: dψ/dt=iHψd|\psi\rangle/dt = -iH|\psi\rangle. Real systems interact with their environment. The Lindblad equation is the most general Markovian master equation that preserves trace, Hermiticity, and positivity of the density matrix ρ\rho:

dρdt=i[H,ρ]+k(LkρLk12{LkLk,ρ})\frac{d\rho}{dt} = -i[H, \rho] + \sum_k \left( L_k \rho L_k^\dagger - \frac{1}{2}\{L_k^\dagger L_k, \rho\} \right)

The first term generates coherent (unitary) evolution. The second term — the dissipator — describes irreversible coupling to the environment through Lindblad operators LkL_k.

Channels in This Module

Two physical channels are implemented, parameterised per qubit:

ChannelLindblad operatorRatePhysical meaning
Amplitude dampingLk=γampσkL_k = \sqrt{\gamma_\text{amp}}\, \sigma^-_kγamp\gamma_\text{amp}Energy relaxation (T1T_1 decay)
Pure dephasingLk=γdeph/2σkzL_k = \sqrt{\gamma_\text{deph}/2}\, \sigma^z_kγdeph\gamma_\text{deph}Phase randomisation (T2T_2 decay)

For the Kuramoto-XY system, amplitude damping destroys synchronisation by relaxing excitations toward the ground state. Dephasing destroys off-diagonal coherences without changing populations.

The XY Hamiltonian

H=i<jKij(XiXj+YiYj)iωiZiH = -\sum_{i<j} K_{ij}(X_i X_j + Y_i Y_j) - \sum_i \omega_i Z_i

where KijK_{ij} is the coupling matrix (typically exponentially decaying with distance) and ωi\omega_i are natural frequencies.

Order Parameter and Purity

  • Kuramoto order parameter RR: extracted from single-qubit Pauli expectations Xk\langle X_k \rangle, Yk\langle Y_k \rangle via the density matrix. Quantifies synchronisation (R=1R=1 perfect sync, R0R \to 0 incoherent).
  • Purity Tr(ρ2)\text{Tr}(\rho^2): $1 for a pure state, \1/d$ for maximally mixed. Decreases under dissipation.

API Reference

LindbladKuramotoSolver

from scpn_quantum_control.phase.lindblad import LindbladKuramotoSolver

Constructor

LindbladKuramotoSolver(
    n_oscillators: int,
    K_coupling: np.ndarray,       # shape (n, n)
    omega_natural: np.ndarray,    # shape (n,)
    gamma_amp: float = 0.0,       # amplitude damping rate
    gamma_deph: float = 0.0,      # dephasing rate
    *,
    max_dense_gib: float | None = None,
)

Parameters:

ParameterTypeDescription
n_oscillatorsintPositive number of qubits and oscillators.
K_couplingndarray (n, n)Finite real symmetric coupling matrix. The diagonal is discarded.
omega_naturalndarray (n,)Finite real natural frequencies ordered like the rows of K_coupling.
gamma_ampfloatFinite non-negative amplitude-damping rate per qubit. γ=0\gamma = 0 disables damping.
gamma_dephfloatFinite non-negative pure-dephasing rate per qubit. γ=0\gamma = 0 disables dephasing.
max_dense_gib`floatNone`

If max_dense_gib is omitted, dense allocation uses SCPN_MAX_DENSE_GIB when set, otherwise the shared host-aware default. build() estimates the simultaneous Hamiltonian, density-matrix, work-array, and channel-operator footprint and raises DenseAllocationError before an over-budget allocation.

Methods

MethodSignatureReturnsDescription
build()(*, max_dense_gib=None) → NoneBuild and cache the Hamiltonian and channel operators under the active dense budget.
run()(t_max, dt, method="RK45", *, max_dense_gib=None) → dictSee belowEvolve through t_max; dt bounds adjacent output spacing. A zero horizon returns the initial state without SciPy.
order_parameter()(rho) → floatKuramoto RRReturn the mean transverse-expectation magnitude.
purity()(rho) → floatTr(ρ2)\text{Tr}(\rho^2)Return density-matrix purity.

The run() budget argument is a build-time override. If the solver is already built, its cached operators are reused. Invalid grids fail with ValueError, and an unsuccessful SciPy integration fails with RuntimeError.

run() Return Value

{
    "times": np.ndarray,      # shape (n_samples,)
    "R": np.ndarray,          # Kuramoto R at each sample, shape (n_samples,)
    "purity": np.ndarray,     # Tr(ρ²) at each sample, shape (n_samples,)
    "rho_final": np.ndarray,  # final density matrix, shape (dim, dim)
}

The initial density matrix is a pure product state obtained by applying one Ry(ωimod2π)R_y(\omega_i \bmod 2\pi) rotation to each qubit of the all-zero state.


Tutorial: Open-System Kuramoto Synchronisation

Step 1: Set Up the System

import numpy as np
from scpn_quantum_control.phase.lindblad import LindbladKuramotoSolver

# 4-oscillator chain with exponentially decaying coupling
n = 4
K = 0.45 * np.exp(-0.3 * np.abs(np.subtract.outer(range(n), range(n))))
np.fill_diagonal(K, 0.0)
omega = np.linspace(0.8, 1.2, n)

Step 2: Closed-System Baseline

solver_closed = LindbladKuramotoSolver(n, K, omega, gamma_amp=0.0, gamma_deph=0.0)
result_closed = solver_closed.run(t_max=2.0, dt=0.05)

print(f"Closed system — R: {result_closed['R'][0]:.3f}{result_closed['R'][-1]:.3f}")
print(f"Purity: {result_closed['purity'][-1]:.6f}")  # should be 1.000000

Step 3: Add Dissipation

solver_open = LindbladKuramotoSolver(n, K, omega, gamma_amp=0.05, gamma_deph=0.02)
result_open = solver_open.run(t_max=2.0, dt=0.05)

print(f"Open system — R: {result_open['R'][0]:.3f}{result_open['R'][-1]:.3f}")
print(f"Purity: {result_open['purity'][0]:.3f}{result_open['purity'][-1]:.3f}")

Step 4: Compare

import matplotlib.pyplot as plt

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))

ax1.plot(result_closed['times'], result_closed['R'], label='Closed')
ax1.plot(result_open['times'], result_open['R'], label='Open (γ=0.05)')
ax1.set_xlabel('Time')
ax1.set_ylabel('R')
ax1.legend()
ax1.set_title('Synchronisation Order Parameter')

ax2.plot(result_closed['times'], result_closed['purity'], label='Closed')
ax2.plot(result_open['times'], result_open['purity'], label='Open')
ax2.set_xlabel('Time')
ax2.set_ylabel('Tr(ρ²)')
ax2.legend()
ax2.set_title('Purity')

plt.tight_layout()
plt.savefig('lindblad_comparison.png', dpi=150)

Examples

Strong Damping Kills Synchronisation

solver_strong = LindbladKuramotoSolver(n, K, omega, gamma_amp=0.5)
result_strong = solver_strong.run(t_max=5.0, dt=0.1)
print(f"R(T=5) = {result_strong['R'][-1]:.4f}")  # → near 0
print(f"Purity(T=5) = {result_strong['purity'][-1]:.4f}")  # → near 1/2^n

Dephasing Only (No Energy Relaxation)

solver_deph = LindbladKuramotoSolver(n, K, omega, gamma_amp=0.0, gamma_deph=0.1)
result_deph = solver_deph.run(t_max=2.0, dt=0.05)
# Populations unchanged, but coherences decay

Verify Density Matrix Properties

rho = result_open['rho_final']
assert np.allclose(np.trace(rho), 1.0), "Trace not preserved"
assert np.allclose(rho, rho.conj().T), "Not Hermitian"
eigenvalues = np.linalg.eigvalsh(rho)
assert np.all(eigenvalues >= -1e-12), "Not positive semidefinite"

Differentiable Objective Evidence

Bounded open-system objective rows are available through scpn_quantum_control.phase.open_system_objectives. The suite evaluates small Kuramoto-XY Lindblad objectives through LindbladKuramotoSolver.run() and certifies the final density matrix before accepting the objective row:

from scpn_quantum_control.phase import run_open_system_objective_suite


suite = run_open_system_objective_suite(backends=("lindblad_density",))
record = suite.records[0]
print(record.gradient)
print(record.invariant_certificate)

The trainable parameters are bounded scalar coupling and damping scales. The recorded gradient is a deterministic central finite difference, so it is useful for local objective diagnostics and reviewer replay, not an adjoint Lindblad gradient or a provider/hardware gradient. The committed evidence artifact is data/differentiable_phase_qnode/open_system_objective_evidence_20260709.json; regenerate it with scpn-bench open-system-objective-evidence --no-diff or scripts/export_open_system_objective_evidence.py.


Comparison with Other Tools

FeatureThis moduleQuTiP mesolveMISTIQS
Lindblad equationYesYesNo
HamiltonianKuramoto-XY (built-in)Any (user-supplied)TFIM only
Coupling matrixArbitrary KijK_{ij}AnyNearest-neighbour
Solverscipy.solve_ivp (RK45)Internal ODE solver
GPUNoNo (QuTiP 5: CuPy)No
OutputR(t)R(t), purity, ρ\rhoArbitrary expect

When to use this module: You want open-system dynamics for the Kuramoto-XY Hamiltonian with the SCPN coupling matrix KnmK_{nm}, integrated with the rest of the scpn-quantum-control pipeline.

When to use QuTiP: You need arbitrary Hamiltonians, Floquet theory, stochastic Schrödinger equation, or QuTiP's extensive toolbox. Our module is not a QuTiP replacement — it is a specialised solver for one Hamiltonian.


Scaling

nnHilbert space dimDensity matrix sizeMemory (complex128)
41616 × 164 KB
8256256 × 2561 MB
101,0241,024 × 1,02416 MB
124,0964,096 × 4,096256 MB
1416,38416,384 × 16,3844 GB

Beyond n=12n = 12, wall-time becomes the bottleneck (the RHS evaluation at each time step is O(d2)O(d^2) where d=2nd = 2^n). For larger systems, use the MCWF method (phase/tensor_jump.py) which evolves state vectors instead of density matrices.


References

  1. Lindblad, G. "On the generators of quantum dynamical semigroups." Commun. Math. Phys. 48, 119–130 (1976).
  2. Gorini, V., Kossakowski, A. & Sudarshan, E. C. G. "Completely positive dynamical semigroups of N-level systems." J. Math. Phys. 17, 821 (1976).
  3. Ameri, V. et al. "Mutual information as an order parameter for quantum synchronization." PRA 91, 012301 (2015).
  4. Giorgi, G. L. et al. "Quantum correlations and mutual synchronization." PRA 85, 052101 (2012).

See Also