Time Evolution using Renormalizer

Overview

In this notebook we will simulate the charge transfer between two molecules using the Marcus model

\[\hat H = -V(a^\dagger_0 a_1 + a^\dagger_1 a_0) + \Delta G a^\dagger_1 a_1 + \omega \sum_{i=0, 1} b^\dagger_i b_i + g \omega \sum_{i=0, 1} a^\dagger_i a_i (b^\dagger_i + b_i)\]

with transfer integral \(V=-0.1\), dimensionless coupling constant \(g=1\), vibration frequency \(\omega=0.5\).

We will first show how to use Renormalizer to simulation the time evolution at \(\Delta G = 0\). Then, we will show that, by decreasing the reaction Gibbs free energy change \(\Delta G\), the reaction rate will first increase and then decrease, as predicted by the Marcus theory.

Preparation: Setting Up Logger

[1]:
from renormalizer.utils.log import package_logger as logger
2026-10-14 01:46:28,593[INFO] Use numpy as backend
2026-10-14 01:46:28,594[INFO] numpy random seed is 9012
2026-10-14 01:46:28,594[INFO] backend random seed is 2019
2026-10-14 01:46:28,595[INFO] random seed is 1092
2026-10-14 01:46:28,603[INFO] Git Commit Hash: 3507afde83fd6f408c1c2198aad4dfe455d88312
[2]:
logger.debug("logger output")
2026-10-14 01:46:29,374[DEBUG] logger output
[3]:
from renormalizer.utils.log import set_stream_level, INFO
[4]:
# filter logger output
set_stream_level(INFO)
[5]:
logger.debug("This message will not be shown")
[6]:
logger.info("Logger output")
2026-10-14 01:46:29,392[INFO] Logger output

Define the Model and Initial State

[7]:
from renormalizer import Op, BasisMultiElectron, BasisSHO, Model
import numpy as np
[8]:
v = -0.1
g = 1
omega = 0.5
nbas = 16
[9]:
def get_model(delta_g):
    ham_terms = v * Op(r"a^\dagger a", ["e0", "e1"]) + v * Op(r"a^\dagger a", ["e1", "e0"])
    ham_terms += delta_g * Op(r"a^\dagger a", "e1")
    for i in range(2):
        ham_terms += omega * Op(r"b^\dagger b", f"v{i}")
        ham_terms += g * omega * Op(r"a^\dagger a", f"e{i}") * Op(r"b^\dagger+b", f"v{i}")
    basis = [BasisMultiElectron(["e0", "e1"], [0, 0]), BasisSHO("v0", omega, nbas), BasisSHO("v1", omega, nbas)]
    return Model(basis, ham_terms)
[10]:
# using a relaxed initial state
def get_init_condition():
    basis = BasisSHO(0, omega, nbas)
    state = np.linalg.eigh(basis.op_mat(r"b^\dagger b") + g * basis.op_mat(r"b^\dagger+b"))[1][:, 0]
    return {"v0": state}
init_condition = get_init_condition()

Time Evolution with the Default Configuration

Next, we run the simulation using the evolve method in the Mps class. At this phase, we keep \(\Delta G = 0\).

[11]:
delta_g = 0
model = get_model(delta_g)
[12]:
from renormalizer import Mps, Mpo
[13]:
# Hamiltonian MPO
mpo = Mpo(model)
# The occupation of e0
n_op = Mpo(model, Op(r"a^\dagger a", "e0"))
[14]:
# initialize the MPS
mps = Mps.hartree_product_state(model, condition=init_condition)
# time evolution step
dt = 0.2
# record the electronic occupation
n_list = []
for i_step in range(50):
    n = mps.expectation(n_op)
    logger.info(f"Step {i_step}. Time {i_step * dt:.2f}. $n$ {n}")
    # perform time evolution. Note that the evolution is not in-place.
    mps = mps.evolve(mpo, dt)
    n_list.append(n)
2026-10-14 01:46:29,437[INFO] Step 0. Time 0.00. $n$ 0.9999999999999997
2026-10-14 01:46:29,448[INFO] Step 1. Time 0.20. $n$ 0.9996030537865599
2026-10-14 01:46:29,458[INFO] Step 2. Time 0.40. $n$ 0.9984313966561627
2026-10-14 01:46:29,468[INFO] Step 3. Time 0.60. $n$ 0.9965532876450582
2026-10-14 01:46:29,478[INFO] Step 4. Time 0.80. $n$ 0.9940731362639054
2026-10-14 01:46:29,488[INFO] Step 5. Time 1.00. $n$ 0.9911161868842484
2026-10-14 01:46:29,498[INFO] Step 6. Time 1.20. $n$ 0.9878132450238745
2026-10-14 01:46:29,508[INFO] Step 7. Time 1.40. $n$ 0.9842873078294339
2026-10-14 01:46:29,518[INFO] Step 8. Time 1.60. $n$ 0.9806441927926957
2026-10-14 01:46:29,528[INFO] Step 9. Time 1.80. $n$ 0.9769677466243794
2026-10-14 01:46:29,538[INFO] Step 10. Time 2.00. $n$ 0.9733182226560815
2026-10-14 01:46:29,548[INFO] Step 11. Time 2.20. $n$ 0.9697373081106375
2026-10-14 01:46:29,558[INFO] Step 12. Time 2.40. $n$ 0.9662497016753411
2026-10-14 01:46:29,568[INFO] Step 13. Time 2.60. $n$ 0.9628671609457058
2026-10-14 01:46:29,578[INFO] Step 14. Time 2.80. $n$ 0.9595919026133976
2026-10-14 01:46:29,588[INFO] Step 15. Time 3.00. $n$ 0.956419752167962
2026-10-14 01:46:29,598[INFO] Step 16. Time 3.20. $n$ 0.9533423734970332
2026-10-14 01:46:29,609[INFO] Step 17. Time 3.40. $n$ 0.9503492089387037
2026-10-14 01:46:29,619[INFO] Step 18. Time 3.60. $n$ 0.9474287391824951
2026-10-14 01:46:29,628[INFO] Step 19. Time 3.80. $n$ 0.9445692798814911
2026-10-14 01:46:29,639[INFO] Step 20. Time 4.00. $n$ 0.9417594196434944
2026-10-14 01:46:29,651[INFO] Step 21. Time 4.20. $n$ 0.9389883140168832
2026-10-14 01:46:29,661[INFO] Step 22. Time 4.40. $n$ 0.9362456942950406
2026-10-14 01:46:29,671[INFO] Step 23. Time 4.60. $n$ 0.9335221984937241
2026-10-14 01:46:29,681[INFO] Step 24. Time 4.80. $n$ 0.9308095732941706
2026-10-14 01:46:29,692[INFO] Step 25. Time 5.00. $n$ 0.9281008849250421
2026-10-14 01:46:29,702[INFO] Step 26. Time 5.20. $n$ 0.9253906107085335
2026-10-14 01:46:29,712[INFO] Step 27. Time 5.40. $n$ 0.922673847165473
2026-10-14 01:46:29,723[INFO] Step 28. Time 5.60. $n$ 0.9199478805518423
2026-10-14 01:46:29,733[INFO] Step 29. Time 5.80. $n$ 0.9172094618331411
2026-10-14 01:46:29,743[INFO] Step 30. Time 6.00. $n$ 0.9144551950424464
2026-10-14 01:46:29,753[INFO] Step 31. Time 6.20. $n$ 0.9116816732036945
2026-10-14 01:46:29,763[INFO] Step 32. Time 6.40. $n$ 0.9088859026726788
2026-10-14 01:46:29,773[INFO] Step 33. Time 6.60. $n$ 0.9060659656334908
2026-10-14 01:46:29,784[INFO] Step 34. Time 6.80. $n$ 0.9032210121837201
2026-10-14 01:46:29,795[INFO] Step 35. Time 7.00. $n$ 0.9003515623906608
2026-10-14 01:46:29,805[INFO] Step 36. Time 7.20. $n$ 0.8974590790192777
2026-10-14 01:46:29,816[INFO] Step 37. Time 7.40. $n$ 0.8945453849965332
2026-10-14 01:46:29,826[INFO] Step 38. Time 7.60. $n$ 0.8916120979060874
2026-10-14 01:46:29,837[INFO] Step 39. Time 7.80. $n$ 0.8886602437062088
2026-10-14 01:46:29,847[INFO] Step 40. Time 8.00. $n$ 0.8856902107426251
2026-10-14 01:46:29,858[INFO] Step 41. Time 8.20. $n$ 0.8827020259679251
2026-10-14 01:46:29,868[INFO] Step 42. Time 8.40. $n$ 0.8796958667524071
2026-10-14 01:46:29,879[INFO] Step 43. Time 8.60. $n$ 0.8766726737398555
2026-10-14 01:46:29,889[INFO] Step 44. Time 8.80. $n$ 0.8736347299848457
2026-10-14 01:46:29,899[INFO] Step 45. Time 9.00. $n$ 0.8705861034366988
2026-10-14 01:46:29,910[INFO] Step 46. Time 9.20. $n$ 0.867532873755651
2026-10-14 01:46:29,920[INFO] Step 47. Time 9.40. $n$ 0.8644830817098138
2026-10-14 01:46:29,931[INFO] Step 48. Time 9.60. $n$ 0.8614463370235246
2026-10-14 01:46:29,941[INFO] Step 49. Time 9.80. $n$ 0.858433004390228
[15]:
# plotting the occupation
from matplotlib import pyplot as plt
plt.style.use("mm.mplstyle")

plt.plot(np.arange(len(n_list)) * dt, n_list, label="Default")
plt.xlabel("$t$")
plt.ylabel(r"Occupation $\langle a^\dagger_0 a_0 \rangle$")
plt.legend()
plt.show()
../_images/tutorials_time_evolution_19_0.png

In this example, the time evolution is performed with default time evolution configuration and MPS compression configuration.

Renormalizer by default uses the RK4 “propagation and compression” method for time evolution. The advantage of the method is that it is easy to understand and setup.

Please refer to our recent review for a discussion of the different time evolution schemes.

[16]:
mps.evolve_config.method
[16]:
<EvolveMethod.prop_and_compress: 'P&C'>

Regarding MPS compression/truncation configuration, Renormalizer by default employs a truncation scheme based on the the singular value threshold.

[17]:
mps.compress_config.criteria, mps.compress_config.threshold
[17]:
(<CompressCriteria.threshold: 'threshold'>, 0.001)

Inspection of the dimension of the final mps after time evolution shows that the compression is efficient.

[18]:
mps.bond_dims
[18]:
[1, 2, 4, 1]

Configuring Time Evolution

In order to configure the time evolution, you should update the evolve_config and compress_config attributes of an MPS instance. These attributes are instances of the EvolveConfig class and the CompressConfig class. Please see the API referece for full options of the configuration classes.

[19]:
from renormalizer.utils.configs import CompressConfig, CompressCriteria
[20]:
# update the compresssion configuration. Adopt a fixed bond dimension of 8
mps.compress_config = CompressConfig(CompressCriteria.fixed, max_bonddim=8)

Next, we perform one more step of the time evolution, and the bond dimension in the middle of the MPS is increased from 4 to 8, according to the updated compression configuration.

[21]:
new_mps = mps.evolve(mpo, dt)
new_mps.bond_dims
[21]:
[1, 2, 8, 1]

Recent studies have shown that methods based on time dependent variantional principle (TDVP) show higher accuracy and efficiency. In our production runs, we usually employ one-site TDVP with projector splitting (TDVP-PS) for time evolution. TDVP-PS allows much larger time evolution step size and reduces memory consumption. However, its setup is a little more complex than propagation and compression, since one-site TDVP generally can not adjust bond dimension during time evolution.

[22]:
from renormalizer.utils.configs import EvolveConfig, EvolveMethod
[23]:
mps.evolve_config = EvolveConfig(EvolveMethod.tdvp_ps)

Next, we perform one more step of the time evolution using TDVP-PS.

Note that the bond dimension in the middle of the MPS does not increase from 4 to 8. This is because one-site TDVP-PS does not alter the bond dimension.

In order to perform one-site TDVP-PS time evolution, it is imperative to increase the bond dimension of the MPS first, and then perform the time evolution.

[24]:
new_mps = mps.evolve(mpo, dt)
new_mps.bond_dims
[24]:
[1, 2, 4, 1]

The expand_bond_dimension function increases the bond dimension to target value specified by the compress_config. In short, the function adds the vectors in the Krylov space \(H^n|\psi\rangle\) to the input wavefunction \(|\psi\rangle\), and then compresses it to the target bond dimension. expand_bond_dimension works with fixed bond dimension compression configuration, instead of singular value truncation threshold.

The include_ex option is specifically designed for systems with quantum number conservation. If the initial wavefunction does not include contributions from a certain symmetry sector, these contributions will not reappear during time evolution due to the projection error in TDVP. Setting include_ex=True will add a small perturbation to the initial state to help recover the missing symmetry sector contributions. In our case, the quantum number conservation is disabled, so we set include_ex=False.

[25]:
new_mps = mps.expand_bond_dimension(mpo, include_ex=False)
new_mps.bond_dims
[25]:
[1, 2, 8, 1]

Observing Marcus Inverted Region

Next, we put everything together and perform time evolution with different \(\Delta G\) using TDVP-PS. Since the initial state of time evolution is a Hartree product state, we must expand the bond dimension before performing the time evolution.

[26]:
# time evolution step
dt = 0.5

# initialize the MPS in the Hartree product state
init_mps = Mps.hartree_product_state(model, condition=init_condition)
logger.info(f"Initial MPS bond dimension: {init_mps.bond_dims}")
# setup compression configuration
init_mps.compress_config = CompressConfig(CompressCriteria.fixed, max_bonddim=8)
# setup time evolution configuration
init_mps.evolve_config = EvolveConfig(EvolveMethod.tdvp_ps)


# record the electronic occupation
n_list_list = []

delta_g_list = np.linspace(0, -2, 5)
for delta_g in delta_g_list:
    # reconstruct the Hamiltonian. We can reuse the occupation operator though
    model = get_model(delta_g)
    mpo = Mpo(model)
    # since using TDVP-PS, expand the bond dimension to target value.
    # otherwise the time evolution is limited to the Hartree product state.
    mps = init_mps.expand_bond_dimension(mpo, include_ex=False)
    logger.info(f"MPS bond dimension after expanding: {mps.bond_dims}")
    n_list = []
    for i_step in range(20):
        n = mps.expectation(n_op)
        logger.info(f"Step {i_step}. Time {i_step * dt:.2f}. $n$ {n}")
        # perform time evolution. Note that the evolution is not in-place.
        mps = mps.evolve(mpo, dt)
        n_list.append(n)
    n_list_list.append(n_list)
2026-10-14 01:46:31,952[INFO] Initial MPS bond dimension: [1, 1, 1, 1]
2026-10-14 01:46:31,967[INFO] MPS bond dimension after expanding: [1, 2, 8, 1]
2026-10-14 01:46:31,968[INFO] Step 0. Time 0.00. $n$ 1.0
2026-10-14 01:46:31,983[INFO] Step 1. Time 0.50. $n$ 0.9975776788496071
2026-10-14 01:46:31,997[INFO] Step 2. Time 1.00. $n$ 0.9911341778211986
2026-10-14 01:46:32,011[INFO] Step 3. Time 1.50. $n$ 0.982498183827564
2026-10-14 01:46:32,025[INFO] Step 4. Time 2.00. $n$ 0.9733283418283689
2026-10-14 01:46:32,038[INFO] Step 5. Time 2.50. $n$ 0.9645218516469468
2026-10-14 01:46:32,051[INFO] Step 6. Time 3.00. $n$ 0.9563382368491798
2026-10-14 01:46:32,065[INFO] Step 7. Time 3.50. $n$ 0.9487304333892244
2026-10-14 01:46:32,079[INFO] Step 8. Time 4.00. $n$ 0.9415533981895283
2026-10-14 01:46:32,092[INFO] Step 9. Time 4.50. $n$ 0.9346400325048942
2026-10-14 01:46:32,105[INFO] Step 10. Time 5.00. $n$ 0.9278351842224875
2026-10-14 01:46:32,118[INFO] Step 11. Time 5.50. $n$ 0.921029899617328
2026-10-14 01:46:32,132[INFO] Step 12. Time 6.00. $n$ 0.9141749831328395
2026-10-14 01:46:32,145[INFO] Step 13. Time 6.50. $n$ 0.9072563582335615
2026-10-14 01:46:32,158[INFO] Step 14. Time 7.00. $n$ 0.9002591285942482
2026-10-14 01:46:32,171[INFO] Step 15. Time 7.50. $n$ 0.893152108533183
2026-10-14 01:46:32,184[INFO] Step 16. Time 8.00. $n$ 0.8858943878858218
2026-10-14 01:46:32,198[INFO] Step 17. Time 8.50. $n$ 0.87845535986051
2026-10-14 01:46:32,211[INFO] Step 18. Time 9.00. $n$ 0.8708472420376305
2026-10-14 01:46:32,224[INFO] Step 19. Time 9.50. $n$ 0.863161654921283
2026-10-14 01:46:32,249[INFO] MPS bond dimension after expanding: [1, 2, 8, 1]
2026-10-14 01:46:32,250[INFO] Step 0. Time 0.00. $n$ 0.9999999999999999
2026-10-14 01:46:32,263[INFO] Step 1. Time 0.50. $n$ 0.9975401925879047
2026-10-14 01:46:32,277[INFO] Step 2. Time 1.00. $n$ 0.9906013628490247
2026-10-14 01:46:32,290[INFO] Step 3. Time 1.50. $n$ 0.9802488858640304
2026-10-14 01:46:32,303[INFO] Step 4. Time 2.00. $n$ 0.9676593608104599
2026-10-14 01:46:32,317[INFO] Step 5. Time 2.50. $n$ 0.9537696503059964
2026-10-14 01:46:32,330[INFO] Step 6. Time 3.00. $n$ 0.9392072948520427
2026-10-14 01:46:32,343[INFO] Step 7. Time 3.50. $n$ 0.9243586104259068
2026-10-14 01:46:32,357[INFO] Step 8. Time 4.00. $n$ 0.9094397848357549
2026-10-14 01:46:32,370[INFO] Step 9. Time 4.50. $n$ 0.8945511232281894
2026-10-14 01:46:32,383[INFO] Step 10. Time 5.00. $n$ 0.8797430038663074
2026-10-14 01:46:32,397[INFO] Step 11. Time 5.50. $n$ 0.8650797798242396
2026-10-14 01:46:32,410[INFO] Step 12. Time 6.00. $n$ 0.8506519218061608
2026-10-14 01:46:32,423[INFO] Step 13. Time 6.50. $n$ 0.8365374567167934
2026-10-14 01:46:32,436[INFO] Step 14. Time 7.00. $n$ 0.8227688239626167
2026-10-14 01:46:32,449[INFO] Step 15. Time 7.50. $n$ 0.8093300617625527
2026-10-14 01:46:32,463[INFO] Step 16. Time 8.00. $n$ 0.7961632960751635
2026-10-14 01:46:32,476[INFO] Step 17. Time 8.50. $n$ 0.7831685752127828
2026-10-14 01:46:32,489[INFO] Step 18. Time 9.00. $n$ 0.7702000677808496
2026-10-14 01:46:32,503[INFO] Step 19. Time 9.50. $n$ 0.7570646850942878
2026-10-14 01:46:32,528[INFO] MPS bond dimension after expanding: [1, 2, 8, 1]
2026-10-14 01:46:32,529[INFO] Step 0. Time 0.00. $n$ 1.0
2026-10-14 01:46:32,544[INFO] Step 1. Time 0.50. $n$ 0.9975277339592459
2026-10-14 01:46:32,557[INFO] Step 2. Time 1.00. $n$ 0.9904261839751389
2026-10-14 01:46:32,570[INFO] Step 3. Time 1.50. $n$ 0.9795268047068697
2026-10-14 01:46:32,583[INFO] Step 4. Time 2.00. $n$ 0.9659170449060868
2026-10-14 01:46:32,598[INFO] Step 5. Time 2.50. $n$ 0.9506850089406372
2026-10-14 01:46:32,612[INFO] Step 6. Time 3.00. $n$ 0.9347455146608092
2026-10-14 01:46:32,625[INFO] Step 7. Time 3.50. $n$ 0.918742272664204
2026-10-14 01:46:32,642[INFO] Step 8. Time 4.00. $n$ 0.9030158921696358
2026-10-14 01:46:32,656[INFO] Step 9. Time 4.50. $n$ 0.8876520609099995
2026-10-14 01:46:32,669[INFO] Step 10. Time 5.00. $n$ 0.8725982798020762
2026-10-14 01:46:32,682[INFO] Step 11. Time 5.50. $n$ 0.8577742342545667
2026-10-14 01:46:32,696[INFO] Step 12. Time 6.00. $n$ 0.8431151893145141
2026-10-14 01:46:32,710[INFO] Step 13. Time 6.50. $n$ 0.8285809886858968
2026-10-14 01:46:32,723[INFO] Step 14. Time 7.00. $n$ 0.8141772509580619
2026-10-14 01:46:32,737[INFO] Step 15. Time 7.50. $n$ 0.7999687732324235
2026-10-14 01:46:32,750[INFO] Step 16. Time 8.00. $n$ 0.7860556760300724
2026-10-14 01:46:32,766[INFO] Step 17. Time 8.50. $n$ 0.7725203376735785
2026-10-14 01:46:32,779[INFO] Step 18. Time 9.00. $n$ 0.7593659426994879
2026-10-14 01:46:32,792[INFO] Step 19. Time 9.50. $n$ 0.746461560509593
2026-10-14 01:46:32,819[INFO] MPS bond dimension after expanding: [1, 2, 8, 1]
2026-10-14 01:46:32,820[INFO] Step 0. Time 0.00. $n$ 1.0
2026-10-14 01:46:32,834[INFO] Step 1. Time 0.50. $n$ 0.9975406090105956
2026-10-14 01:46:32,849[INFO] Step 2. Time 1.00. $n$ 0.9906249611406759
2026-10-14 01:46:32,863[INFO] Step 3. Time 1.50. $n$ 0.9804700824710505
2026-10-14 01:46:32,877[INFO] Step 4. Time 2.00. $n$ 0.9686190882357345
2026-10-14 01:46:32,891[INFO] Step 5. Time 2.50. $n$ 0.9564506630039392
2026-10-14 01:46:32,905[INFO] Step 6. Time 3.00. $n$ 0.9448244017405336
2026-10-14 01:46:32,919[INFO] Step 7. Time 3.50. $n$ 0.9339798618067823
2026-10-14 01:46:32,932[INFO] Step 8. Time 4.00. $n$ 0.9236970054408269
2026-10-14 01:46:32,946[INFO] Step 9. Time 4.50. $n$ 0.9136118419975218
2026-10-14 01:46:32,960[INFO] Step 10. Time 5.00. $n$ 0.9034945341226438
2026-10-14 01:46:32,973[INFO] Step 11. Time 5.50. $n$ 0.8933290940569689
2026-10-14 01:46:32,987[INFO] Step 12. Time 6.00. $n$ 0.8832123669504437
2026-10-14 01:46:33,001[INFO] Step 13. Time 6.50. $n$ 0.8732206640594663
2026-10-14 01:46:33,014[INFO] Step 14. Time 7.00. $n$ 0.8633414313841793
2026-10-14 01:46:33,029[INFO] Step 15. Time 7.50. $n$ 0.8534881636839358
2026-10-14 01:46:33,043[INFO] Step 16. Time 8.00. $n$ 0.8435889218011109
2026-10-14 01:46:33,057[INFO] Step 17. Time 8.50. $n$ 0.8336922461638034
2026-10-14 01:46:33,070[INFO] Step 18. Time 9.00. $n$ 0.8239993937768332
2026-10-14 01:46:33,084[INFO] Step 19. Time 9.50. $n$ 0.8147658347612909
2026-10-14 01:46:33,109[INFO] MPS bond dimension after expanding: [1, 2, 8, 1]
2026-10-14 01:46:33,110[INFO] Step 0. Time 0.00. $n$ 0.9999999999999999
2026-10-14 01:46:33,124[INFO] Step 1. Time 0.50. $n$ 0.9975784978846652
2026-10-14 01:46:33,137[INFO] Step 2. Time 1.00. $n$ 0.9911783314788788
2026-10-14 01:46:33,151[INFO] Step 3. Time 1.50. $n$ 0.9828793267407698
2026-10-14 01:46:33,164[INFO] Step 4. Time 2.00. $n$ 0.974804737510624
2026-10-14 01:46:33,177[INFO] Step 5. Time 2.50. $n$ 0.9681008008243928
2026-10-14 01:46:33,190[INFO] Step 6. Time 3.00. $n$ 0.9626946118364176
2026-10-14 01:46:33,203[INFO] Step 7. Time 3.50. $n$ 0.9578334887382711
2026-10-14 01:46:33,216[INFO] Step 8. Time 4.00. $n$ 0.9528636883612388
2026-10-14 01:46:33,230[INFO] Step 9. Time 4.50. $n$ 0.9476402488995558
2026-10-14 01:46:33,243[INFO] Step 10. Time 5.00. $n$ 0.9423714783197507
2026-10-14 01:46:33,256[INFO] Step 11. Time 5.50. $n$ 0.9372226613902708
2026-10-14 01:46:33,270[INFO] Step 12. Time 6.00. $n$ 0.932143487387623
2026-10-14 01:46:33,283[INFO] Step 13. Time 6.50. $n$ 0.9270168710144905
2026-10-14 01:46:33,296[INFO] Step 14. Time 7.00. $n$ 0.9218472771077
2026-10-14 01:46:33,309[INFO] Step 15. Time 7.50. $n$ 0.9167421622551066
2026-10-14 01:46:33,323[INFO] Step 16. Time 8.00. $n$ 0.911727659809429
2026-10-14 01:46:33,336[INFO] Step 17. Time 8.50. $n$ 0.906647971798646
2026-10-14 01:46:33,349[INFO] Step 18. Time 9.00. $n$ 0.9013355144296522
2026-10-14 01:46:33,363[INFO] Step 19. Time 9.50. $n$ 0.8959335401053742

By plotting the figure, we see that when \(\Delta G=-1\), the charge transfer rate is highest.

[27]:
t = np.arange(len(n_list_list[0])) * dt
for i, n_list in enumerate(n_list_list):
    label = r"$\Delta G =" + str(delta_g_list[i]) + "$"
    plt.plot(t, n_list, label=label, linestyle="--")
plt.xlabel("$t$")
plt.ylabel(r"Occupation $\langle a^\dagger_0 a_0 \rangle$")
plt.legend()
[27]:
<matplotlib.legend.Legend at 0x7f1b96ed5250>
../_images/tutorials_time_evolution_42_1.png

The prediction is consistent with the Marcus theory ,where the Marcus rate is

\[k = \frac{V^2}{\hbar} \sqrt{\frac{\pi\beta}{\lambda}} \exp{\left (-\frac{\beta(\lambda + \Delta G)^2}{4\lambda} \right )}\]

Here \(\lambda = 2g^2\omega = 1\) is the reorganization energy.

Features of Time Evolution Schemes

Renormalizer has a lot of different time evolution schemes, the most commonly used ones are

  1. Propagation and Compression: EvolveMethod.prop_and_compress

  2. Single-site TDVP-PS: EvolveMethod.tdvp_ps

  3. Two-site TDVP-PS: EvolveMethod.tdvp_ps2

  4. TDVP with varianble mean field (VMF): EvolveMethod.tdvp_vmf

The features of these methods are as follows

Name

Accuracy

Computational Cost

Adaptive Step-Size

Adaptive Bond Dimension

Projection Error

prop_and_compress

Low

High

partial

Yes

No

tdvp_ps

High

Low

No

No

Yes

tdvp_ps2

High

High

No

Yes

Partial

tdvp_vmf

High

High

Yes

No

Yes

“Adaptive Step-Size” refers to the ability to dynamically adjust the time-evolution step size based on a predefined error threshold. In practice, this means the method automatically takes smaller steps when the wavefunction changes abruptly and larger steps when it evolves smoothly. For example, tdvp_vmf performs multiple small steps within a single call to the evolve method. This capability removes the need for users to manually check step-size convergence in TD-DMRG by testing multiple step sizes.

“Adaptive Bond Dimension” refers to the ability to dynamically adjust the bond dimension during time evolution. Typically, the initial state is a Hartree product state. For tdvp_ps and tdvp_vmf, the expand_bond_dimension method should be called before starting the time evolution. Otherwise, the simulation will proceed with a bond dimension of 1 rather than the value specified in the optimization settings.

“Projection Error” is the error introduced when projecting the time derivative onto the MPS manifold.

Empirically, we recommend tdvp_ps for production level calculations.

[ ]: