|
| 1 | +--- |
| 2 | +jupyter: |
| 3 | + jupytext: |
| 4 | + text_representation: |
| 5 | + extension: .md |
| 6 | + format_name: markdown |
| 7 | + format_version: '1.3' |
| 8 | + jupytext_version: 1.16.4 |
| 9 | + kernelspec: |
| 10 | + display_name: Python 3 (ipykernel) |
| 11 | + language: python |
| 12 | + name: python3 |
| 13 | +--- |
| 14 | + |
| 15 | +# QuTiPv5 Paper Example: Stochastic Solver - Homodyne Detection |
| 16 | + |
| 17 | +Authors: Maximilian Meyer-Mölleringhof ( [email protected]), Neill Lambert ( [email protected]) |
| 18 | + |
| 19 | +## Introduction |
| 20 | + |
| 21 | +When modelling an open quantum system, stochastic noise can be used to simulate a large range of phenomena. |
| 22 | +In the `smesolve()` solver, noise is introduced by continuous measurement. |
| 23 | +This allows us to generate the trajectory evolution of a quantum system conditioned on a noisy measurement record. |
| 24 | +Historically speaking, such models were used by the quantum optics community to model homodyne and heterodyne detection of light emitted from a cavity. |
| 25 | +However, this solver is of course quite general and can thus also be applied to other problems. |
| 26 | + |
| 27 | +In this example we look at an optical cavity whose output is subject to homodyne detection. |
| 28 | +Such a cavity obeys the general stochastic master equation |
| 29 | + |
| 30 | +$d \rho(t) = -i [H, \rho(t)] dt + \mathcal{D}[a] \rho (t) dt + \mathcal{H}[a] \rho\, dW(t)$ |
| 31 | + |
| 32 | +with the Hamiltonian |
| 33 | + |
| 34 | +$H = \Delta a^\dagger a$ |
| 35 | + |
| 36 | +and the Lindblad dissipator |
| 37 | + |
| 38 | +$\mathcal{D}[a] = a \rho a^\dagger - \dfrac{1}{2} a^\dagger a \rho - \dfrac{1}{2} \rho a^\dagger a$. |
| 39 | + |
| 40 | +The stochastic part |
| 41 | + |
| 42 | +$\mathcal{H}[a]\rho = a \rho + \rho a^\dagger - tr[a \rho + \rho a^\dagger]$ |
| 43 | + |
| 44 | +captures the conditioning of the trajectory through continuous monitoring of the operator $a$. |
| 45 | +The term $dW(t)$ is the increment of a Wiener process that obeys $\mathbb{E}[dW] = 0$ and $\mathbb{E}[dW^2] = dt$. |
| 46 | + |
| 47 | +Note that a similiar example is available in the [QuTiP user guide](https://qutip.readthedocs.io/en/qutip-5.0.x/guide/dynamics/dynamics-stochastic.html#stochastic-master-equation). |
| 48 | + |
| 49 | +```python |
| 50 | +import numpy as np |
| 51 | +from matplotlib import pyplot as plt |
| 52 | +from qutip import about, coherent, destroy, mesolve, smesolve |
| 53 | + |
| 54 | +%matplotlib inline |
| 55 | +``` |
| 56 | + |
| 57 | +## Problem Parameters |
| 58 | + |
| 59 | +```python |
| 60 | +N = 20 # dimensions of Hilbert space |
| 61 | +delta = 10 * np.pi # cavity detuning |
| 62 | +kappa = 1 # decay rate |
| 63 | +A = 4 # initial coherent state intensity |
| 64 | +``` |
| 65 | + |
| 66 | +```python |
| 67 | +a = destroy(N) |
| 68 | +x = a + a.dag() # operator for expectation value |
| 69 | +H = delta * a.dag() * a # Hamiltonian |
| 70 | +mon_op = np.sqrt(kappa) * a # continiously monitored operators |
| 71 | +``` |
| 72 | + |
| 73 | +## Solving for the Time Evolution |
| 74 | + |
| 75 | +We calculate the predicted trajectory conditioned on the continuous monitoring of the operator $a$. |
| 76 | +This is compared to the regular `mesolve()` solver for the same model but without resolving conditioned trajectories. |
| 77 | + |
| 78 | +```python |
| 79 | +rho_0 = coherent(N, np.sqrt(A)) # initial state |
| 80 | +times = np.arange(0, 1, 0.0025) |
| 81 | +num_traj = 500 # number of computed trajectories |
| 82 | +opt = {"dt": 0.00125, "store_measurement": True, "map": "parallel"} |
| 83 | +``` |
| 84 | + |
| 85 | +```python |
| 86 | +me_solution = mesolve(H, rho_0, times, c_ops=[mon_op], e_ops=[x]) |
| 87 | +``` |
| 88 | + |
| 89 | +```python |
| 90 | +stoc_solution = smesolve( |
| 91 | + H, rho_0, times, sc_ops=[mon_op], e_ops=[x], ntraj=num_traj, options=opt |
| 92 | +) |
| 93 | +``` |
| 94 | + |
| 95 | +## Comparison of Results |
| 96 | + |
| 97 | +We plot the averaged homodyne current $J_x = \langle x \rangle + dW / dt$ and the average system behaviour $\langle x \rangle$ for 500 trajectories. |
| 98 | +This is compared with the prediction of the regular `mesolve()` solver that does not include the conditioned trajectories. |
| 99 | +Since the conditioned expectation values do not depend on the trajectories, we expect that this reproduces the result of the standard `mesolve()`. |
| 100 | + |
| 101 | +```python |
| 102 | +stoc_meas_mean = np.array(stoc_solution.measurement).mean(axis=0)[0, :].real |
| 103 | +``` |
| 104 | + |
| 105 | +```python |
| 106 | +plt.figure() |
| 107 | +plt.plot(times[1:], stoc_meas_mean, lw=2, label=r"$J_x$") |
| 108 | +plt.plot(times, stoc_solution.expect[0], label=r"$\langle x \rangle$") |
| 109 | +plt.plot( |
| 110 | + times, |
| 111 | + me_solution.expect[0], |
| 112 | + "--", |
| 113 | + color="gray", |
| 114 | + label=r"$\langle x \rangle$ mesolve", |
| 115 | +) |
| 116 | + |
| 117 | +plt.legend() |
| 118 | +plt.xlabel(r"$t \cdot \kappa$") |
| 119 | +plt.show() |
| 120 | +``` |
| 121 | + |
| 122 | +## References |
| 123 | + |
| 124 | +[1] [QuTiP 5: The Quantum Toolbox in Python](https://arxiv.org/abs/2412.04705) |
| 125 | + |
| 126 | + |
| 127 | +## About |
| 128 | + |
| 129 | +```python |
| 130 | +about() |
| 131 | +``` |
| 132 | + |
| 133 | +## Testing |
| 134 | + |
| 135 | +```python |
| 136 | +assert np.allclose( |
| 137 | + stoc_solution.expect[0], me_solution.expect[0], atol=1e-1 |
| 138 | +), "smesolve and mesolve do not preoduce the same trajectory." |
| 139 | +``` |
0 commit comments