Development notebook: Tests for QuTiP's stochastic master equation solver

Copyright (C) 2011 and later, Paul D. Nation & Robert J. Johansson

In this notebook we test the qutip stochastic master equation solver (smesolve) with a few textbook examples taken from the book Quantum Optics, by Walls and Milburn, section 6.7.


In [1]:
%pylab inline


Populating the interactive namespace from numpy and matplotlib

In [2]:
from qutip import *

Photo-count detection

Theory

Stochastic master equation in Milburn's formulation

$\displaystyle d\rho(t) = dN(t) \mathcal{G}[a] \rho(t) - dt \gamma \mathcal{H}[\frac{1}{2}a^\dagger a] \rho(t)$

where

$\displaystyle \mathcal{G}[A] \rho = \frac{A\rho A^\dagger}{\mathrm{Tr}[A\rho A^\dagger]} - \rho$

$\displaystyle \mathcal{H}[A] \rho = \frac{1}{2}(A\rho + \rho A^\dagger - \mathrm{Tr}[A\rho + \rho A^\dagger] \rho) $

and $dN(t)$ is a Poisson distributed increment with $E[dN(t)] = \gamma \langle a^\dagger a\rangle (t)dt$.

Formulation in QuTiP

In QuTiP we write the stochastic master equation on the form (in the interaction picture, with no deterministic dissipation):

$\displaystyle d\rho(t) = D_{1}[A]\rho(t) dt + D_{2}[A]\rho(t) dW$

where $A = \sqrt{\gamma} a$, so we can identify

$\displaystyle D_{1}[A]\rho(t) = - \frac{1}{2}\gamma \mathcal{H}[a^\dagger a] \rho(t) = -\gamma \frac{1}{2}\left( a^\dagger a\rho + \rho a^\dagger a - \mathrm{Tr}[a^\dagger a\rho + \rho a^\dagger a] \rho \right) = -\frac{1}{2}\left( A^\dagger A\rho + \rho A^\dagger A - \mathrm{Tr}[A^\dagger A\rho + \rho A^\dagger A] \rho \right)$

$\displaystyle D_{2}[A]\rho(t) = \mathcal{G}[a] \rho = \frac{A\rho A^\dagger}{\mathrm{Tr}[A\rho A^\dagger]} - \rho$

and

$dW = dN(t)$

and $A = \sqrt{\gamma} a$ is the collapse operator including the rate of the process as a coefficient in the operator.

Reference solution: deterministic master equation


In [3]:
N = 10
w0 = 0.5 * 2 * pi
times = linspace(0, 15, 150)
dt = times[1] - times[0]
gamma = 0.25
A = 2.5
ntraj = 50
nsubsteps = 100

In [4]:
a = destroy(N)
x = a + a.dag()

In [5]:
H = w0 * a.dag() * a

In [6]:
#rho0 = coherent(N, 5)
rho0 = fock(N, 5)

In [7]:
c_ops = [sqrt(gamma) * a]

In [8]:
e_ops = [a.dag() * a, x]

In [9]:
result_ref = mesolve(H, rho0, times, c_ops, e_ops)

In [10]:
plot_expectation_values(result_ref);


Solve using stochastic master equation


In [11]:
# The argument A in the d1 and d2 callback functions is a list with the following
# precomputed superoperators, where c is the stochastic collapse operator given
# to the solver (called once for each operator, if more than one is given)
#
#     A[0] = spre(c)
#     A[1] = spost(c)
#     A[2] = spre(c.dag())
#     A[3] = spost(c.dag())
#     A[4] = spre(n)
#     A[5] = spost(n)
#     A[6] = (spre(c) * spost(c.dag())
#     A[7] = lindblad_dissipator(c)

$\displaystyle D_{1}[a, \rho] = -\gamma \frac{1}{2}\left( a^\dagger a\rho + \rho a^\dagger a - \mathrm{Tr}[a^\dagger a\rho + \rho a^\dagger a] \right) \rightarrow - \frac{1}{2}(\{A^\dagger A\}_L + \{A^\dagger A\}_R)\rho_v + \mathrm{E}[(\{A^\dagger A\}_L + \{A^\dagger A\}_R)\rho_v]$


In [12]:
def d1_rho_func(A, rho_vec):
    n_sum = A[4] + A[5]
    return 0.5 * (expect_rho_vec(n_sum, rho_vec, False) * rho_vec - n_sum * rho_vec)

$\displaystyle D_{2}[A, \rho(t)] = \frac{A\rho A^\dagger}{\mathrm{Tr}[A\rho A^\dagger]} - \rho \rightarrow \frac{A_LA^\dagger_R \rho_v}{\mathrm{E}[A_LA^\dagger_R \rho_v]} - \rho_v$


In [13]:
def d2_rho_func(A, rho_vec):
    e1 = expect_rho_vec(A[6], rho_vec, False) + 1e-16  # add a small number to avoid division by zero
    return [(A[6] * rho_vec) / e1 - rho_vec]

In [14]:
result = smesolve(H, rho0, times, c_ops=[], sc_ops=c_ops, e_ops=e_ops, 
                  ntraj=ntraj, nsubsteps=nsubsteps, d1=d1_rho_func, d2=d2_rho_func, m_ops=[[None]],
                  distribution='poisson', store_measurement=True)


10.0%. Run time:  27.45s. Est. time left: 00:00:04:07
20.0%. Run time:  54.46s. Est. time left: 00:00:03:37
30.0%. Run time:  81.18s. Est. time left: 00:00:03:09
40.0%. Run time: 108.01s. Est. time left: 00:00:02:42
50.0%. Run time: 134.87s. Est. time left: 00:00:02:14
60.0%. Run time: 161.61s. Est. time left: 00:00:01:47
70.0%. Run time: 188.32s. Est. time left: 00:00:01:20
80.0%. Run time: 215.10s. Est. time left: 00:00:00:53
90.0%. Run time: 241.91s. Est. time left: 00:00:00:26
Total run time: 268.66s

In [15]:
plot_expectation_values([result, result_ref]);



In [16]:
fig, ax = subplots()

for m in result.measurement:
    ax.step(times, dt * m.real)


Note that we multiply the measurement records with dt to show the count events instead of the count rate.

Solve problem again, this time with a specified noise (from previous run)


In [17]:
result = smesolve(H, rho0, times, c_ops=[], sc_ops=c_ops, e_ops=e_ops, 
                  ntraj=ntraj, nsubsteps=nsubsteps,
                  d1=d1_rho_func, d2=d2_rho_func, distribution='poisson', m_ops=[[None]],
                  store_measurement=True, noise=result.noise)


10.0%. Run time:  26.22s. Est. time left: 00:00:03:55
20.0%. Run time:  52.33s. Est. time left: 00:00:03:29
30.0%. Run time:  78.30s. Est. time left: 00:00:03:02
40.0%. Run time: 104.54s. Est. time left: 00:00:02:36
50.0%. Run time: 131.08s. Est. time left: 00:00:02:11
60.0%. Run time: 157.75s. Est. time left: 00:00:01:45
70.0%. Run time: 183.89s. Est. time left: 00:00:01:18
80.0%. Run time: 209.92s. Est. time left: 00:00:00:52
90.0%. Run time: 236.05s. Est. time left: 00:00:00:26
Total run time: 262.11s

In [18]:
plot_expectation_values([result, result_ref]);



In [19]:
fig, ax = subplots()

for m in result.measurement:
    ax.step(times, dt * m.real)


Using QuTiP built-in photo-current detection functions for $D_1$ and $D_2$


In [20]:
result = smesolve(H, rho0, times, [], c_ops, e_ops,
                  ntraj=ntraj, nsubsteps=nsubsteps,
                  method='photocurrent', store_measurement=True)


10.0%. Run time:  25.70s. Est. time left: 00:00:03:51
20.0%. Run time:  50.95s. Est. time left: 00:00:03:23
30.0%. Run time:  76.32s. Est. time left: 00:00:02:58
40.0%. Run time: 102.13s. Est. time left: 00:00:02:33
50.0%. Run time: 128.01s. Est. time left: 00:00:02:08
60.0%. Run time: 154.48s. Est. time left: 00:00:01:42
70.0%. Run time: 181.01s. Est. time left: 00:00:01:17
80.0%. Run time: 206.71s. Est. time left: 00:00:00:51
90.0%. Run time: 232.46s. Est. time left: 00:00:00:25
Total run time: 258.28s

In [21]:
plot_expectation_values([result, result_ref]);


Solve problem again, this time with a specified noise (from previous run)


In [22]:
result = smesolve(H, rho0, times, c_ops=[], sc_ops=c_ops, e_ops=e_ops, ntraj=ntraj, nsubsteps=nsubsteps,
                  method='photocurrent', store_measurement=True, noise=result.noise)


10.0%. Run time:  25.09s. Est. time left: 00:00:03:45
20.0%. Run time:  49.74s. Est. time left: 00:00:03:18
30.0%. Run time:  74.35s. Est. time left: 00:00:02:53
40.0%. Run time:  98.40s. Est. time left: 00:00:02:27
50.0%. Run time: 122.17s. Est. time left: 00:00:02:02
60.0%. Run time: 147.82s. Est. time left: 00:00:01:38
70.0%. Run time: 173.38s. Est. time left: 00:00:01:14
80.0%. Run time: 198.61s. Est. time left: 00:00:00:49
90.0%. Run time: 224.00s. Est. time left: 00:00:00:24
Total run time: 248.83s

In [23]:
plot_expectation_values([result, result_ref]);



In [24]:
fig, ax = subplots()

for m in result.measurement:
    ax.step(times, dt * m.real)


Homodyne detection


In [25]:
H = w0 * a.dag() * a + A * (a + a.dag())

In [26]:
result_ref = mesolve(H, rho0, times, c_ops, e_ops)

Theory

Stochastic master equation for homodyne in Milburn's formulation

$\displaystyle d\rho(t) = -i[H, \rho(t)]dt + \gamma\mathcal{D}[a]\rho(t) dt + dW(t) \sqrt{\gamma} \mathcal{H}[a] \rho(t)$

where $\mathcal{D}$ is the standard Lindblad dissipator superoperator, and $\mathcal{H}$ is defined as above, and $dW(t)$ is a normal distributed increment with $E[dW(t)] = \sqrt{dt}$.

In QuTiP format we have:

$\displaystyle d\rho(t) = -i[H, \rho(t)]dt + D_{1}[A]\rho(t) dt + D_{2}[A]\rho(t) dW$

where $A = \sqrt{\gamma} a$, so we can identify

$\displaystyle D_{1}[A]\rho(t) = \gamma \mathcal{D}[a]\rho(t) = \mathcal{D}[A]\rho(t)$


In [27]:
def d1_rho_func(A, rho_vec):
    return A[7] * rho_vec

$\displaystyle D_{2}[A]\rho(t) = \sqrt{\gamma} \mathcal{H}[a]\rho(t) = A\rho + \rho A^\dagger - \mathrm{Tr}[A\rho + \rho A^\dagger] \rho \rightarrow (A_L + A_R^\dagger)\rho_v - \mathrm{Tr}[(A_L + A_R^\dagger)\rho_v] \rho_v$


In [28]:
def d2_rho_func(A, rho_vec):
    n_sum = A[0] + A[3]
    e1 = expect_rho_vec(n_sum, rho_vec, False)
    return [n_sum * rho_vec - e1 * rho_vec]

In [29]:
result = smesolve(H, rho0, times, [], c_ops, e_ops, 
                  ntraj=ntraj, nsubsteps=nsubsteps,
                  d1=d1_rho_func, d2=d2_rho_func, distribution='normal',
                  m_ops=[[(a + a.dag())]], dW_factors=[1/sqrt(gamma)],
                  store_measurement=True)


10.0%. Run time:  25.47s. Est. time left: 00:00:03:49
20.0%. Run time:  50.70s. Est. time left: 00:00:03:22
30.0%. Run time:  75.60s. Est. time left: 00:00:02:56
40.0%. Run time: 101.52s. Est. time left: 00:00:02:32
50.0%. Run time: 126.13s. Est. time left: 00:00:02:06
60.0%. Run time: 150.69s. Est. time left: 00:00:01:40
70.0%. Run time: 175.51s. Est. time left: 00:00:01:15
80.0%. Run time: 200.34s. Est. time left: 00:00:00:50
90.0%. Run time: 225.09s. Est. time left: 00:00:00:25
Total run time: 249.80s

In [30]:
plot_expectation_values([result, result_ref]);



In [31]:
fig, ax = subplots()

for m in result.measurement:
    ax.plot(times, m[:, 0].real, 'b', alpha=0.025)
    
ax.plot(times, result_ref.expect[1], 'k', lw=2);
ax.set_ylim(-15, 15)
ax.plot(times, array(result.measurement).mean(axis=0)[:,0].real, 'r', lw=2);


Solve problem again, this time with a specified noise (from previous run)


In [32]:
result = smesolve(H, rho0, times, [], c_ops, e_ops, 
                  ntraj=ntraj, nsubsteps=nsubsteps, d1=d1_rho_func, d2=d2_rho_func,
                  m_ops=[[(a + a.dag())]], dW_factors=[1/sqrt(gamma)],        
                  distribution='normal', store_measurement=True, noise=result.noise)


10.0%. Run time:  25.98s. Est. time left: 00:00:03:53
20.0%. Run time:  51.36s. Est. time left: 00:00:03:25
30.0%. Run time:  76.91s. Est. time left: 00:00:02:59
40.0%. Run time: 102.44s. Est. time left: 00:00:02:33
50.0%. Run time: 127.96s. Est. time left: 00:00:02:07
60.0%. Run time: 153.44s. Est. time left: 00:00:01:42
70.0%. Run time: 178.84s. Est. time left: 00:00:01:16
80.0%. Run time: 204.30s. Est. time left: 00:00:00:51
90.0%. Run time: 229.79s. Est. time left: 00:00:00:25
Total run time: 255.43s

In [33]:
plot_expectation_values([result, result_ref]);



In [34]:
fig, ax = subplots()

for m in result.measurement:
    ax.plot(times, m[:, 0].real, 'b', alpha=0.025)
    
ax.plot(times, result_ref.expect[1], 'k', lw=2);

ax.plot(times, array(result.measurement).mean(axis=0)[:,0].real, 'r', lw=2);


Using QuTiP built-in homodyne detection functions for $D_1$ and $D_2$


In [35]:
result = smesolve(H, rho0, times, [], c_ops, e_ops, ntraj=ntraj, nsubsteps=100,
                  method='homodyne', store_measurement=True)


10.0%. Run time:  26.41s. Est. time left: 00:00:03:57
20.0%. Run time:  52.02s. Est. time left: 00:00:03:28
30.0%. Run time:  76.30s. Est. time left: 00:00:02:58
40.0%. Run time: 101.28s. Est. time left: 00:00:02:31
50.0%. Run time: 125.55s. Est. time left: 00:00:02:05
60.0%. Run time: 150.20s. Est. time left: 00:00:01:40
70.0%. Run time: 174.87s. Est. time left: 00:00:01:14
80.0%. Run time: 199.70s. Est. time left: 00:00:00:49
90.0%. Run time: 224.55s. Est. time left: 00:00:00:24
Total run time: 249.37s

In [36]:
plot_expectation_values([result, result_ref]);



In [37]:
fig, ax = subplots()

for m in result.measurement:
    ax.plot(times, m[:, 0].real / sqrt(gamma), 'b', alpha=0.025)
    
ax.plot(times, array(result.measurement).mean(axis=0)[:,0].real / sqrt(gamma), 'r', lw=2);
ax.plot(times, result_ref.expect[1], 'k', lw=2);


Solve problem again, this time with a specified noise (from previous run)


In [38]:
result = smesolve(H, rho0, times, [], c_ops, e_ops, ntraj=ntraj, nsubsteps=nsubsteps,
                  method='homodyne', store_measurement=True, noise=result.noise)


10.0%. Run time:  25.25s. Est. time left: 00:00:03:47
20.0%. Run time:  50.00s. Est. time left: 00:00:03:20
30.0%. Run time:  74.73s. Est. time left: 00:00:02:54
40.0%. Run time:  99.85s. Est. time left: 00:00:02:29
50.0%. Run time: 124.70s. Est. time left: 00:00:02:04
60.0%. Run time: 149.56s. Est. time left: 00:00:01:39
70.0%. Run time: 175.13s. Est. time left: 00:00:01:15
80.0%. Run time: 199.28s. Est. time left: 00:00:00:49
90.0%. Run time: 223.48s. Est. time left: 00:00:00:24
Total run time: 248.24s

In [39]:
plot_expectation_values([result, result_ref]);



In [40]:
fig, ax = subplots()

for m in result.measurement:
    ax.plot(times, m[:, 0].real / sqrt(gamma), 'b', alpha=0.025)
    

ax.plot(times, array(result.measurement).mean(axis=0)[:,0].real / sqrt(gamma), 'r', lw=2)

ax.plot(times, result_ref.expect[1], 'k', lw=2);


Heterodyne detection


In [41]:
e_ops = [a.dag() * a, a + a.dag(), -1j * (a - a.dag())]

In [42]:
result_ref = mesolve(H, rho0, times, c_ops, e_ops)

Stochastic master equation for heterodyne in Milburn's formulation

$\displaystyle d\rho(t) = -i[H, \rho(t)]dt + \gamma\mathcal{D}[a]\rho(t) dt + \frac{1}{\sqrt{2}} dW_1(t) \sqrt{\gamma} \mathcal{H}[a] \rho(t) + \frac{1}{\sqrt{2}} dW_2(t) \sqrt{\gamma} \mathcal{H}[-ia] \rho(t)$

where $\mathcal{D}$ is the standard Lindblad dissipator superoperator, and $\mathcal{H}$ is defined as above, and $dW_i(t)$ is a normal distributed increment with $E[dW_i(t)] = \sqrt{dt}$.

In QuTiP format we have:

$\displaystyle d\rho(t) = -i[H, \rho(t)]dt + D_{1}[A]\rho(t) dt + D_{2}^{(1)}[A]\rho(t) dW_1 + D_{2}^{(2)}[A]\rho(t) dW_2$

where $A = \sqrt{\gamma} a$, so we can identify

$\displaystyle D_{1}[A]\rho = \gamma \mathcal{D}[a]\rho = \mathcal{D}[A]\rho$


In [43]:
def d1_rho_func(A, rho_vec):
    return A[7] * rho_vec

$D_{2}^{(1)}[A]\rho = \frac{1}{\sqrt{2}} \sqrt{\gamma} \mathcal{H}[a] \rho = \frac{1}{\sqrt{2}} \mathcal{H}[A] \rho = \frac{1}{\sqrt{2}}(A\rho + \rho A^\dagger - \mathrm{Tr}[A\rho + \rho A^\dagger] \rho) \rightarrow \frac{1}{\sqrt{2}} \left\{(A_L + A_R^\dagger)\rho_v - \mathrm{Tr}[(A_L + A_R^\dagger)\rho_v] \rho_v\right\}$

$D_{2}^{(2)}[A]\rho = \frac{1}{\sqrt{2}} \sqrt{\gamma} \mathcal{H}[-ia] \rho = \frac{1}{\sqrt{2}} \mathcal{H}[-iA] \rho = \frac{-i}{\sqrt{2}}(A\rho - \rho A^\dagger - \mathrm{Tr}[A\rho - \rho A^\dagger] \rho) \rightarrow \frac{-i}{\sqrt{2}} \left\{(A_L - A_R^\dagger)\rho_v - \mathrm{Tr}[(A_L - A_R^\dagger)\rho_v] \rho_v\right\}$


In [44]:
def d2_rho_func(A, rho_vec):

    n_sum = A[0] + A[3]
    e1 = expect_rho_vec(n_sum, rho_vec, False)
    drho1 = n_sum * rho_vec - e1 * rho_vec

    n_sum = A[0] - A[3]
    e1 = expect_rho_vec(n_sum, rho_vec, False)
    drho2 = n_sum * rho_vec - e1 * rho_vec

    return [1.0/sqrt(2) * drho1, -1.0j/sqrt(2) * drho2]

In [45]:
result = smesolve(H, rho0, times, [], c_ops, e_ops, 
                  ntraj=ntraj, nsubsteps=nsubsteps, d1=d1_rho_func, d2=d2_rho_func, d2_len=2,
                  m_ops=[[(a + a.dag()), (-1j)*(a - a.dag())]],
                  dW_factors=[2/sqrt(gamma), 2/sqrt(gamma)],
                  distribution='normal', store_measurement=True)


10.0%. Run time:  45.16s. Est. time left: 00:00:06:46
20.0%. Run time:  89.41s. Est. time left: 00:00:05:57
30.0%. Run time: 134.63s. Est. time left: 00:00:05:14
40.0%. Run time: 180.29s. Est. time left: 00:00:04:30
50.0%. Run time: 225.76s. Est. time left: 00:00:03:45
60.0%. Run time: 271.35s. Est. time left: 00:00:03:00
70.0%. Run time: 317.10s. Est. time left: 00:00:02:15
80.0%. Run time: 362.57s. Est. time left: 00:00:01:30
90.0%. Run time: 407.69s. Est. time left: 00:00:00:45
Total run time: 453.43s

In [46]:
plot_expectation_values([result, result_ref]);



In [47]:
fig, ax = subplots()

for m in result.measurement:
    ax.plot(times, m[:, 0, 0].real, 'r', alpha=0.025)
    ax.plot(times, m[:, 0, 1].real, 'b', alpha=0.025)

ax.set_ylim(-20, 20)
    
ax.plot(times, array(result.measurement).mean(axis=0)[:,0,0].real, 'r', lw=2);
ax.plot(times, array(result.measurement).mean(axis=0)[:,0,1].real, 'b', lw=2);

ax.plot(times, result_ref.expect[1], 'k', lw=2);
ax.plot(times, result_ref.expect[2], 'k', lw=2);


Using QuTiP built-in heterodyne detection functions for $D_1$ and $D_2$


In [48]:
result = smesolve(H, rho0, times, [], c_ops, e_ops, ntraj=ntraj, nsubsteps=nsubsteps,
                  method='heterodyne', store_measurement=True)


10.0%. Run time:  43.89s. Est. time left: 00:00:06:35
20.0%. Run time:  87.27s. Est. time left: 00:00:05:49
30.0%. Run time: 130.79s. Est. time left: 00:00:05:05
40.0%. Run time: 174.58s. Est. time left: 00:00:04:21
50.0%. Run time: 217.08s. Est. time left: 00:00:03:37
60.0%. Run time: 259.77s. Est. time left: 00:00:02:53
70.0%. Run time: 302.67s. Est. time left: 00:00:02:09
80.0%. Run time: 345.66s. Est. time left: 00:00:01:26
90.0%. Run time: 388.29s. Est. time left: 00:00:00:43
Total run time: 431.85s

In [49]:
plot_expectation_values([result, result_ref]);



In [50]:
fig, ax = subplots()

for m in result.measurement:
    ax.plot(times, m[:, 0, 0].real / sqrt(gamma), 'r', alpha=0.025)
    ax.plot(times, m[:, 0, 1].real / sqrt(gamma), 'b', alpha=0.025)
    
ax.plot(times, array(result.measurement).mean(axis=0)[:,0,0].real / sqrt(gamma), 'r', lw=2);
ax.plot(times, array(result.measurement).mean(axis=0)[:,0,1].real / sqrt(gamma), 'b', lw=2);

ax.plot(times, result_ref.expect[1], 'k', lw=2);
ax.plot(times, result_ref.expect[2], 'k', lw=2);


Solve problem again, this time with a specified noise (from previous run)


In [51]:
result = smesolve(H, rho0, times, [], c_ops, e_ops, ntraj=ntraj, nsubsteps=nsubsteps,
                  method='heterodyne', store_measurement=True, noise=result.noise)


10.0%. Run time:  43.16s. Est. time left: 00:00:06:28
20.0%. Run time:  85.92s. Est. time left: 00:00:05:43
30.0%. Run time: 128.91s. Est. time left: 00:00:05:00
40.0%. Run time: 170.88s. Est. time left: 00:00:04:16
50.0%. Run time: 213.67s. Est. time left: 00:00:03:33
60.0%. Run time: 257.85s. Est. time left: 00:00:02:51
70.0%. Run time: 301.59s. Est. time left: 00:00:02:09
80.0%. Run time: 345.57s. Est. time left: 00:00:01:26
90.0%. Run time: 388.91s. Est. time left: 00:00:00:43
Total run time: 430.98s

In [52]:
plot_expectation_values([result, result_ref]);



In [53]:
fig, ax = subplots(figsize=(12,6))

for m in result.measurement:
    ax.plot(times, m[:, 0, 0].real / sqrt(gamma), 'r', alpha=0.025)
    ax.plot(times, m[:, 0, 1].real / sqrt(gamma), 'b', alpha=0.025)
    
ax.plot(times, array(result.measurement).mean(axis=0)[:,0,0].real / sqrt(gamma), 'r', lw=2);
ax.plot(times, array(result.measurement).mean(axis=0)[:,0,1].real / sqrt(gamma), 'b', lw=2);
ax.plot(times, result_ref.expect[1], 'k', lw=2);
ax.plot(times, result_ref.expect[2], 'k', lw=2);

ax.axis('tight')
ax.set_ylim(-25, 25);


Software version


In [54]:
from qutip.ipynbtools import version_table

version_table()


Out[54]:
SoftwareVersion
OSposix [linux]
Numpy1.9.0.dev-d4c7c3a
IPython2.0.0-b1
Cython0.20.post0
QuTiP3.0.0.dev-8072d41
SciPy0.15.0.dev-c04c506
Python3.3.2+ (default, Oct 9 2013, 14:50:09) [GCC 4.8.1]
matplotlib1.4.x
Wed Mar 12 15:54:27 2014 JST