From cb461755f2eae4d162bb7e9fbc2c12525c96acd5 Mon Sep 17 00:00:00 2001 From: Riley Murray Date: Sat, 28 Sep 2024 09:59:50 -0400 Subject: [PATCH 1/6] split insanely complicated casting function into simpler functions --- pygsti/baseobjs/basis.py | 204 +++++++++++++++++---------------------- 1 file changed, 91 insertions(+), 113 deletions(-) diff --git a/pygsti/baseobjs/basis.py b/pygsti/baseobjs/basis.py index f4b329e7a..438f7f6db 100644 --- a/pygsti/baseobjs/basis.py +++ b/pygsti/baseobjs/basis.py @@ -14,6 +14,7 @@ import itertools as _itertools import warnings as _warnings from functools import lru_cache +from typing import Union, Tuple, List import numpy as _np import scipy.sparse as _sps @@ -154,126 +155,103 @@ class Basis(_NicelySerializable): The "vectors" of this basis, always 1D (sparse or dense) arrays. """ + # Implementation note: casting functions are classmethods, but current implementations + # could be static methods. + @classmethod - def cast(cls, name_or_basis_or_matrices, dim=None, sparse=None, classical_name='cl'): - """ - Convert various things that can describe a basis into a `Basis` object. + def cast_from_name_and_statespace(cls, name: str, state_space: _StateSpace, sparse=None, classical_name='cl'): + tpbBases = [] + if len(state_space.tensor_product_blocks_labels) == 1 \ + and len(state_space.tensor_product_blocks_labels[0]) == 1: + #Special case when we can actually pipe state_space to the BuiltinBasis constructor + lbl = state_space.tensor_product_blocks_labels[0][0] + nm = name if (state_space.label_type(lbl) == 'Q') else classical_name + tpbBases.append(BuiltinBasis(nm, state_space, sparse)) + else: + #TODO: add methods to StateSpace that can extract a sub-*StateSpace* object for a given label. + for tpbLabels in state_space.tensor_product_blocks_labels: + if len(tpbLabels) == 1: + nm = name if (state_space.label_type(tpbLabels[0]) == 'Q') else classical_name + tpbBases.append(BuiltinBasis(nm, state_space.label_dimension(tpbLabels[0]), sparse)) + else: + tpbBases.append(TensorProdBasis([ + BuiltinBasis(name if (state_space.label_type(l) == 'Q') else classical_name, + state_space.label_dimension(l), sparse) for l in tpbLabels])) + if len(tpbBases) == 1: + return tpbBases[0] + else: + return DirectSumBasis(tpbBases) - Parameters - ---------- - name_or_basis_or_matrices : various - Can take on a variety of values to produce different types of bases: - - - `None`: an empty `ExpicitBasis` - - `Basis`: checked with `dim` and `sparse` and passed through. - - `str`: `BuiltinBasis` or `DirectSumBasis` with the given name. - - `list`: an `ExplicitBasis` if given matrices/vectors or a - `DirectSumBasis` if given a `(name, dim)` pairs. - - dim : int or StateSpace, optional - The dimension of the basis to create. Sometimes this can be - inferred based on `name_or_basis_or_matrices`, other times it must - be supplied. This is the dimension of the space that this basis - fully or partially spans. This is equal to the number of basis - elements in a "full" (ordinary) basis. When a `StateSpace` - object is given, a more detailed direct-sum-of-tensor-product-blocks - structure for the state space (rather than a single dimension) is - described, and a basis is produced for this space. For instance, - a `DirectSumBasis` basis of `TensorProdBasis` components can result - when there are multiple tensor-product blocks and these blocks - consist of multiple factors. + @classmethod + def cast_from_name_and_dims(cls, name: str, dim: Union[int,list,tuple], sparse=None): + if isinstance(dim, (list, tuple)): # list/tuple of block dimensions + tpbBases = [] + for tpbDim in dim: + if isinstance(tpbDim, (list, tuple)): # list/tuple of tensor-product dimensions + tpbBases.append( + TensorProdBasis([BuiltinBasis(name, factorDim, sparse) for factorDim in tpbDim])) + else: + tpbBases.append(BuiltinBasis(name, tpbDim, sparse)) - sparse : bool, optional - Whether the resulting basis should be "sparse", meaning that its - elements will be sparse rather than dense matrices. + if len(tpbBases) == 1: + return tpbBases[0] + else: + return DirectSumBasis(tpbBases) + else: + return BuiltinBasis(name, dim, sparse) + + @classmethod + def cast_from_basis(cls, basis, dim=None, sparse=None): + #then just check to make sure consistent with `dim` & `sparse` + if dim is not None: + if isinstance(dim, _StateSpace): + state_space = dim + if hasattr(basis, 'state_space'): # TODO - should *all* basis objects have a state_space? + assert(state_space.is_compatible_with(basis.state_space)), \ + "Basis object has incompatible state space: %s != %s" % (str(state_space), + str(basis.state_space)) + else: # assume dim is an integer + assert(dim == basis.dim or dim == basis.elsize), \ + "Basis object has unexpected dimension: %d != %d or %d" % (dim, basis.dim, basis.elsize) + if sparse is not None: + basis = basis.with_sparsity(sparse) + return basis - classical_name : str, optional - An alternate builtin basis name that should be used when - constructing the bases for the classical sectors of `dim`, - when `dim` is a `StateSpace` object. + @classmethod + def cast_from_arrays(cls, arrays, dim=None, sparse=None): + b = ExplicitBasis(arrays, sparse=sparse) + if dim is not None: + assert(dim == b.dim), "Created explicit basis has unexpected dimension: %d vs %d" % (dim, b.dim) + if sparse is not None: + assert(sparse == b.sparse), "Basis object has unexpected sparsity: %s" % (b.sparse) + return b - Returns - ------- - Basis - """ - #print("DB: CAST = ",name_or_basis_or_matrices,dim) - from pygsti.baseobjs.statespace import StateSpace as _StateSpace - if name_or_basis_or_matrices is None: # special case of empty basis - return ExplicitBasis([], [], "*Empty*", "Empty (0-element) basis", False, sparse) # empty basis - elif isinstance(name_or_basis_or_matrices, Basis): - #then just check to make sure consistent with `dim` & `sparse` - basis = name_or_basis_or_matrices - if dim is not None: - if isinstance(dim, _StateSpace): - state_space = dim - if hasattr(basis, 'state_space'): # TODO - should *all* basis objects have a state_space? - assert(state_space.is_compatible_with(basis.state_space)), \ - "Basis object has incompatible state space: %s != %s" % (str(state_space), - str(basis.state_space)) - else: # assume dim is an integer - assert(dim == basis.dim or dim == basis.elsize), \ - "Basis object has unexpected dimension: %d != %d or %d" % (dim, basis.dim, basis.elsize) - if sparse is not None: - basis = basis.with_sparsity(sparse) - return basis - elif isinstance(name_or_basis_or_matrices, str): - name = name_or_basis_or_matrices + @classmethod + def cast(cls, arg, dim=None, sparse=None, classical_name='cl'): + #print("DB: CAST = ",arg,dim) + if isinstance(arg, Basis): + return cls.cast_from_basis(arg, dim, sparse) + if isinstance(arg, str): if isinstance(dim, _StateSpace): - state_space = dim - tpbBases = [] - if len(state_space.tensor_product_blocks_labels) == 1 \ - and len(state_space.tensor_product_blocks_labels[0]) == 1: - #Special case when we can actually pipe state_space to the BuiltinBasis constructor - lbl = state_space.tensor_product_blocks_labels[0][0] - nm = name if (state_space.label_type(lbl) == 'Q') else classical_name - tpbBases.append(BuiltinBasis(nm, state_space, sparse)) - else: - #TODO: add methods to StateSpace that can extract a sub-*StateSpace* object for a given label. - for tpbLabels in state_space.tensor_product_blocks_labels: - if len(tpbLabels) == 1: - nm = name if (state_space.label_type(tpbLabels[0]) == 'Q') else classical_name - tpbBases.append(BuiltinBasis(nm, state_space.label_dimension(tpbLabels[0]), sparse)) - else: - tpbBases.append(TensorProdBasis([ - BuiltinBasis(name if (state_space.label_type(l) == 'Q') else classical_name, - state_space.label_dimension(l), sparse) for l in tpbLabels])) - if len(tpbBases) == 1: - return tpbBases[0] - else: - return DirectSumBasis(tpbBases) - elif isinstance(dim, (list, tuple)): # list/tuple of block dimensions - tpbBases = [] - for tpbDim in dim: - if isinstance(tpbDim, (list, tuple)): # list/tuple of tensor-product dimensions - tpbBases.append( - TensorProdBasis([BuiltinBasis(name, factorDim, sparse) for factorDim in tpbDim])) - else: - tpbBases.append(BuiltinBasis(name, tpbDim, sparse)) - - if len(tpbBases) == 1: - return tpbBases[0] - else: - return DirectSumBasis(tpbBases) - else: - return BuiltinBasis(name, dim, sparse) - elif isinstance(name_or_basis_or_matrices, (list, tuple, _np.ndarray)): - # assume a list/array of matrices or (name, dim) pairs - if len(name_or_basis_or_matrices) == 0: # special case of empty basis - return ExplicitBasis([], [], "*Empty*", "Empty (0-element) basis", False, sparse) # empty basis - elif isinstance(name_or_basis_or_matrices[0], _np.ndarray): - b = ExplicitBasis(name_or_basis_or_matrices, sparse=sparse) - if dim is not None: - assert(dim == b.dim), "Created explicit basis has unexpected dimension: %d vs %d" % (dim, b.dim) - if sparse is not None: - assert(sparse == b.sparse), "Basis object has unexpected sparsity: %s" % (b.sparse) - return b - else: # assume els are (name, dim) pairs - compBases = [BuiltinBasis(subname, subdim, sparse) - for (subname, subdim) in name_or_basis_or_matrices] - return DirectSumBasis(compBases) + return cls.cast_from_name_and_statespace(arg, dim, sparse, classical_name) + return cls.cast_from_name_and_dims(arg, dim, sparse, classical_name) + if isinstance(arg, None) or (hasattr(arg,'__len__') and len(arg) == 0): + return ExplicitBasis([], [], "*Empty*", "Empty (0-element) basis", False, sparse) + # ^ The original implementation would return this value under two conditions. + # Either arg was None, or isinstance(arg,(tuple,list,ndarray)) and len(arg) == 0. + # We're just slightly relaxing the type requirement by using this check instead. + + # At this point, original behavior would check that arg is a tuple, list, or ndarray. + # Instead, we'll just require that arg[0] is well-defined. This is enough to discern + # between the two cases we can still support. + if isinstance(arg[0], _np.ndarray): + return cls.cast_from_arrays(arg, dim, sparse) + if len(arg[0]) == 2: + compBases = [BuiltinBasis(subname, subdim, sparse) for (subname, subdim) in arg] + return DirectSumBasis(compBases) + + raise ValueError("Can't cast %s to be a basis!" % str(type(arg))) - else: - raise ValueError("Can't cast %s to be a basis!" % str(type(name_or_basis_or_matrices))) def __init__(self, name, longname, real, sparse): super().__init__() From 90e8a7d0ca673fe0e1b07d5b9ff081dbc21b1a03 Mon Sep 17 00:00:00 2001 From: Riley Murray Date: Sat, 28 Sep 2024 11:01:55 -0400 Subject: [PATCH 2/6] bugfixes in earlier changes --- pygsti/baseobjs/basis.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygsti/baseobjs/basis.py b/pygsti/baseobjs/basis.py index 438f7f6db..8c6f0e350 100644 --- a/pygsti/baseobjs/basis.py +++ b/pygsti/baseobjs/basis.py @@ -234,8 +234,8 @@ def cast(cls, arg, dim=None, sparse=None, classical_name='cl'): if isinstance(arg, str): if isinstance(dim, _StateSpace): return cls.cast_from_name_and_statespace(arg, dim, sparse, classical_name) - return cls.cast_from_name_and_dims(arg, dim, sparse, classical_name) - if isinstance(arg, None) or (hasattr(arg,'__len__') and len(arg) == 0): + return cls.cast_from_name_and_dims(arg, dim, sparse) + if (arg is None) or (hasattr(arg,'__len__') and len(arg) == 0): return ExplicitBasis([], [], "*Empty*", "Empty (0-element) basis", False, sparse) # ^ The original implementation would return this value under two conditions. # Either arg was None, or isinstance(arg,(tuple,list,ndarray)) and len(arg) == 0. From dd5e7b7cd31b73919dc5e084cacc258f37f344ea Mon Sep 17 00:00:00 2001 From: Riley Murray Date: Sat, 28 Sep 2024 11:21:45 -0400 Subject: [PATCH 3/6] remove classical_label argument from Basis.cast --- pygsti/baseobjs/basis.py | 22 +++++++++++----------- pygsti/baseobjs/statespace.py | 1 + 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/pygsti/baseobjs/basis.py b/pygsti/baseobjs/basis.py index 8c6f0e350..0fe82b7eb 100644 --- a/pygsti/baseobjs/basis.py +++ b/pygsti/baseobjs/basis.py @@ -159,23 +159,23 @@ class Basis(_NicelySerializable): # could be static methods. @classmethod - def cast_from_name_and_statespace(cls, name: str, state_space: _StateSpace, sparse=None, classical_name='cl'): + def cast_from_name_and_statespace(cls, name: str, state_space: _StateSpace, sparse=None): tpbBases = [] - if len(state_space.tensor_product_blocks_labels) == 1 \ - and len(state_space.tensor_product_blocks_labels[0]) == 1: - #Special case when we can actually pipe state_space to the BuiltinBasis constructor - lbl = state_space.tensor_product_blocks_labels[0][0] - nm = name if (state_space.label_type(lbl) == 'Q') else classical_name + block_labels = state_space.tensor_product_blocks_labels + if len(block_labels) == 1 and len(block_labels[0]) == 1: + # Special case when we can actually pipe state_space to the BuiltinBasis constructor + lbl = block_labels[0][0] + nm = name if (state_space.label_type(lbl) == 'Q') else 'cl' tpbBases.append(BuiltinBasis(nm, state_space, sparse)) else: #TODO: add methods to StateSpace that can extract a sub-*StateSpace* object for a given label. - for tpbLabels in state_space.tensor_product_blocks_labels: + for tpbLabels in block_labels: if len(tpbLabels) == 1: - nm = name if (state_space.label_type(tpbLabels[0]) == 'Q') else classical_name + nm = name if (state_space.label_type(tpbLabels[0]) == 'Q') else 'cl' tpbBases.append(BuiltinBasis(nm, state_space.label_dimension(tpbLabels[0]), sparse)) else: tpbBases.append(TensorProdBasis([ - BuiltinBasis(name if (state_space.label_type(l) == 'Q') else classical_name, + BuiltinBasis(name if (state_space.label_type(l) == 'Q') else 'cl', state_space.label_dimension(l), sparse) for l in tpbLabels])) if len(tpbBases) == 1: return tpbBases[0] @@ -227,13 +227,13 @@ def cast_from_arrays(cls, arrays, dim=None, sparse=None): return b @classmethod - def cast(cls, arg, dim=None, sparse=None, classical_name='cl'): + def cast(cls, arg, dim=None, sparse=None): #print("DB: CAST = ",arg,dim) if isinstance(arg, Basis): return cls.cast_from_basis(arg, dim, sparse) if isinstance(arg, str): if isinstance(dim, _StateSpace): - return cls.cast_from_name_and_statespace(arg, dim, sparse, classical_name) + return cls.cast_from_name_and_statespace(arg, dim, sparse) return cls.cast_from_name_and_dims(arg, dim, sparse) if (arg is None) or (hasattr(arg,'__len__') and len(arg) == 0): return ExplicitBasis([], [], "*Empty*", "Empty (0-element) basis", False, sparse) diff --git a/pygsti/baseobjs/statespace.py b/pygsti/baseobjs/statespace.py index 4a358a35f..4ab8a26cb 100644 --- a/pygsti/baseobjs/statespace.py +++ b/pygsti/baseobjs/statespace.py @@ -1274,6 +1274,7 @@ def __str__(self): ['*'.join(["%s(%d%s)" % (lbl, self.label_dims[lbl], 'c' if (self.label_types[lbl] == 'C') else '') for lbl in tpb]) for tpb in self.labels]) + def default_space_for_dim(dim): """ Create a state space for a given superoperator dimension. From e65285256c066fb88781f105f36ca9ea649e09cd Mon Sep 17 00:00:00 2001 From: Riley Murray Date: Tue, 7 Jan 2025 10:58:57 -0500 Subject: [PATCH 4/6] obliterate unused EmbeddedBasis class --- pygsti/baseobjs/basis.py | 280 --------------------------------------- 1 file changed, 280 deletions(-) diff --git a/pygsti/baseobjs/basis.py b/pygsti/baseobjs/basis.py index 0fe82b7eb..bd2bdf7de 100644 --- a/pygsti/baseobjs/basis.py +++ b/pygsti/baseobjs/basis.py @@ -1760,283 +1760,3 @@ def create_simple_equivalent(self, builtin_basis_name=None): if all([c.name == first_comp_name for c in self.component_bases]): builtin_basis_name = first_comp_name # if all components have the same name return BuiltinBasis(builtin_basis_name, self.elsize, sparse=self.sparse) - - -class EmbeddedBasis(LazyBasis): - """ - A basis that embeds a basis for a smaller state space within a larger state space. - - The elements of an EmbeddedBasis are therefore just embedded versions - of the elements of the basis that is embedded. - - Parameters - ---------- - basis_to_embed : Basis - The basis being embedded. - - state_space_labels : StateSpaceLabels - An object describing the struture of the entire state space. - - target_labels : list or tuple - The labels contained in `stateSpaceLabels` which demarcate the - portions of the state space acted on by `basis_to_embed`. - - name : str, optional - The name of this basis. If `None`, the names of `basis_to_embed` - is joined with ':' characters to the elements of `target_labels`. - - longname : str, optional - A longer description of this basis. If `None`, then a long name is - automatically generated. - """ - - @classmethod - def embed_label(cls, lbl, target_labels): - """ - Gets the EmbeddedBasis label for `lbl`. - - Convenience method that gives the EmbeddedBasis label for `lbl` - without needing to construct the `EmbeddedBasis`. E.g. `"XX:1,2"`. - - Parameters - ---------- - lbl : str - Un-embedded basis element label, e.g. `"XX"`. - - target_labels : tuple - The target state space labels upon which this basis element - will be embedded, e.g. `(1,2)` - - Returns - ------- - str - The embedded-basis-element label as an EmbeddedBasis would - assign it. E.g. `"XX:1,2"`. - """ - return "%s:%s" % (lbl, ",".join(map(str, target_labels))) - - @classmethod - def unembed_label(cls, lbl, target_labels): - """ - Convenience method that performs the reverse of :meth:`embed_label` - - Parameters - ---------- - lbl : str - Embedded basis element label, e.g. `"XX:1,2"`. - - target_labels : tuple - The target state space labels upon which this basis element - will be embedded, e.g. `(1,2)` - - Returns - ------- - str - The un-embedded label, e.g. `"XX"`. - """ - suffix = ":" + ",".join(map(str, target_labels)) - if lbl.endswith(suffix): - return lbl[:-len(suffix)] - else: - raise ValueError("Cannot unembed '%s' - doesn't end in '%s'!" % (lbl, suffix)) - - def __init__(self, basis_to_embed, state_space, target_labels, name=None, longname=None): - ''' - Create a new EmbeddedBasis. - - Parameters - ---------- - basis_to_embed : Basis - The basis being embedded. - - state_space : StateSpace - An object describing the struture of the entire state space. - - target_labels : list or tuple - The labels contained in `stateSpaceLabels` which demarcate the - portions of the state space acted on by `basis_to_embed`. - - name : str, optional - The name of this basis. If `None`, the names of `basis_to_embed` - is joined with ':' characters to the elements of `target_labels`. - - longname : str, optional - A longer description of this basis. If `None`, then a long name is - automatically generated. - ''' - from pygsti.baseobjs.statespace import StateSpace as _StateSpace - self.embedded_basis = basis_to_embed - self.target_labels = target_labels - self.state_space = _StateSpace.cast(state_space) - - if name is None: - name = ':'.join((basis_to_embed.name,) + tuple(map(str, target_labels))) - if longname is None: - longname = "Embedded %s basis as %s within %s" % \ - (basis_to_embed.name, ':'.join(map(str, target_labels)), str(self.state_space)) - - real = basis_to_embed.real - sparse = basis_to_embed.sparse - - super(EmbeddedBasis, self).__init__(name, longname, real, sparse) - - def _to_nice_serialization(self): - state = super()._to_nice_serialization() - state.update({'name': self.name, - 'longname': self.longname, - 'state_space': self.state_space.to_nice_serialization(), - 'embedded_basis': self.embedded_basis.to_nice_serialization() - }) - return state - - @classmethod - def _from_nice_serialization(cls, state): - basis_to_embed = Basis.from_nice_serialization(state['embedded_basis']) - state_space = _StateSpace.from_nice_serialization(state['state_space']) - return cls(basis_to_embed, state_space, state['target_labels'], state['name'], state['longname']) - - @property - def dim(self): - """ - The dimension of the vector space this basis fully or partially - spans. Equivalently, the length of the `vector_elements` of the - basis. - """ - return self.state_space.dim - - @property - def size(self): - """ - The number of elements (or vector-elements) in the basis. - """ - return self.embedded_basis.size - - @property - def elshape(self): - """ - The shape of each element. Typically either a length-1 or length-2 - tuple, corresponding to vector or matrix elements, respectively. - Note that *vector elements* always have shape `(dim,)` (or `(dim,1)` - in the sparse case). - """ - elndim = self.embedded_basis.elndim - if elndim == 2: # a "matrix" basis - d = int(_np.sqrt(self.dim)) - assert(d**2 == self.dim), \ - "Dimension of state_space must be a perfect square when embedding a matrix basis" - elshape = (d, d) - elif elndim == 1: - elshape = (self.dim,) - else: - raise ValueError("Can only embed bases with .elndim == 1 or 2 (received %d)!" % elndim) - return elshape - - def __hash__(self): - return hash(tuple(hash(self.embedded_basis), self.target_labels, self.state_space)) - - def _lazy_build_elements(self): - """ Take a dense or sparse basis matrix and embed it. """ - #LAZY building of elements (in case we never need them) - if self.elndim == 2: # then use EmbeddedOp to do matrix - from ..modelmembers.operations import StaticArbitraryOp - from ..modelmembers.operations import EmbeddedOp - sslbls = self.state_space.copy() - sslbls.reduce_dims_densitymx_to_state_inplace() # because we're working with basis matrices not gates - - if self.sparse: - self._elements = [] - for spmx in self.embedded_basis.elements: - mxAsOp = StaticArbitraryOp(spmx.to_dense(), evotype='statevec') - self._elements.append(EmbeddedOp(sslbls, self.target_labels, - mxAsOp).to_sparse()) - else: - self._elements = _np.zeros((self.size,) + self.elshape, 'complex') - for i, mx in enumerate(self.embedded_basis.elements): - self._elements[i] = EmbeddedOp( - sslbls, self.target_labels, StaticArbitraryOp(mx, evotype='statevec') - ).to_dense(on_space='HilbertSchmidt') - else: - # we need to perform embedding using vectors rather than matrices - doable, but - # not needed yet, so defer implementation to later. - raise NotImplementedError("Embedding *vector*-type bases not implemented yet") - - def _lazy_build_labels(self): - self._labels = [EmbeddedBasis.embed_label(lbl, self.target_labels) - for lbl in self.embedded_basis.labels] - - def _copy_with_toggled_sparsity(self): - return EmbeddedBasis(self.embedded_basis._copy_with_toggled_sparsity(), - self.state_space, - self.target_labels, - self.name, self.longname) - - def is_equivalent(self, other, sparseness_must_match=True): - """ - Tests whether this basis is equal to another basis, optionally ignoring sparseness. - - Parameters - ----------- - other : Basis or str - The basis to compare with. - - sparseness_must_match : bool, optional - If `False` then comparison ignores differing sparseness, and this function - returns `True` when the two bases are equal except for their `.sparse` values. - - Returns - ------- - bool - """ - otherIsBasis = isinstance(other, EmbeddedBasis) - if not otherIsBasis: return False # can't be equal to a non-EmbeddedBasis - if self.target_labels != other.target_labels or self.state_space != other.state_space: - return False - return self.embedded_basis.is_equivalent(other.embedded_basis, sparseness_must_match) - - def create_equivalent(self, builtin_basis_name): - """ - Create an equivalent basis with components of type `builtin_basis_name`. - - Create a Basis that is equivalent in structure & dimension to this - basis but whose simple components (perhaps just this basis itself) is - of the builtin basis type given by `builtin_basis_name`. - - Parameters - ---------- - builtin_basis_name : str - The name of a builtin basis, e.g. `"pp"`, `"gm"`, or `"std"`. Used to - construct the simple components of the returned basis. - - Returns - ------- - EmbeddedBasis - """ - equiv_embedded = self.embedded_basis.create_equivalent(builtin_basis_name) - return EmbeddedBasis(equiv_embedded, self.state_space, self.target_labels) - - def create_simple_equivalent(self, builtin_basis_name=None): - """ - Create a basis of type `builtin_basis_name` whose elements are compatible with this basis. - - Create a simple basis *and* one without components (e.g. a - :class:`TensorProdBasis`, is a simple basis w/components) of the - builtin type specified whose dimension is compatible with the - *elements* of this basis. This function might also be named - "element_equivalent", as it returns the `builtin_basis_name`-analogue - of the standard basis that this basis's elements are expressed in. - - Parameters - ---------- - builtin_basis_name : str, optional - The name of the built-in basis to use. If `None`, then a - copy of this basis is returned (if it's simple) or this - basis's name is used to try to construct a simple and - component-free version of the same builtin-basis type. - - Returns - ------- - Basis - """ - if builtin_basis_name is None: - builtin_basis_name = self.embedded_basis.name # default - return BuiltinBasis(builtin_basis_name, self.elsize, sparse=self.sparse) From ff6dc47d667c325be67fb50069f30b79a2ed454b Mon Sep 17 00:00:00 2001 From: Riley Murray Date: Tue, 7 Jan 2025 11:09:54 -0500 Subject: [PATCH 5/6] remove unused imports --- pygsti/modelmembers/operations/embeddederrorgen.py | 1 - pygsti/modelmembers/operations/embeddedop.py | 1 - 2 files changed, 2 deletions(-) diff --git a/pygsti/modelmembers/operations/embeddederrorgen.py b/pygsti/modelmembers/operations/embeddederrorgen.py index 531004902..72fba13bd 100644 --- a/pygsti/modelmembers/operations/embeddederrorgen.py +++ b/pygsti/modelmembers/operations/embeddederrorgen.py @@ -14,7 +14,6 @@ import warnings as _warnings from pygsti.modelmembers.operations.embeddedop import EmbeddedOp as _EmbeddedOp -from pygsti.baseobjs.basis import Basis as _Basis, EmbeddedBasis as _EmbeddedBasis # Idea: diff --git a/pygsti/modelmembers/operations/embeddedop.py b/pygsti/modelmembers/operations/embeddedop.py index be8ee8d8e..141457fec 100644 --- a/pygsti/modelmembers/operations/embeddedop.py +++ b/pygsti/modelmembers/operations/embeddedop.py @@ -18,7 +18,6 @@ from pygsti.modelmembers.operations.linearop import LinearOperator as _LinearOperator from pygsti.modelmembers import modelmember as _modelmember -from pygsti.baseobjs.basis import EmbeddedBasis as _EmbeddedBasis from pygsti.baseobjs.statespace import StateSpace as _StateSpace From 1affef0dcd1fc8c5f01c8a31da7dcf5d8b1fd085 Mon Sep 17 00:00:00 2001 From: Riley Murray Date: Tue, 7 Jan 2025 11:23:55 -0500 Subject: [PATCH 6/6] make flake8 happy (for good reasons) --- pygsti/modelmembers/operations/embeddederrorgen.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pygsti/modelmembers/operations/embeddederrorgen.py b/pygsti/modelmembers/operations/embeddederrorgen.py index 72fba13bd..60c833cce 100644 --- a/pygsti/modelmembers/operations/embeddederrorgen.py +++ b/pygsti/modelmembers/operations/embeddederrorgen.py @@ -11,6 +11,7 @@ #*************************************************************************************************** import collections as _collections +from pygsti.baseobjs.basis import Basis as _Basis import warnings as _warnings from pygsti.modelmembers.operations.embeddedop import EmbeddedOp as _EmbeddedOp