First Things First¶
In order to load the QuTiP library we must first call the import statement:
from qutip import *
In addition, it is often necessary to load addition mathematical functions and plotting features from the NumPy and Matplotlib libraries, respectively:
import numpy as np
import pylab as plt
Here we have imported the Numpy package as "np" so that the functions included in this module can be called using the np.func() syntax. In addition, the plotting functions from Pylab can be called via e.g. plt.plot().
It is important to note that if we choose to import all of the functions directly from the modules using
from numpy import *
from pylab import *
then the order in which we import QuTiP and these additional libraries is important. In general, if using this import style, you must import QuTiP last:
from numpy import *
from pylab import *
from qutip import *
The Quantum Object Class¶
Introduction¶
The key difference between classical and quantum mechanics lies in the use of operators instead of numbers as variables. Moreover, we need to specify state vectors and their properties. Therefore, in computing the dynamics of quantum systems we need a data structure that is capable of encapsulating the properties of a quantum operator and ket/bra vectors. The quantum object class, Qobj, accomplishes this using a sparse matrix representation.
To begin, let us create a blank Qobj:
Qobj()
where we see the blank Qobj object with dimensions, shape, and data. Here the data corresponds to a 1x1-dimensional sparse matrix consisting of a single zero entry.
We can create a Qobj with a user defined data set by passing a list or array of data into the Qobj:
x = np.array([[1, 2, 3, 4, 5]])
Qobj(x)
r = np.random.rand(4, 4)
Qobj(r)
Notice how both the dims and shape change according to the input data. Although dims and shape appear to have the same function, the difference will become quite clear in the section on tensor products and partial traces.
States and Operators¶
Manually specifying the data for each quantum object is inefficient. Even more so when most objects correspond to commonly used types such as the ladder operators of a harmonic oscillator, the Pauli spin operators for a two-level system, or state vectors such as Fock states. Therefore, QuTiP includes predefined objects for a variety of states:
| States | Command (# = optional) | Inputs |
|---|---|---|
| Fock State | `basis(N, #m)` or `fock(N, #m)` | N = # of levels in Hilbert space, m = level containing excitation (0 if m not given). |
| Fock State Density Matrix | `fock_dm(N, #m)` | Same as above. |
| Coherent State | `coherent(N, alpha)` | alpha = complex number (eigenvalue) defining coherent state. |
| Coherent State Density Matrix | `coherent_dm(N, alpha)` | Same as above. |
| Thermal State Density Matrix | `thermal_dm(N, n)` | n = particle number expectation value. |
and operators:
| Operator | Command (# = optional) | Inputs |
|---|---|---|
| Identity | `qeye(N)` or `identity(N)` | N = # of levels in Hilbert space. |
| Lowering (destruction) Operator | `destroy(N)` | |
| Raising (creation) Operator | `create(N)` | |
| Number Operator | `num(N)` | |
| Single-Mode Displacement Operator | `displace(N, alpha)` | alpha = Complex displacement amplitude. |
| Single-Mode Squeezing Operator | `squeeze(N, sp)` | sp = Squeezing parameter. |
| Pauli Pauli X-Operator (sigma-x) | `sigmax()` | |
| Pauli Spin Y-Operator (sigma-y) | `sigmay()` | |
| Pauli Spin Z-Operator (sigma-z) | `sigmaz()` | |
| Spin Raising Operator (sigma-plus) | `sigmap()` | |
| Spin Lowering Operator (sigma-minus) | `sigmam()` | |
| Higher-Spin Operators | `jmat(j, #s)` | j = int or half-int representing spin. s= 'x', 'y', 'z', '+', or '-'. |
As an example, we give the output for a few of these functions:
basis(5,3)
coherent(5,0.5-0.5j)
destroy(4)
sigmaz()
jmat(5/2.0,'+')
Qobj Attributes¶
We have seen that a quantum object has several internal attributes, such as data, dims, and shape. These can be accessed in the following way:
q = destroy(4)
q.dims
[[4], [4]]
q.shape
[4, 4]
In general, the attributes (properties) of a Qobj object (or any Python class) can be retrieved using the Q.attribute notation. In addition to the attributes shown with the print function, the Qobj class also has the following:
| Property | Attribute | Description |
|---|---|---|
| Data | Q.data | Sparse matrix representing quantum state or operator. |
| Dimensions | Q.dims | List keeping track of shapes for individual components of a multipartite system (for tensor products and partial traces). |
| Shape | Q.shape | Dimensions of underlying data matrix. |
| is Hermitian? | Q.isherm | Is operator Hermitian or not? |
| Type | Q.type |
The `Qobj` class viwed as a container for the properties needed to characterize a quantum operator or state vector.
For the destruction operator above:
q.type
'oper'
q.isherm
False
q.data
<4x4 sparse matrix of type '<class 'numpy.complex128'>' with 3 stored elements in Compressed Sparse Row format>
The data attribute returns a message stating that the data is a sparse matrix. All Qobj instances store their data as a sparse matrix to save memory. To access the underlying dense matrix one needs to use the Q.full() function as described below.
Qobj Math¶
The rules for mathematical operations on Qobj instances are similar to standard matrix arithmetic:
q = destroy(4)
x = sigmax()
q + 5
x * x
q ** 3
x / np.sqrt(2)
Of course, like matrices, multiplying two objects of incompatible shape throws an error:
q * x
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-40-c5138e004127> in <module>() ----> 1 q * x /opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/qutip-3.2.0.dev_0ba1b6a-py3.4-macosx-10.10-x86_64.egg/qutip/qobj.py in __mul__(self, other) 451 452 else: --> 453 raise TypeError("Incompatible Qobj shapes") 454 455 elif isinstance(other, (list, np.ndarray)): TypeError: Incompatible Qobj shapes
In addition, the logic operators is equal == and is not equal != are also supported.
Functions Acting on the Qobj Class¶
Like attributes, the quantum object class has defined functions (methods) that operate on Qobj class instances. For a general quantum object Q:
| Function | Command | Description |
|---|---|---|
| Hermicity Check | `Q.check_herm()` | Check if Qobj is Hermitian. |
| Conjugate | `Q.conj()` | Conjugate of Qobj. |
| Dagger (adjoint) | `Q.dag()` | Adjoint of Qobj. |
| Diagonal | `Q.diag()` | Returns array of diagonal elements. |
| Eigenenergies | `Q.eigenenergies()` | Eigenenergies (values) of a Qobj. |
| Eliminate States | `Q.eliminate_states(inds)` | Qobj with states is list 'inds' removed. |
| Exponential | `Q.expm()` | Matrix exponential of Qobj. |
| Extract States | `Q.extract_states(inds)` | Qobj with only states listed in 'inds'. |
| Full | `Q.full()` | Returns full (dense) array of Qobj data. |
| Groundstate | `Q.groundstate()` | Eigenvalue & vector of Qobj ground state. |
| Matrix Element | `Q.matrix_element(bra,ket)` | Matrix element <bra|Q|ket>. |
| Norm | `Q.norm()` | Returns L2-norm for states and trace norm for operators. |
| Overlap | `Q.overlap(state)` | Overlap between Qobj and a given state. |
| Partial Trace | `Q.ptrace(sel)` | Partial trace returning components selected using 'sel'. |
| Permute | `Q.permute(order)` | Permutes tensor structure of Qobj in a given order. |
| Sqrt | `Q.sqrt()` | Matrix sqrt of Qobj, |
| Tidyup | `Q.tidyup()` | Removes small elements from Qobj. |
| Trace | `Q.trace()` | Trace of Qobj. |
| Transform | `Q.transform(inpt)` | Basis transformation defined by matrix or list of kets given by 'inpt'. |
| Transpose | `Q.transpose()` | Transpose of Qobj. |
| Unit | `Q.unit()` | Returns normalized Qobj. |
basis(5, 3)
basis(5, 3).dag()
coherent_dm(5, 1)
coherent_dm(5, 1).diag()
array([ 0.36791117, 0.36757705, 0.18523331, 0.05810197, 0.0211765 ])
coherent_dm(5, 1).full()
array([[ 0.36791117+0.j, 0.36774407+0.j, 0.26105441+0.j, 0.14620658+0.j,
0.08826704+0.j],
[ 0.36774407+0.j, 0.36757705+0.j, 0.26093584+0.j, 0.14614018+0.j,
0.08822695+0.j],
[ 0.26105441+0.j, 0.26093584+0.j, 0.18523331+0.j, 0.10374209+0.j,
0.06263061+0.j],
[ 0.14620658+0.j, 0.14614018+0.j, 0.10374209+0.j, 0.05810197+0.j,
0.03507700+0.j],
[ 0.08826704+0.j, 0.08822695+0.j, 0.06263061+0.j, 0.03507700+0.j,
0.02117650+0.j]])
coherent_dm(5, 1).norm()
1.0
coherent_dm(5, 1).sqrtm()
coherent_dm(5, 1).tr()
1.0
(basis(4, 2) + basis(4, 1)).unit()
from IPython.core.display import HTML
def css_styling():
styles = open("../styles/guide.css", "r").read()
return HTML(styles)
css_styling()