Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature nqubit fogi #258

Merged
merged 24 commits into from
Aug 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7c498a0
The beginning of a series of updates to get the FOGI analysis working…
Mar 23, 2022
5ce3570
Adds StateSpace.sole_tensor_product_block_labels attribute.
Mar 23, 2022
1725368
Fixes and updates FOGI analysis for LocalNoiseModels; particularly ss…
Mar 31, 2022
8581c28
Fixes a bug in matrixtools.nullspace (forgotten .conjugate()!)
Mar 31, 2022
7a6a81d
Updates setup_fogi within implicit (local noise) models to work with …
Mar 31, 2022
ed06ca6
Fixes independent_spam=True SPAM construction of a cloud noise model.
Mar 31, 2022
90f4dfb
Adds FOGI analysis to cloud noise models; checks results with std 2Q …
Apr 6, 2022
a75af03
Switches nullspace -> nice_nullspace within gauge space intersection.
Apr 6, 2022
c8fceb6
Adds an optional `primitive_op_labels` argument to setup_fogi methods.
Apr 6, 2022
b2f2432
Consolidates setup_fogi methods into OpModel.setup_fogi.
Apr 6, 2022
485781b
Updates models to allow FOGI parameterization in implicit models.
Apr 8, 2022
c74906d
Updates ComposedOp.errorgen_coefficients_array_deriv_wrt_params to be…
Apr 8, 2022
525ecf4
Updates create_cloudnoise_circuits to work when max_idle_weight=0 (an…
Apr 8, 2022
96c9fd0
Adds a try/except guard to ConfidenceRegionFactory.compute_hessian fo…
Apr 8, 2022
77f357c
Updates several docstrings.
Apr 8, 2022
99cffa6
Adds a few minor updates to CloudCrosstalkModel construction in bound…
Apr 12, 2022
84d1a06
Adds 'only_global' implicit idle mode.
Apr 28, 2022
03b84b2
Fixes a minor bug in cloud circuit construction to prevent a warning.
Apr 28, 2022
d581092
Changes a hardcoded 'pp' to 'PP', which is more correct but maybe not…
Apr 28, 2022
7bc444e
Adds temporary debugging statements for debugging FOGI vector sparsity.
Apr 28, 2022
dc412a5
Changes list to tuple to hopefully correct include_spam=False behavior.
May 5, 2022
a790660
Updates unit tests for nqubit-fogi updates.
Aug 12, 2022
da5ba2e
Merge branch 'develop' into feature-nqubit-fogi
Aug 12, 2022
7188ccb
Adds FOGI unit and system tests. Fixes a couple minor bugs.
Aug 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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