Skip to content

Commit 5e563a2

Browse files
authored
Merge pull request #110 from Langhaarzombie/feature/ntbk_smesolve
QuTiPv5 Paper Notebook: smesolve
2 parents 0d87e07 + a5df6a5 commit 5e563a2

File tree

1 file changed

+139
-0
lines changed

1 file changed

+139
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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

Comments
 (0)