Instances of pygsti.objects.StateSpaceLabels
describe the structure of a model's state space and associate labels with the parts of that structure. This is particularly useful when dealing with multiple qubits or a qubit and its environment, as it can be useful to reference subspaces or subsystems of the entire quantum state space.
In general, a state space is the direct sum of one or more tensor product blocks, each of which is the tensor product of one or more factors:
$$ \mbox{State space} = (\mathcal{H}_1^A \otimes \mathcal{H}_2^A \otimes \cdots) \oplus (\mathcal{H}_1^B \otimes \mathcal{H}_2^B \otimes \cdots) \oplus \cdots$$In the above expression the tensor product blocks are in parenthesis and labelled by $A$, $B$, etc., and the $\mathcal{H}_i^X$ are the factors. We can initialize a StateSpaceLabels
object using a list of tuples containing labels and dimensions which mirror this structure, i.e.
StateSpaceLabels( [(H1A_label, H2A_label, ...), ((H1B_label, H2B_label, ...), ... ],
[(H1A_dim , H2A_dim, ...), ((H1B_dim , H2B_dim, ...), ... ])
where _label
variables are either strings or integers (it can be convenient to label qubits, for instance, by integers) and _dim
variables are always integers. Here are some examples:
import pygsti
from pygsti.objects import StateSpaceLabels
lbls = StateSpaceLabels([('H0','H1')], [(2,3)])
print(lbls) # label(dim) notation, '*' means 'otimes', '+' means 'oplus'
lbls2 = StateSpaceLabels(('H0','H1'), (2,3)) # same as above - a *single* tensor product block
print(lbls2)
lbls3 = StateSpaceLabels([('H0',), ('H1',)], [(2,),(3,)]) # direct sum
print(lbls3)
lbls4 = StateSpaceLabels([('H1a','H2a'), ('H1b','H2b')], [(2,1),(3,4)])
print(lbls4)
H0(2)*H1(3) H0(2)*H1(3) H0(2) + H1(3) H1a(2)*H2a(1) + H1b(3)*H2b(4)
Since we're often dealing with qubits (dimension = 2 factors), the labels beginning with 'Q' or that are integers default to dimension 2. Similarly, labels beginning with 'L' default dimension 1 (an additional "Level"). If all the labels in the first argument passed to the StateSpaceLabels
constructor have defaults, then the second argument (the dimensions) may be omitted. For example:
lbls5 = StateSpaceLabels(['Q0','Q1']) # 2 qubits
print(lbls5)
lbls6 = StateSpaceLabels(list(range(3))) # 3 qubits
print(lbls6)
lbls7 = StateSpaceLabels([('Q0','Q1'),('Leakage',)])
print(lbls7)
Q0(2)*Q1(2) 0(2)*1(2)*2(2) Q0(2)*Q1(2) + Leakage(1)
The raw data within a StateSpaceLabels
object is stored in the .labels
and .labeldims
members (but be careful, labeldims
is a dictionary):
lbls7.labels
(('Q0', 'Q1'), ('Leakage',))
lbls7.labeldims
{'Q0': 2, 'Q1': 2, 'Leakage': 1}
You can access the total dimensions of the state space using the .dim
member, which is a pygsti.baseobjs.Dim
object containing the following dimensions:
print("Dim object = ",lbls7.dim)
print("Separately: ",lbls7.dim.dmDim, lbls7.dim.blockDims, lbls7.dim.opDim, lbls7.dim.embedDim)
Dim object = Dim: dmDim 5 opDim 17 blockDims [4, 1] embedDim 25 Separately: 5 [4, 1] 17 25
There are also few convenience functions that make it easier to access the raw data:
print("Number of tensor product blocks = ",lbls7.num_tensor_prod_blocks())
print("The labels in the 0th tensor product block are: ",lbls7.tensor_product_block_labels(0))
print("The dimensions corresponding to those labels are: ",lbls7.tensor_product_block_dims(0))
print("The 'Q0' labels exists in the tensor product block w/index=",lbls7.tpb_index['Q0'])
print("The product of the dimensions associated with 'Q0' and 'Leakage' = ",lbls7.product_dim( ('Q0','Leakage') ))
Number of tensor product blocks = 2 The labels in the 0th tensor product block are: ('Q0', 'Q1') The dimensions corresponding to those labels are: (2, 2) The 'Q0' labels exists in the tensor product block w/index= 0 The product of the dimensions associated with 'Q0' and 'Leakage' = 2
That's it! You know all there is to know about the StateSpaceLabels
object. Remember you can pass a StateSpaceLabels
object to pygsti.construction.build_explicit_model
to create a model which operates on the given state space.