@@ -1787,3 +1787,74 @@ def create_simple_equivalent(self, builtin_basis_name=None):
1787
1787
if all ([c .name == first_comp_name for c in self ._component_bases ]):
1788
1788
builtin_basis_name = first_comp_name # if all components have the same name
1789
1789
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