7575# the following double-factorized form in terms of orthonormal core tensors :math:`Z^{(t)}`
7676# and symmetric leaf tensors :math:`U^{(t)}` [#cdf2]_:
7777#
78- # .. math:: V_{pqrs} \approx \sum_t^T \sum_{ij} U_{pi}^{(t)} U_{pj }^{(t)} Z_{ij}^{(t)} U_{qk }^{(t)} U_{ql }^{(t)},
78+ # .. math:: V_{pqrs} \approx \sum_t^T \sum_{ij} U_{pi}^{(t)} U_{qi }^{(t)} Z_{ij}^{(t)} U_{rj }^{(t)} U_{sj }^{(t)},
7979#
8080# where :math:`Z_{ij}^{(t)} = W_i^{(t)} W_j^{(t)}`. This decomposition is referred
8181# to as the *explicit* double factorization (XDF) and decreases the number of terms
234234def leaf_unitary_rotation (leaf , wires ):
235235 """Applies the basis rotation transformation corresponding to the leaf tensor."""
236236 basis_mat = qml .math .kron (leaf , qml .math .eye (2 )) # account for spin
237- qml .BasisRotation (unitary_matrix = basis_mat , wires = wires )
237+ return qml .BasisRotation (unitary_matrix = basis_mat , wires = wires )
238238
239239######################################################################
240240# Similarly, the unitary transformation for the core tensors can be applied efficiently
@@ -248,20 +248,22 @@ def leaf_unitary_rotation(leaf, wires):
248248
249249def core_unitary_rotation (core , body_type , wires ):
250250 """Applies the unitary transformation corresponding to the core tensor."""
251+ ops = []
251252 if body_type == "one_body" : # implements one-body term
252253 for wire , cval in enumerate (qml .math .diag (core )):
253254 for sigma in [0 , 1 ]:
254- qml .RZ (- cval , wires = 2 * wire + sigma )
255- qml .GlobalPhase (qml .math .sum (core ), wires = wires )
255+ ops . append ( qml .RZ (- cval , wires = 2 * wire + sigma ) )
256+ ops . append ( qml .GlobalPhase (qml .math .sum (core ), wires = wires ) )
256257
257258 if body_type == "two_body" : # implements two-body term
258259 for odx1 , odx2 in it .product (range (len (wires ) // 2 ), repeat = 2 ):
259- cval = core [odx1 , odx2 ]
260+ cval = core [odx1 , odx2 ] / 4.0
260261 for sigma , tau in it .product (range (2 ), repeat = 2 ):
261262 if odx1 != odx2 or sigma != tau :
262- qml .IsingZZ (cval / 4.0 , wires = [2 * odx1 + sigma , 2 * odx2 + tau ])
263- gphase = 0.5 * qml .math .sum (core ) + 0.25 * qml .math .trace (core )
264- qml .GlobalPhase (- gphase , wires = wires )
263+ ops .append (qml .IsingZZ (cval , wires = [2 * odx1 + sigma , 2 * odx2 + tau ]))
264+ gphase = 0.5 * qml .math .sum (core ) - 0.25 * qml .math .trace (core )
265+ ops .append (qml .GlobalPhase (- gphase , wires = wires ))
266+ return ops
265267
266268######################################################################
267269# We can now use these functions to approximate the evolution operator :math:`e^{-iHt}` for
@@ -292,19 +294,16 @@ def CDFTrotterStep(time, cdf_ham, wires):
292294 """
293295 cores , leaves = cdf_ham ["core_tensors" ], cdf_ham ["leaf_tensors" ]
294296 for bidx , (core , leaf ) in enumerate (zip (cores , leaves )):
295- # apply the basis rotation for leaf tensor
296- leaf_unitary_rotation (leaf , wires )
297-
298- # apply the rotation for core tensor scaled by the time-step
299297 # Note: only the first term is one-body, others are two-body
300298 body_type = "two_body" if bidx else "one_body"
301- core_unitary_rotation (time * core , body_type , wires )
302-
303- # revert the change-of-basis for leaf tensor
304- leaf_unitary_rotation (leaf .conjugate ().T , wires )
305-
306- # apply the global phase gate based on the nuclear core energy
307- qml .GlobalPhase (cdf_ham ["nuc_constant" ] * time , wires = wires )
299+ qml .prod (
300+ # revert the change-of-basis for leaf tensor
301+ leaf_unitary_rotation (leaf .conjugate ().T , wires ),
302+ # apply the rotation for core tensor scaled by the time-step
303+ * core_unitary_rotation (time * core , body_type , wires ),
304+ # apply the basis rotation for leaf tensor
305+ leaf_unitary_rotation (leaf , wires ),
306+ ) # Note: prod applies operations in the reverse order (right-to-left).
308307
309308######################################################################
310309# We now use this function to simulate the evolution of the :math:`H_4` Hamiltonian
@@ -320,6 +319,7 @@ def CDFTrotterStep(time, cdf_ham, wires):
320319def cdf_circuit (n_steps , order ):
321320 qml .BasisState (hf_state , wires = circ_wires )
322321 qml .trotterize (CDFTrotterStep , n_steps , order )(time , cdf_hamiltonian , circ_wires )
322+ qml .GlobalPhase (cdf_hamiltonian ["nuc_constant" ], wires = circ_wires )
323323 return qml .state ()
324324
325325circuit_state = cdf_circuit (n_steps = 10 , order = 2 )
0 commit comments