**pyqo** is a python library similar to the *quantum optics toolbox* for
Matlab. It lets the user define state vectors and operators and provides
functionality to solve typical problems occurring in quantum optics, e.g.
solving Schroedinger or master equations.

To be able to use **pyqo** from a python script the **pyqo** library has
to be in your `PYTHONPATH` or in the same directory as the script that
uses it. Then it can for example be imported as:

```
>>> import pyqo as qo
```

In all following examples it is assumed that **pyqo** was imported in that
way.

All objects in **pyqo** are defined as tensors of different ranks. Taking
advantage of the power of numpy, they inherit from the mighty
`numpy.ndarray`. Obviously their dimensionality is limited by the
memory available on your system so it is impossible to calculate in
infinite dimensional Hilbert spaces.
For quantum states **pyqo** provides the class `pyqo.StateVector`. It
can be used to directly create states from nested lists or tuples (or
anything else that a numpy array can handle):

```
>>> psi = qo.StateVector([1,0])
>>> print(psi)
StateVector(2)
[ 1.+0.j 0.+0.j]
```

Alternatively there are some functions that create commonly used state vectors:

```
>>> psi = qo.basis(4,0)
>>> print(psi)
StateVector(4)
[ 1.+0.j 0.+0.j 0.+0.j 0.+0.j]
>>> psi = qo.coherent(10, 0.5)
```

Composing systems can be done with the tensor product between two states.
For this the operator `^` can be used.

```
>>> psi1 = qo.basis(2,0)
>>> psi2 = qo.basis(2,1)
>>> print(psi1 ^ psi2)
StateVector(2 x 2)
[[ 0.+0.j 1.+0.j]
[ 0.+0.j 0.+0.j]]
```

Note

The `^` operator follows the built-in operator precedence. That
means “*” and “+” have higher precedence!

Operators are represented by the `pyqo.Operator`. Like in the case of
state vectors operators can be constructed directly from a list or tuple:

```
>>> A = qo.Operator([[1,0], [0,-1]])
>>> print(A)
Operator
2 -> 2
[[ 1.+0.j 0.+0.j]
[ 0.+0.j -1.+0.j]]
```

Operators have some constraint on their shape - it has to be of the form .

Many commonly used operators are already defined:

```
>>> print(qo.sigmax)
Operator
2 -> 2
[[ 0.+0.j 1.+0.j]
[ 1.+0.j 0.+0.j]]
>>> print(qo.create(3))
Operator
3 -> 3
[[ 0.00000000+0.j 0.00000000+0.j 0.00000000+0.j]
[ 1.00000000+0.j 0.00000000+0.j 0.00000000+0.j]
[ 0.00000000+0.j 1.41421356+0.j 0.00000000+0.j]]
```

Composing operators of different systems can be done in the following way:

```
>>> s_z = qo.sigmaz
>>> s_p = qo.sigmap
>>> print(s_z^s_p)
Operator
2 x 2 -> 2 x 2
[[[[ 0.+0.j 0.+0.j]
[ 0.+0.j 0.+0.j]]
[[ 1.+0.j 0.+0.j]
[ 0.+0.j 0.+0.j]]]
[[[ 0.+0.j 0.+0.j]
[-0.+0.j -0.+0.j]]
[[ 0.+0.j 0.+0.j]
[-1.+0.j -0.+0.j]]]]
```