Skip to content

Commit 2eee587

Browse files
committed
OuterProdBasis
1 parent 0be9a1e commit 2eee587

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

pygsti/baseobjs/basis.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1787,3 +1787,74 @@ def create_simple_equivalent(self, builtin_basis_name=None):
17871787
if all([c.name == first_comp_name for c in self._component_bases]):
17881788
builtin_basis_name = first_comp_name # if all components have the same name
17891789
return BuiltinBasis(builtin_basis_name, self.elsize, sparse=self.sparse)
1790+
1791+
1792+
class OuterProdBasis(TensorProdBasis):
1793+
1794+
def __init__(self, component_bases, name=None, longname=None, squeeze=True):
1795+
"""
1796+
Let ⨂ denote an infix operator where (a ⨂ b) := numpy.tensordot(a, b, axes=0).
1797+
Suppose component_bases has length k. Under the default setting of squeeze=True,
1798+
the elements of this OuterProdBasis are all arrays of the form
1799+
1800+
v1.squeeze() ⨂ v2.squeeze() ⨂ ... ⨂ vk.squeeze(),
1801+
1802+
where vi belongs to component_bases[i].elements. The definition is changed in the
1803+
natural way if squeeze=False.
1804+
"""
1805+
TensorProdBasis.__init__(self, component_bases, name, longname)
1806+
if self.sparse:
1807+
raise NotImplementedError()
1808+
cnames = [c.name for c in self.component_bases]
1809+
if name is None:
1810+
self.name = "⨂".join(cnames)
1811+
if longname is None:
1812+
self.longname = "Outer-product basis with components " + ", ".join(cnames)
1813+
self._squeeze = squeeze
1814+
return
1815+
1816+
@property
1817+
def elshape(self):
1818+
shape = []
1819+
if self._squeeze:
1820+
for c in self.component_bases:
1821+
shape.extend(d for d in c.elshape if d > 1)
1822+
else:
1823+
for c in self.component_bases:
1824+
shape.extend(c.elshape)
1825+
return tuple(shape)
1826+
1827+
def _lazy_build_elements(self):
1828+
compMxs = _np.zeros((self.size,) + self.elshape, 'complex')
1829+
comp_els = [c.elements for c in self.component_bases]
1830+
for i, factors in enumerate(_itertools.product(*comp_els)):
1831+
M = factors[0].squeeze() if self._squeeze else factors[0]
1832+
for f in factors[1:]:
1833+
if self._squeeze:
1834+
f = f.squeeze()
1835+
M = _np.tensordot(M, f, axes=0)
1836+
compMxs[i] = M
1837+
self._elements = compMxs
1838+
1839+
def _lazy_build_labels(self):
1840+
self._labels = []
1841+
comp_lbls = [c.labels for c in self.component_bases]
1842+
for i, factor_lbls in enumerate(_itertools.product(*comp_lbls)):
1843+
self._labels.append('⨂'.join(factor_lbls))
1844+
1845+
def is_equivalent(self, other, sparseness_must_match=True):
1846+
if not sparseness_must_match:
1847+
raise NotImplementedError()
1848+
otherIsBasis = isinstance(other, OuterProdBasis)
1849+
if not otherIsBasis: return False # can't be equal to a non-DirectSumBasis
1850+
return all([c1.is_equivalent(c2, True)
1851+
for (c1, c2) in zip(self.component_bases, other.component_bases)])
1852+
1853+
def _copy_with_toggled_sparsity(self):
1854+
raise NotImplementedError()
1855+
1856+
def create_equivalent(self, builtin_basis_name):
1857+
raise NotImplementedError()
1858+
1859+
def create_simple_equivalent(self, builtin_basis_name=None):
1860+
raise NotImplementedError()

0 commit comments

Comments
 (0)