Quantum Objects

The primary user-facing type is Qobj, which all users will have interacted with as it represents any quantum object in QuTiP. Qobj consists of two major components: the underlying data representation of the object, and information about what object is being represented. In fact, Qobj itself is only really responsible for managing this “auxiliary” information, ensuring that all mathematical operations on the data make sense, and neatly wrapping the data-layer functions to be more convenient for the user. All the numeric heavy lifting is handled by the data layer.

Data Store

The data is actually stored in the data attribute of a Qobj. This is always a “data-layer type”, which will be covered in more detail in the coming sections. The different available types store the data in different manners, such as full two-dimensional dense matrices (like NumPy arrays) or compressed sparse matrix formats, as different formats have different advantages. Qobj in general does not care what form its data is stored in, as all numerical operations are handed off to the data-layer dispatchers, which will ensure the correct specialised methods are called.

Typically these data layer types do not expose buffers to Python-space programmes directly, though individual types may have an as_array(), as_scipy(), or similar method. This is for speed and memory-safety. Once Python can access the underlying data buffers directly, all references to them must be managed by the garbage collector to ensure that nothing goes stale, even if only partial slices onto the data are taken. To access a copy of the data, Qobj exposes the full() method, which will always return a two-dimensional numpy.ndarray. If your object is too large to reasonably have a dense-matrix representation, you will need to use the specific methods on the data-layer type that is used.

The amount of information guaranteed to be stored by data-layer types is very small—sufficient to know whether a linear algebra operation can take place. This is currently just the shape of the data being represented; there is no information on Hilbert space (tensor product) dimensions, what type of object the data represents, or anything else. This is all managed by Qobj.

Auxiliary Information

Qobj contains several pieces of auxiliary information about the object being represented. The major parts are:


The tensor-product structure that this quantum object lives in. This is a list of two elements—the “left” dimensions and the “right” dimensions. For example, an operator on a Hilbert space formed of two qubits has dims of [[2, 2], [2, 2]]. A state (a “ket”) in the same space has dimensions of [[2, 2], [1, 1]]. The data structure storing these two objects would not keep this information; the shape attributes would respectively be simply (4, 4) and (4, 1).


The type of object represented by this Qobj. This is typically derived from dims. This is a string, containing a human-readable description of what type the object is, such as "oper", "ket" or "bra".


If this object is a super-operator, then this attribute is a string describing the particular representation used, such as the default "super" or something more specific like "choi".


As Qobj is the primary Python user-facing type, it provides all the Python niceties and “magic” methods, such as __add__(), __mul__() and so forth. Qobj will check that the operation makes sense, returning NotImplemented on failure, but a successful output will typically require passing off to the data layer. The data layer types themselves generally do not have these magic methods, as they are not designed to be manipulated by user code in Python.

In addition to the operator-overloading methods, Qobj also provides many quantum-specific mathematical operations, such as dag(), norm(), proj() and eigenstates(). Typically these are pass-throughs to the data layer, as Qobj accesses its own data using the abstract interface defined there.

Qobj adds in its own __repr__() methods for nice output in REPLs, and includes IPython and Jupyter integration. When running in a rich environment, the _repr_latex_() method will be called to better format the output.