Timing for QobjEvo

Made by Eric Giguere

In [1]:
import qutip as qt
import numpy as np
from qutip import QobjEvo
%load_ext cython
In [2]:
N = 10
destroy, create, Id = qt.destroy(N), qt.create(N), qt.qeye(N)
def exp_i(t,args):
    return np.exp(-1j*t)
def cos_w(t,args):
    return np.cos(args["w"]*t)
tlist = np.linspace(0,10,10000)
tlistlog = np.logspace(-3,1,10000)

# state vector as np array
vec = np.arange(N)*.5+.5j
vec_super = np.arange(N**2)*.5+.5j
mat_c = (np.arange(N**2)*.5+.5j).reshape((10,10))
mat_f = np.asfortranarray(mat_c*1.)

# Construct QobjEvo of all type
td_cte1 = QobjEvo(Id)
td_cte2 = QobjEvo([Id])

td_func = QobjEvo([Id,[create,exp_i],[destroy,cos_w]],args={"w":2})
td_str = QobjEvo([Id,[create,"exp(-1j*t)"],[destroy,"cos(w*t)"]],args={'w':2.})
td_array = QobjEvo([Id,[create,np.exp(-1j*tlist)],[destroy,np.cos(2*tlist)]],tlist=tlist)
td_array_log = QobjEvo([Id,[create,np.exp(-1j*tlistlog)],[destroy,np.cos(2*tlistlog)]],tlist=tlistlog)

td_super = qt.liouvillian(td_func, c_ops=td_cte1)

Timing: call

Timing check for all coeff formats.
Once compiled, the cython method is called by the usual method.

In [3]:
# The compiled version build the scipy object from the sparce matrix if not used with data=True
print("Time for cte")
td_cte1.compiled = False
%timeit td_cte1(2)
%timeit td_cte1(2, data=True)
print("Time for compiled cte")
td_cte1.compile()
%timeit td_cte1(2)
%timeit td_cte1(2, data=True)
Time for cte
31.5 µs ± 442 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
7.3 µs ± 115 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Time for compiled cte
32.3 µs ± 737 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
7.18 µs ± 60.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [4]:
print("Time for str")
td_str.compiled = False
%timeit td_str(2)
%timeit td_str(2, data=True)
td_str.compile()
%timeit td_str(2)
%timeit td_str(2, data=True)
Time for str
453 µs ± 18.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
140 µs ± 1.11 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
45.9 µs ± 3.69 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
9.67 µs ± 306 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [5]:
print("Time for function")
td_func.compiled = False
%timeit td_func(2)
%timeit td_func(2, data=True)
td_func.compile()
%timeit td_func(2)
%timeit td_func(2, data=True)
Time for function
394 µs ± 7.31 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
103 µs ± 1.15 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
50.2 µs ± 464 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
13.5 µs ± 551 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [6]:
print("Time for array")
td_array.compiled = False
%timeit td_array(2)
%timeit td_array(2, data=True)
td_array.compile()
%timeit td_array(2)
%timeit td_array(2, data=True)
Time for array
443 µs ± 12.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
166 µs ± 25.8 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
47 µs ± 2.91 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
9.54 µs ± 190 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [7]:
print("Time for array with variable time step")
td_array_log.compiled = False
%timeit td_array_log(2)
%timeit td_array_log(2, data=True)
td_array_log.compile()
%timeit td_array_log(2)
%timeit td_array_log(2, data=True)
Time for array with variable time step
447 µs ± 7.13 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
145 µs ± 2.71 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
44.8 µs ± 532 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
9.57 µs ± 168 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Timing: multiplication with a vector

The QobjEvo at t x vec, used by most solver

In [8]:
print("timing for rhs: cte")
td_cte1.compiled = False
%timeit qt.cy.spmv(td_cte1(2, data=True), vec)
%timeit qt.cy.spmv(Id.data, vec)
%timeit td_cte1.mul_vec(2,vec)
td_cte1.compile()
%timeit td_cte1.mul_vec(2,vec)
timing for rhs: cte
13.6 µs ± 133 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
4.51 µs ± 63.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
16.2 µs ± 77.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
4.18 µs ± 35.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [9]:
print("timing for rhs: str")
td_str.compiled = False
%timeit qt.cy.spmv(td_str(2, data=True), vec)
%timeit td_str.mul_vec(2,vec)
td_str.compile()
%timeit td_str.mul_vec(2,vec)
timing for rhs: str
157 µs ± 1.82 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
160 µs ± 1.04 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
5.39 µs ± 53.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [10]:
print("timing for rhs: cte")
td_func.compiled = False
%timeit qt.cy.spmv(td_func(2, data=True), vec)
%timeit td_func.mul_vec(2,vec)
td_func.compile()
%timeit td_func.mul_vec(2,vec)
timing for rhs: cte
115 µs ± 999 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
129 µs ± 10.2 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
12.1 µs ± 2.23 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [11]:
print("timing for rhs: cte")
td_array.compiled = False
%timeit qt.cy.spmv(td_array(2, data=True), vec)
%timeit td_array.mul_vec(2,vec)
td_array.compile()
%timeit td_array.mul_vec(2,vec)
timing for rhs: cte
160 µs ± 6.56 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
162 µs ± 6.32 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
6.1 µs ± 565 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [12]:
print("timing for rhs: cte")
td_array_log.compiled = False
%timeit qt.cy.spmv(td_array_log(2, data=True), vec)
%timeit td_array_log.mul_vec(2,vec)
td_array_log.compile()
%timeit td_array_log.mul_vec(2,vec)
timing for rhs: cte
170 µs ± 17.1 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
157 µs ± 1.65 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
5.66 µs ± 169 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Timing: multiplication with matrix

QobjEvo at t time same shape matrix, used for operator evolution

In [13]:
print("timing for mul_mat: c format sparce")
td_str.compiled = False
%timeit td_str(2, data=True) * mat_c
%timeit td_str.mul_mat(2,mat_c)
td_str.compile()
%timeit td_str.mul_mat(2,mat_c)
timing for mul_mat: c format sparce
159 µs ± 4 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
164 µs ± 2.2 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
8.41 µs ± 109 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [14]:
print("timing for mul_mat: c format dense")
td_str.compiled = False
%timeit td_str(2, data=True) * mat_c
%timeit td_str.mul_mat(2,mat_c)
td_str.compile(dense=True)
%timeit td_str.mul_mat(2,mat_c)
timing for mul_mat: c format dense
156 µs ± 1.31 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
162 µs ± 1.23 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
9.15 µs ± 99.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [15]:
print("timing for mul_mat: f format sparce")
td_str.compiled = False
%timeit td_str(2, data=True) * mat_f
%timeit td_str.mul_mat(2,mat_f)
td_str.compile()
%timeit td_str.mul_mat(2,mat_f)
timing for mul_mat: f format sparce
159 µs ± 1.81 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
170 µs ± 4.01 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
6.25 µs ± 76.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [16]:
print("timing for mul_mat: f format dense")
td_str.compiled = False
%timeit td_str(2, data=True) * mat_f
%timeit td_str.mul_mat(2,mat_f)
td_str.compile(dense=True)
%timeit td_str.mul_mat(2,mat_f)
timing for mul_mat: f format dense
159 µs ± 2.91 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
171 µs ± 6.09 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
10.2 µs ± 432 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Timing: expect

expectation value of QobjEvo(t) and psi/rho

In [17]:
print("timing for expect: cte")
td_cte1.compiled = False
%timeit qt.cy.cy_expect_psi(td_cte1(2, data=True), vec, 0)
%timeit td_cte1.expect(2,vec,0)
td_cte1.compile()
%timeit td_cte1.expect(2,vec,0)
timing for expect: cte
11.4 µs ± 92.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
16.2 µs ± 264 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
5.56 µs ± 63.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [18]:
print("timing for expect: str")
td_str.compiled = False
%timeit qt.cy.cy_expect_psi(td_str(2, data=True), vec, 0)
%timeit td_str.expect(2,vec,0)
td_str.compile()
%timeit td_str.expect(2,vec,0)
timing for expect: str
152 µs ± 1.35 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
163 µs ± 2.68 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
6.92 µs ± 61.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [19]:
print("timing for expect: func")
td_func.compiled = False
%timeit qt.cy.cy_expect_psi(td_func(2, data=True), vec, 0)
%timeit td_func.expect(2,vec,0)
td_func.compile()
%timeit td_func.expect(2,vec,0)
timing for expect: func
119 µs ± 4.36 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
121 µs ± 3.62 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
12.1 µs ± 393 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [20]:
print("timing for expect: array")
td_array.compiled = False
%timeit qt.cy.cy_expect_psi(td_array(2, data=True), vec, 0)
%timeit td_array.expect(2,vec,0)
td_array.compile()
%timeit td_array.expect(2,vec,0)
timing for expect: array
200 µs ± 46.8 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
163 µs ± 7.36 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
10.1 µs ± 2.1 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [21]:
print("timing for expect: array logscale")
td_array_log.compiled = False
%timeit qt.cy.cy_expect_psi(td_array_log(2, data=True), vec, 0)
%timeit td_array_log.expect(2,vec,0)
td_array_log.compile()
%timeit td_array_log.expect(2,vec,0)
timing for expect: array logscale
156 µs ± 7.88 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
158 µs ± 4.11 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
7.14 µs ± 40.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [22]:
print("timing for expect_rho: func")
td_super.compiled = False
%timeit qt.cy.cy_expect_rho_vec(td_super(2, data=True), vec_super, 0)
%timeit td_super.expect(2,vec_super,0)
td_super.compile()
%timeit td_super.expect(2,vec_super,0)
timing for expect_rho: func
121 µs ± 1.99 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
127 µs ± 579 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
9.28 µs ± 67.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Timing: call with other arguments

In [23]:
td_args = QobjEvo([Id,[destroy,cos_w]],args={"w":1})
In [24]:
print("timing for function")
%timeit td_args(2, args={"w":2})
%timeit td_args(2)
%timeit td_args(2, args={"w":2}, data=True)
%timeit td_args(2, data=True)
td_args.compile()
%timeit td_args(2, args={"w":2})
%timeit td_args(2)
%timeit td_args(2, args={"w":2}, data=True)
%timeit td_args(2, data=True)
timing for function
212 µs ± 3.18 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
207 µs ± 1.65 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
60.2 µs ± 2.19 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
62.1 µs ± 2.68 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
225 µs ± 19.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
47 µs ± 487 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
58.5 µs ± 838 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
10.9 µs ± 139 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [25]:
td_args = QobjEvo([Id,[destroy,"cos(w*t)"]],args={"w":1})
In [26]:
print("timing for string")
%timeit td_args(2, args={"w":2})
%timeit td_args(2)
%timeit td_args(2, args={"w":2}, data=True)
%timeit td_args(2, data=True)
td_args.compile()
%timeit td_args(2, args={"w":2})
%timeit td_args(2)
%timeit td_args(2, args={"w":2}, data=True)
%timeit td_args(2, data=True)
timing for string
251 µs ± 5.55 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
244 µs ± 11.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
76.7 µs ± 493 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
74.3 µs ± 834 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
245 µs ± 6.85 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
44 µs ± 1.36 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
76.4 µs ± 518 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
8.37 µs ± 86 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Timing: call that depends on state

In [27]:
def coeff_state(t, args):
    return np.max(args["vec"])*args["w"]
td_state = QobjEvo([Id, [destroy, coeff_state]],args={"w":1,"vec=vec":vec})
%timeit td_state(2, state=vec, data=True)
td_state.compile()
%timeit td_state(2, state=vec, data=True)
68.2 µs ± 2.79 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
17.7 µs ± 409 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [28]:
def coeff_state(t, args):
    return args["e1"]
td_state = QobjEvo([Id, [destroy, coeff_state]], args={"e1=expect":qt.qeye(N)})
%timeit td_state(2, state=vec, data=True)
td_state.compile()
%timeit td_state(2, state=vec, data=True)
76.4 µs ± 673 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
17.5 µs ± 162 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [29]:
td_state = QobjEvo([Id, [destroy, "e1"]], args={"e1=expect":qt.qeye(N)})
%timeit td_state(2, state=vec, data=True)
td_state.compile()
%timeit td_state(2, state=vec, data=True)
93 µs ± 772 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
17.1 µs ± 341 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [30]:
qt.about()
QuTiP: Quantum Toolbox in Python
Copyright (c) 2011 and later.
A. J. Pitchford, P. D. Nation, R. J. Johansson, A. Grimsmo, and C. Granade

QuTiP Version:      4.4.0.dev0+1a639d7a
Numpy Version:      1.16.3
Scipy Version:      1.2.1
Cython Version:     0.29.7
Matplotlib Version: 3.0.3
Python Version:     3.7.3
Number of CPUs:     2
BLAS Info:          INTEL MKL
OPENMP Installed:   False
INTEL MKL Ext:      True
Platform Info:      Darwin (x86_64)
Installation path:  /Users/nathanshammah/miniconda3/envs/qobjevo/lib/python3.7/site-packages/qutip-4.4.0.dev0+1a639d7a-py3.7-macosx-10.7-x86_64.egg/qutip
==============================================================================
Please cite QuTiP in your publication.
==============================================================================
For your convenience a bibtex reference can be easily generated using `qutip.cite()`