@@ -1737,7 +1737,7 @@ def rdm2(self):
1737
1737
1738
1738
def compute_rdms (self , U : QCircuit = None , variables : Variables = None , spin_free : bool = True ,
1739
1739
get_rdm1 : bool = True , get_rdm2 : bool = True , ordering = "dirac" , use_hcb : bool = False ,
1740
- rdm_trafo : QubitHamiltonian = None , decompose = None ):
1740
+ rdm_trafo : QubitHamiltonian = None , evaluate = True ):
1741
1741
"""
1742
1742
Computes the one- and two-particle reduced density matrices (rdm1 and rdm2) given
1743
1743
a unitary U. This method uses the standard ordering in physics as denoted below.
@@ -1768,7 +1768,10 @@ def compute_rdms(self, U: QCircuit = None, variables: Variables = None, spin_fre
1768
1768
rdm_trafo :
1769
1769
The rdm operators can be transformed, e.g., a^dagger_i a_j -> U^dagger a^dagger_i a_j U,
1770
1770
where U represents the transformation. The default is set to None, implying that U equas the identity.
1771
-
1771
+ evaluate :
1772
+ if true, the tequila expectation values are evaluated directly via the tq.simulate command.
1773
+ the protocol is optimized to avoid repetation of wavefunction simulation
1774
+ if false, the rdms are returned as tq.QTensors
1772
1775
Returns
1773
1776
-------
1774
1777
"""
@@ -1891,13 +1894,14 @@ def _build_2bdy_operators_spinfree() -> list:
1891
1894
ops += [op ]
1892
1895
return ops
1893
1896
1894
- def _assemble_rdm1 (evals ) -> numpy .ndarray :
1897
+ def _assemble_rdm1 (evals , rdm1 = None ) -> numpy .ndarray :
1895
1898
"""
1896
1899
Returns spin-ful or spin-free one-particle RDM built by symmetry conditions
1897
1900
Same symmetry with or without spin, so we can use the same function
1898
1901
"""
1899
1902
N = n_MOs if spin_free else n_SOs
1900
- rdm1 = numpy .zeros ([N , N ])
1903
+ if rdm1 is None :
1904
+ rdm1 = numpy .zeros ([N , N ])
1901
1905
ctr : int = 0
1902
1906
for p in range (N ):
1903
1907
for q in range (p + 1 ):
@@ -1908,10 +1912,11 @@ def _assemble_rdm1(evals) -> numpy.ndarray:
1908
1912
1909
1913
return rdm1
1910
1914
1911
- def _assemble_rdm2_spinful (evals ) -> numpy .ndarray :
1915
+ def _assemble_rdm2_spinful (evals , rdm2 = None ) -> numpy .ndarray :
1912
1916
""" Returns spin-ful two-particle RDM built by symmetry conditions """
1913
1917
ctr : int = 0
1914
- rdm2 = numpy .zeros ([n_SOs , n_SOs , n_SOs , n_SOs ])
1918
+ if rdm2 is None :
1919
+ rdm2 = numpy .zeros ([n_SOs , n_SOs , n_SOs , n_SOs ])
1915
1920
for p in range (n_SOs ):
1916
1921
for q in range (p ):
1917
1922
for r in range (n_SOs ):
@@ -1933,10 +1938,11 @@ def _assemble_rdm2_spinful(evals) -> numpy.ndarray:
1933
1938
1934
1939
return rdm2
1935
1940
1936
- def _assemble_rdm2_spinfree (evals ) -> numpy .ndarray :
1941
+ def _assemble_rdm2_spinfree (evals , rdm2 = None ) -> numpy .ndarray :
1937
1942
""" Returns spin-free two-particle RDM built by symmetry conditions """
1938
1943
ctr : int = 0
1939
- rdm2 = numpy .zeros ([n_MOs , n_MOs , n_MOs , n_MOs ])
1944
+ if rdm2 is None :
1945
+ rdm2 = numpy .zeros ([n_MOs , n_MOs , n_MOs , n_MOs ])
1940
1946
for p , q , r , s in product (range (n_MOs ), repeat = 4 ):
1941
1947
if p * n_MOs + q >= r * n_MOs + s and (p >= q or r >= s ):
1942
1948
rdm2 [p , q , r , s ] = evals [ctr ]
@@ -2012,18 +2018,25 @@ def _build_2bdy_operators_hcb() -> list:
2012
2018
# Transform operator lists to QubitHamiltonians
2013
2019
if (not use_hcb ):
2014
2020
qops = [_get_qop_hermitian (op ) for op in qops ]
2015
-
2021
+
2016
2022
# Compute expected values
2017
- if rdm_trafo is None :
2018
- if decompose is not None :
2019
- print ("MANIPULATED" )
2020
- X = decompose (H = qops , U = U )
2021
- evals = simulate (X , variables = variables )
2023
+ rdm1 = None
2024
+ rdm2 = None
2025
+ from tequila import QTensor
2026
+ if evaluate :
2027
+ if rdm_trafo is None :
2028
+ evals = simulate (ExpectationValue (H = qops , U = U , shape = [len (qops )]), variables = variables )
2022
2029
else :
2030
+ qops = [rdm_trafo .dagger ()* qops [i ]* rdm_trafo for i in range (len (qops ))]
2023
2031
evals = simulate (ExpectationValue (H = qops , U = U , shape = [len (qops )]), variables = variables )
2024
2032
else :
2025
- qops = [rdm_trafo .dagger ()* qops [i ]* rdm_trafo for i in range (len (qops ))]
2026
- evals = simulate (ExpectationValue (H = qops , U = U , shape = [len (qops )]), variables = variables )
2033
+ if rdm_trafo is None :
2034
+ evals = [ExpectationValue (H = x , U = U ) for x in qops ]
2035
+ N = n_MOs if spin_free else n_SOs
2036
+ rdm1 = QTensor (shape = [N ,N ])
2037
+ rdm2 = QTensor (shape = [N , N , N , N ])
2038
+ else :
2039
+ raise TequilaException ("compute_rdms: rdm_trafo was set but evaluate flag is False (not supported)" )
2027
2040
2028
2041
# Assemble density matrices
2029
2042
# If self._rdm1, self._rdm2 exist, reset them if they are of the other spin-type
@@ -2044,11 +2057,11 @@ def _reset_rdm(rdm):
2044
2057
len_1 = 0
2045
2058
evals_1 , evals_2 = evals [:len_1 ], evals [len_1 :]
2046
2059
# Build matrices using the expectation values
2047
- self ._rdm1 = _assemble_rdm1 (evals_1 ) if get_rdm1 else self ._rdm1
2060
+ self ._rdm1 = _assemble_rdm1 (evals_1 , rdm1 = rdm1 ) if get_rdm1 else self ._rdm1
2048
2061
if spin_free or use_hcb :
2049
- self ._rdm2 = _assemble_rdm2_spinfree (evals_2 ) if get_rdm2 else self ._rdm2
2062
+ self ._rdm2 = _assemble_rdm2_spinfree (evals_2 , rdm2 = rdm2 ) if get_rdm2 else self ._rdm2
2050
2063
else :
2051
- self ._rdm2 = _assemble_rdm2_spinful (evals_2 ) if get_rdm2 else self ._rdm2
2064
+ self ._rdm2 = _assemble_rdm2_spinful (evals_2 , rdm2 = rdm2 ) if get_rdm2 else self ._rdm2
2052
2065
2053
2066
if get_rdm2 :
2054
2067
rdm2 = NBodyTensor (elems = self .rdm2 , ordering = "dirac" , verify = False )
0 commit comments