Consider the space of density matrices corresponding to a Hilbert space $\mathcal{H}$ of dimension $d$. The basis used for this Hilbert-Schmidt space, $B(\mathcal{H})$, can be any set of $d\times d$ matrices which span the density matrix space. pyGSTi supports arbitrary bases by deriving from the `pygsti.tools.Basis`

class, and constains built-in support for the following basis sets:

- the matrix unit, or "standard" basis, consisting of the matrices with a single unit (1.0) element and otherwise zero. This basis is selected by passing
`"std"`

to appropriate function arguments. - the Pauli-product basis, consisting of tensor products of the four Pauli matrices {I, X, Y, Z} normalized so that $Tr(B_i B_j) = \delta_{ij}$. All of these matrices are Hermitian, so that Hilbert-Schmidt vectors and matrices are real when this basis is used. This basis can only be used when the $d = 4^i$ for integer $i$, and is selected using the string
`"pp"`

. - the Gell-Mann basis, consisting of the normalized Gell-Mann matrices (see Wikipedia if you don't know what these are). Similar to the Pauli-product case, these matrices are also Hermitian, so that Hilbert-Schmidt vectors and matrices are real when this basis is used. Unlike the Pauli-product case, since Gell-Mann matrices are well defined in any dimension, the Gell-Mann basis is
*not*restricted to cases when $d=4^i$. This basis is selected using the string`"gm"`

. - a special basis of $3 \times 3$ matricies designed for Qutrit systems formed by taking the symmetric subspace of a 2-qubit system. This basis is selected using the string
`"qt"`

.

Various functions and objects within pyGSTi require knowledge of what Hilbert-Schmidt basis is being used. The `pygsti.objects.Basis`

object encapsulates a basis, and is the most flexible way of specifying a basis in pyGSTi. Alternatively, many functions also accept the short strings `"std"`

, `"gm"`

, `"pp"`

, and `"qt"`

to select one of the standard bases. In this tutorial, we'll demonstrate how to create a `Basis`

object and use it and related functions to obtain and change the basis of the operation matrices and SPAM vectors stored in a `Model`

.

The most straightforward way to create a `Basis`

object is to provide its short name and dimension to the `Basis.cast`

function, which "casts" various things as a basis object. PyGSTi contains built-in support for bases consisting of the tensor product of Pauli matrices (or just the Pauli matrices in the case of 1 qubit), named `"pp"`

, as well as the Gell-Mann matrices, named `"gm"`

. It also contains a special "qutrit" basis, named `"qt"`

, for the case of 3-level quantum systems. In cases when there are an integral number of qubits, and the dimension equals $4^N$, the `"pp"`

basis is usually preferred since it is more intuitive. In other cases, where the Hilbert space includes non-qubit (e.g. environmental) degrees of freedom, the Gell-Mann basis may be useful since it can be used in any dimension. Note that both the Gell-Mann and Pauli-Product bases reduce to the usual Pauli matrices plus identity in when the dimension equals 4 (1 qubit).

Here are some examples:

In [ ]:

```
import pygsti
from pygsti import Basis
pp = Basis.cast('pp', 4) # Pauli-product (in this dim=4 case, just the Paulis)
std = Basis.cast('std', 4) # "standard" basis of matrix units
gm = Basis.cast('gm', 4) # Gell-Mann
qt = Basis.cast('qt', 9) # qutrit - must be dim 9
bases = [pp, std, gm, qt]
```

Each of the `pp`

, `std`

, and `gm`

bases created will have $4$ $2x2$ matrices each. The `qt`

basis has $9$ $3x3$ matrices instead:

In [ ]:

```
for basis in bases:
print('\n{} basis (dim {}):'.format(basis.name, basis.dim))
print('{} elements:'.format(len(basis)))
for element in basis:
pygsti.tools.print_mx(element)
```

However, custom "explicit" bases, which expicitly hold a set of basis-element matrices, can be easily created by supplying a list of the elements:

In [ ]:

```
import numpy as np
from pygsti.objects import ExplicitBasis
std2x2Matrices = [
np.array([[1, 0],
[0, 0]]),
np.array([[0, 1],
[0, 0]]),
np.array([[0, 0],
[1, 0]]),
np.array([[0, 0],
[0, 1]])]
alt_standard = ExplicitBasis(std2x2Matrices, ["myElement%d" % i for i in range(4)],
name='std', longname='Standard')
print(alt_standard)
```

More complex bases can be created by chaining the elements of other bases together along the diagonal. This yields a basis for the direct-sum of the spaces spanned by the original basis. For example, a composition of the $2x2$ `std`

basis with the $1x1$ `std`

basis leads to a basis with state vectors of length $5$, or $5x5$ matrices:

In [ ]:

```
from pygsti.objects import DirectSumBasis
comp = Basis.cast('std', [4, 1])
comp = Basis.cast([('std', 4), ('std', 1)])
comp = DirectSumBasis([ Basis.cast('std', 4), Basis.cast('std', 1)])
#All three comps above give the same final basis
print(comp)
for element in comp.elements:
print(element)
```

Once created, bases are used to manipulate matrices and vectors within pygsti:

In [ ]:

```
from pygsti.tools import change_basis, flexible_change_basis
mx = np.array([[1, 0, 0, 1],
[0, 1, 2, 0],
[0, 2, 1, 0],
[1, 0, 0, 1]])
change_basis(mx, 'std', 'gm') # shortname lookup
change_basis(mx, std, gm) # object only
change_basis(mx, std, 'gm') # combination
```

Composite bases can be converted between expanded and contracted forms:

In [ ]:

```
mxInStdBasis = np.array([[1,0,0,2],
[0,0,0,0],
[0,0,0,0],
[3,0,0,4]],'d')
begin = Basis.cast('std', 4)
end = Basis.cast('std', [1,1])
mxInReducedBasis = flexible_change_basis(mxInStdBasis, begin, end)
print(mxInReducedBasis)
original = flexible_change_basis(mxInReducedBasis, end, begin)
```

In [ ]:

```
```