Skip to content

Commit

Permalink
Merge pull request #258 from pyGSTio/feature-nqubit-fogi
Browse files Browse the repository at this point in the history
Feature nqubit fogi
  • Loading branch information
Erik authored Aug 15, 2022
2 parents 97b00f9 + 7188ccb commit d0148a3
Show file tree
Hide file tree
Showing 39 changed files with 1,696 additions and 706 deletions.
41 changes: 32 additions & 9 deletions pygsti/baseobjs/errorgenbasis.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ class ElementaryErrorgenBasis(object):
Intersection and union can be performed as a set.
"""

def label_indices(self, labels):
def label_indices(self, labels, ok_if_missing=False):
""" TODO: docstring """
return [self.label_index(lbl) for lbl in labels]
return [self.label_index(lbl, ok_if_missing) for lbl in labels]

def __len__(self):
""" Number of elementary errorgen elements in this basis """
Expand All @@ -46,7 +46,7 @@ def __init__(self, state_space, labels, basis1q=None):

self.state_space = state_space
assert(self.state_space.is_entirely_qubits), "FOGI only works for models containing just qubits (so far)"
sslbls = self.state_space.tensor_product_block_labels(0) # all the model's state space labels
sslbls = self.state_space.sole_tensor_product_block_labels # all the model's state space labels
self.sslbls = sslbls # the "support" of this space - the qubit labels
self._cached_elements = None

Expand All @@ -64,10 +64,14 @@ def elemgen_supports_and_matrices(self):
for elemgen_label in self.labels))
return self._cached_elements

def label_index(self, label):
def label_index(self, label, ok_if_missing=False):
"""
TODO: docstring
ok_if_missing : bool
If True, then returns `None` instead of an integer when the given label is not present.
"""
if ok_if_missing and label not in self._label_indices:
return None
return self._label_indices[label]

#@property
Expand Down Expand Up @@ -231,7 +235,7 @@ def _create_ordered_labels(cls, type_str, basis_1q, state_space,

if max_weight is None:
assert(state_space.is_entirely_qubits), "FOGI only works for models containing just qubits (so far)"
sslbls = state_space.tensor_product_block_labels(0) # all the model's state space labels
sslbls = state_space.sole_tensor_product_block_labels # all the model's state space labels
max_weight = len(sslbls)

# Let k be len(nontrivial_bels)
Expand Down Expand Up @@ -292,7 +296,7 @@ def _create_ordered_label_offsets(cls, type_str, basis_1q, state_space,

if max_weight is None:
assert(state_space.is_entirely_qubits), "FOGI only works for models containing just qubits (so far)"
sslbls = state_space.tensor_product_block_labels(0) # all the model's state space labels
sslbls = state_space.sole_tensor_product_block_labels # all the model's state space labels
max_weight = len(sslbls)

# Let k be len(nontrivial_bels)
Expand Down Expand Up @@ -366,7 +370,7 @@ def __init__(self, basis_1q, state_space, elementary_errorgen_types=('H', 'S', '

#Note: state space can have additional labels that aren't in support
# (this is, I think, only true when must_overlap_with_these_sslbls != None)
sslbls = self.state_space.tensor_product_block_labels(0) # all the model's state space labels
sslbls = self.state_space.sole_tensor_product_block_labels # all the model's state space labels

if set(sslbls) == present_sslbls:
self.sslbls = sslbls # the "support" of this space - the qubit labels
Expand Down Expand Up @@ -421,6 +425,15 @@ def labels(self):
self._must_overlap_with_these_sslbls))
return tuple(labels)

@property
def elemgen_supports_and_dual_matrices(self):
return tuple(((elemgen_label.sslbls,
_ot.create_elementary_errorgen_nqudit_dual(
elemgen_label.errorgen_type, elemgen_label.basis_element_labels,
self._basis_1q, normalize=False, sparse=False,
tensorprod_basis=True)) # Note: normalize was set to True...
for elemgen_label in self.labels))

@property
def elemgen_supports_and_matrices(self):
return tuple(((elemgen_label.sslbls,
Expand All @@ -430,24 +443,34 @@ def elemgen_supports_and_matrices(self):
tensorprod_basis=True)) # Note: normalize was set to True...
for elemgen_label in self.labels))

def label_index(self, elemgen_label):
def label_index(self, elemgen_label, ok_if_missing=False):
"""
TODO: docstring
ok_if_missing : bool
If True, then returns `None` instead of an integer when the given label is not present.
"""
support = elemgen_label.sslbls
eetype = elemgen_label.errorgen_type
bels = elemgen_label.basis_element_labels
trivial_bel = self._basis_1q.labels[0] # assumes first element is identity
nontrivial_bels = self._basis_1q.labels[1:]

if ok_if_missing and eetype not in self._offsets:
return None

if eetype in ('H', 'S'):
if ok_if_missing and support not in self._offsets[eetype]:
return None
base = self._offsets[eetype][support]
indices = {lbl: i for i, lbl in enumerate(self._create_diag_labels_for_support(support, eetype,
nontrivial_bels))}
elif eetype in ('C', 'A'):
assert(len(trivial_bel) == 1) # assumes this is a single character
nontrivial_inds = [i for i, letter in enumerate(bels[0]) if letter != trivial_bel]
left_support = tuple([self.sslbls[i] for i in nontrivial_inds])

if ok_if_missing and (support, left_support) not in self._offsets[eetype]:
return None
base = self._offsets[eetype][(support, left_support)]

indices = {lbl: i for i, lbl in enumerate(self._create_uptriangle_labels_for_support(
Expand Down Expand Up @@ -509,7 +532,7 @@ def difference(self, other_basis):
# self._must_overlap_with_these_sslbls = must_overlap_with_these_sslbls
#
# assert(self.state_space.is_entirely_qubits), "FOGI only works for models containing just qubits (so far)"
# sslbls = self.state_space.tensor_product_block_labels(0) # all the model's state space labels
# sslbls = self.state_space.sole_tensor_product_block_labels # all the model's state space labels
# self.sslbls = sslbls # the "support" of this space - the qubit labels
#
# self._cached_label_indices = None
Expand Down
41 changes: 40 additions & 1 deletion pygsti/baseobjs/errorgenlabel.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,11 @@ def cast(cls, obj, sslbls=None, identity_label='I'):
else:
raise ValueError("Cannot convert %s to a global elementary errorgen label!" % str(obj))

def __init__(self, errorgen_type, basis_element_labels, sslbls):
def __init__(self, errorgen_type, basis_element_labels, sslbls, sort=True):
if sort:
sorted_indices, sslbls = zip(*sorted(enumerate(sslbls), key=lambda x: x[1]))
basis_element_labels = [''.join([bel[i] for i in sorted_indices]) for bel in basis_element_labels]

self.errorgen_type = str(errorgen_type)
self.basis_element_labels = tuple(basis_element_labels)
self.sslbls = tuple(sslbls)
Expand Down Expand Up @@ -183,3 +187,38 @@ def padded_basis_element_labels(self, all_sslbls, identity_label='I'):
lbl[i] = char
ret.append(''.join(lbl))
return tuple(ret)

def map_state_space_labels(self, mapper):
"""
Creates a new GlobalElementaryErrorgenLabel whose `sslbls` attribute is updated according to a mapping function.
Parameters
----------
mapper : dict or function
A dictionary whose keys are the existing `self.sslbls` values
and whose value are the new labels, or a function which takes a
single existing state space label argument and returns a new state
space label to replace it with.
Returns
-------
GlobalElementaryErrorgenLabel
"""
def mapper_func(sslbl): return mapper[sslbl] \
if isinstance(mapper, dict) else mapper(sslbl)
mapped_sslbls = tuple(map(mapper_func, self.sslbls))
return GlobalElementaryErrorgenLabel(self.errorgen_type, self.basis_element_labels, mapped_sslbls)

def sort_sslbls(self):
"""
Creates a new GlobalElementaryErrorgenLabel with sorted (potentially reordered) state space labels.
This puts the label into a canonical form that can be useful for comparison with other labels.
Returns
-------
GlobalElementaryErrorgenLabel
"""
sorted_indices, sorted_sslbls = zip(*sorted(enumerate(self.sslbls), key=lambda x: x[1]))
sorted_bels = [''.join([bel[i] for i in sorted_indices]) for bel in self.basis_element_labels]
return GlobalElementaryErrorgenLabel(self.errorgen_type, sorted_bels, sorted_sslbls)
4 changes: 2 additions & 2 deletions pygsti/baseobjs/errorgenspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def __init__(self, vectors, basis):
# map sslbls => (vectors, basis) where basis.sslbls == sslbls
# or basis => vectors if bases can hash well(?)

def intersection(self, other_space, free_on_unspecified_space=False):
def intersection(self, other_space, free_on_unspecified_space=False, use_nice_nullspace=False):
"""
TODO: docstring
"""
Expand All @@ -56,7 +56,7 @@ def intersection(self, other_space, free_on_unspecified_space=False):
i += Wl
VIWI[common_basis.label_indices(diff_other.labels), i:i + Wli] = _np.identity(Wli, dtype)

ns = _mt.nullspace(VIWI)
ns = _mt.nice_nullspace(VIWI) if use_nice_nullspace else _mt.nullspace(VIWI)
intersection_vecs = _np.dot(VIWI[:, 0:(Vl + Vli)], ns[0:(Vl + Vli), :]) # on common_basis

else:
Expand Down
12 changes: 12 additions & 0 deletions pygsti/baseobjs/statespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ def num_tensor_product_blocks(self):
"""
raise NotImplementedError("Derived classes should implement this!")

@property
def sole_tensor_product_block_labels(self):
"""
The labels of the first and only tensor product block within this state space.
If there are multiple blocks, a ValueError is raised.
"""
if self.num_tensor_product_blocks > 1:
raise ValueError(("Attribute `sole_tensor_product_block_labels` was used but this state space has"
" %d blocks!") % self.num_tensor_product_blocks)
return self.tensor_product_block_labels(0)

@property
def tensor_product_blocks_labels(self):
"""
Expand Down
1 change: 1 addition & 0 deletions pygsti/circuits/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@
GermFiducialPairPlaquette, PlaquetteGridCircuitStructure

from .circuitconstruction import *
from .cloudcircuitconstruction import *
from .gstcircuits import *
# Unused: from rpecircuits import *
Loading

0 comments on commit d0148a3

Please sign in to comment.