# Excitations with DMRG and segment boundary conditions

This notebook illustrates how we can find excited states with DMRG.

The idea is that we run a first DMRG to find the ground state $$|\psi_0\rangle$$ and then run DMRG on a modified Hamiltonian

$H \rightarrow H'= (1-|\psi_0 \rangle \langle \psi_0|) H (1-|\psi_0 \rangle \langle \psi_0|)$

to find the first excited state $$|\psi_1\rangle$$.

For the second excited state, we would use

$H \rightarrow H''= (1-|\psi_0 \rangle \langle \psi_0| - |\psi_1 \rangle \langle \psi_1|) H (1-|\psi_0 \rangle \langle \psi_0| - |\psi_1 \rangle \langle \psi_1|),$

and so on.

In the infinite case, this doesn’t work because the overlaps/projectors are no longer well defined. However, we can consider a finite segment in the infinite chain, and take the limit of making that segment very big.

• ☒ Choose the (beggining of the) filename such that the order of the included examples makes somewhat sense and the basic examples come first.

• ☒ Include a title at the top of the notebook to make sure it can be included into the documentation. Use only subtitles afterwards.

• ☐ Include the output such that others don’t need to rerun everything to see it.

• ☐ Before saving, “Restart Kernel and Run All Cells” to ensure that everything works properly.

• ☐ Add a summary of what is shown in the example at the top, if this seems useful/necessary.

• ☐ Remove this comment

[1]:

import numpy as np
import scipy
import matplotlib.pyplot as plt
np.set_printoptions(precision=5, suppress=True, linewidth=100)
plt.rcParams['figure.dpi'] = 150

[2]:

import tenpy
import tenpy.linalg.np_conserved as npc
from tenpy.algorithms import dmrg
from tenpy.networks.mps import MPS
from tenpy.models.xxz_chain import XXZChain
from tenpy.models.tf_ising import TFIChain

tenpy.tools.misc.setup_logging(to_stdout="INFO")


## Infinite Systems with a modified center: segment boundary conditions

For infinite systems, the issue arrises that the overlap of two different states is formally always zero. However, we can look for excitations on a finite “segment” in the center and keep everything outside this segment fixed:

fixed left half-infinte chain   |      "segment"                        |   fixed right half-infinte chain

... --A[-3]--A[-2]--A[-1]--C[0]--C[1]--C[2]-- ... --C[L-2]--C[L-1]--B[L]--B[L+1]--B[L+2]-- ...


Here, all the A of the left half-chain have to be in left-canonical form, all the B on the right are right-canonical, and the C can be in any canonical form, with a center matrix somewhere (where we do DMRG). Since we keep the A and B fixed, the overlap with a state of modified C is well definied again, and we can use the same trick to orhtogonalize against previously found states.

In DMRG, we can acchieve this situation by just fixing the environments at the boundaries of the segment. If we take trivial boundaries on one of the two sides, we can study the boundary of a half-infinite chain.

[3]:

from tenpy.models.lattice import TrivialLattice
from tenpy.models.model import MPOModel
from tenpy.networks.mpo import MPOEnvironment

[4]:

model_params = {
'J': 1. , 'g': 1.5,
'L': 2,
'bc_MPS': 'infinite',
'conserve': 'best',
}

M_i = TFIChain(model_params)

INFO    : TFIChain: reading 'bc_MPS'='infinite'
INFO    : TFIChain: set conserve to parity

[5]:

# first dmrg run for *infinite* lattice
psi0_i = MPS.from_lat_product_state(M_i.lat, [['up']])

dmrg_params = {
'mixer': True,
'max_E_err': 1.e-10,
'trunc_params': {
'chi_max': 100,
'svd_min': 1.e-10,
},
}
eng0_i = dmrg.TwoSiteDMRGEngine(psi0_i, M_i, dmrg_params)
E0_i, _ = eng0_i.run()
resume_psi0_i = eng0_i.get_resume_data(sequential_simulations=True)

INFO    : TwoSiteDMRGEngine: subconfig 'trunc_params'=Config(<2 options>, 'trunc_params')
INFO    : start environment_sweep
INFO    : Running sweep with optimization
INFO    : start environment_sweep
INFO    : checkpoint after sweep 10
energy=-1.6719262215361717, max S=0.3777904057721018, age=128, norm_err=5.0e-16
Current memory usage 118.9MB, wall time: 1.2s
Delta E = nan, Delta S = 3.7779e-02 (per sweep)
max trunc_err = 1.5828e-20, max E_trunc = 2.8422e-14
chi: [22, 22]
================================================================================
INFO    : Running sweep with optimization
INFO    : disable mixer after 15 sweeps, final amplitude 3.05e-10
INFO    : start environment_sweep
INFO    : checkpoint after sweep 20
energy=-1.6719262215361894, max S=0.3777889917398420, age=248, norm_err=9.2e-16
Current memory usage 118.9MB, wall time: 1.2s
Delta E = -1.7764e-15, Delta S = -1.3730e-07 (per sweep)
max trunc_err = 2.1066e-20, max E_trunc = 5.6843e-14
chi: [21, 21]
================================================================================
INFO    : DMRG finished after 20 sweeps, max chi=21

[6]:

resume_psi0_i

[6]:

{'psi': <tenpy.networks.mps.MPS at 0x7fe6d7956580>,
'init_env_data': {'init_LP': <npc.Array shape=(21, 3, 21) labels=['vR*', 'wR', 'vR']>,
'init_RP': <npc.Array shape=(21, 3, 21) labels=['vL', 'wL', 'vL*']>,
'age_LP': 124,
'age_RP': 124}}

[7]:

psi0_i.entanglement_entropy()

[7]:

array([0.15349, 0.15349])

[8]:

enlarge = 10  # this is a parameter: how large should the "segment" be?
# beware: if you have gapless excitations, this will induce a "finite-size" gap ~ 1/(enlarge*N_sites_per_unit_cell)

M_s = M_i.extract_segment(enlarge=10)
first, last = M_s.lat.segment_first_last

psi0_s = psi0_i.extract_segment(first, last)
init_env_data = eng0_i.env.get_initialization_data(first, last)

psi1_s = psi0_s.copy()  # TODO: perturb this a little bit
resume_psi1_s = {'init_env_data': init_env_data}


Note: there is a somewhat arbitrary constant in the energy depending on the number of contracted sites in the environment. You should only compare energy differences!

[9]:

eng = dmrg.TwoSiteDMRGEngine(psi1_s, M_s, dmrg_params, resume_data=resume_psi1_s)
E1_s, _ = eng.run()

INFO    : TwoSiteDMRGEngine: reading 'diag_method'='default'
INFO    : TwoSiteDMRGEngine: subconfig 'trunc_params'=Config(<5 options>, 'trunc_params')
INFO    : TwoSiteDMRGEngine: subconfig 'lanczos_params'=Config(<9 options>, 'lanczos_params')
INFO    : TwoSiteDMRGEngine: subconfig 'mixer_params'=Config(<3 options>, 'mixer_params')
INFO    : Running sweep with optimization
INFO    : checkpoint after sweep 10
energy=-446.5168099222832438, max S=0.3777916561162044, age=268, norm_err=1.9e-12
Current memory usage 119.5MB, wall time: 10.9s
Delta E = nan, Delta S = 2.2430e-02 (per sweep)
max trunc_err = 4.0435e-20, max E_trunc = 7.9581e-13
chi: [21, 22, 23, 20, 22, 20, 22, 24, 21, 25, 25, 21, 22, 22, 26, 24, 22, 25, 25, 23, 21]
================================================================================
INFO    : Running sweep with optimization
INFO    : disable mixer after 15 sweeps, final amplitude 3.05e-10
INFO    : checkpoint after sweep 20
energy=-446.5168099222866545, max S=0.3777889917721954, age=268, norm_err=1.4e-13
Current memory usage 119.7MB, wall time: 6.4s
Delta E = -3.4106e-13, Delta S = -5.0629e-08 (per sweep)
max trunc_err = 2.1068e-20, max E_trunc = 3.4106e-13
chi: [21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21]
================================================================================
INFO    : DMRG finished after 20 sweeps, max chi=21

[10]:

psi1_s.entanglement_entropy()

[10]:

array([0.15349, 0.15349, 0.15349, 0.15349, 0.15349, 0.15349, 0.15349, 0.15349, 0.15349, 0.15349,
0.15349, 0.15349, 0.15349, 0.15349, 0.15349, 0.15349, 0.15349, 0.15349, 0.15349, 0.15349,
0.15349])

[11]:

psi1_s.entanglement_entropy() - np.mean(psi0_i.entanglement_entropy())

[11]:

array([-0., -0., -0., -0., -0., -0., -0., -0., -0., -0., -0., -0., -0., -0., -0., -0., -0., -0.,
-0., -0., -0.])

[ ]:




## project left boundary onto largest right schmidt state, use trivial/finite left bc

[12]:

psi_halfinf = psi0_s.copy()  # the oringinal MPS
S = psi0_s.get_SL(0)
proj = np.zeros(len(S), bool)
proj[np.argmax(S)] = True
B = psi_halfinf.get_B(0, form='B')
B.iproject(proj, 'vL')
psi_halfinf.set_B(0, B, form='B')
psi_halfinf.set_SL(0, np.ones(1, float))
psi_halfinf.canonical_form_finite()
psi_halfinf.test_sanity()

init_env_data_halfinf = init_env_data.copy()
init_env_data_halfinf['init_LP'] = MPOEnvironment(psi0_i, M_i.H_MPO, psi0_i).init_LP(0, 0)
init_env_data_halfinf['age_LP'] = 0

[13]:

eng_halfinf = dmrg.TwoSiteDMRGEngine(psi_halfinf, M_s, dmrg_params,
resume_data={'init_env_data': init_env_data_halfinf})
eng_halfinf.run()

INFO    : TwoSiteDMRGEngine: reading 'diag_method'='default'
INFO    : TwoSiteDMRGEngine: subconfig 'trunc_params'=Config(<5 options>, 'trunc_params')
INFO    : TwoSiteDMRGEngine: subconfig 'lanczos_params'=Config(<9 options>, 'lanczos_params')
WARNING : dropping init_LP with incompatible MPS legs
INFO    : TwoSiteDMRGEngine: subconfig 'mixer_params'=Config(<3 options>, 'mixer_params')
INFO    : Running sweep with optimization
INFO    : checkpoint after sweep 10
energy=-239.8856633379389791, max S=0.3777897911442927, age=144, norm_err=5.1e-11
Current memory usage 125.4MB, wall time: 7.9s
Delta E = nan, Delta S = 2.2746e-02 (per sweep)
max trunc_err = 4.1687e-20, max E_trunc = 3.6948e-13
chi: [1, 2, 4, 8, 12, 21, 21, 21, 22, 23, 24, 20, 21, 22, 22, 20, 23, 23, 24, 23, 21]
================================================================================
INFO    : Running sweep with optimization
INFO    : disable mixer after 15 sweeps, final amplitude 3.05e-10
INFO    : checkpoint after sweep 20
energy=-239.8856633379392065, max S=0.3777889746421544, age=144, norm_err=5.1e-11
Current memory usage 125.4MB, wall time: 5.0s
Delta E = -2.2737e-14, Delta S = -1.8449e-08 (per sweep)
max trunc_err = 2.0794e-20, max E_trunc = 1.1369e-13
chi: [1, 2, 4, 8, 13, 17, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21]
================================================================================
INFO    : DMRG finished after 20 sweeps, max chi=21

[13]:

(-239.8856633379392, <tenpy.networks.mps.MPS at 0x7fe6d402e940>)

[14]:

psi_halfinf.entanglement_entropy()

[14]:

array([-0.     ,  0.13332,  0.14834,  0.15192,  0.15297,  0.15331,  0.15343,  0.15347,  0.15348,
0.15349,  0.15349,  0.15349,  0.15349,  0.15349,  0.15349,  0.15349,  0.15349,  0.15349,
0.15349,  0.15349,  0.15349])

[15]:

psi_halfinf.expectation_value('Sigmaz')

[15]:

array([0.94082, 0.88667, 0.87957, 0.87797, 0.87753, 0.8774 , 0.87735, 0.87734, 0.87733, 0.87733,
0.87733, 0.87733, 0.87733, 0.87733, 0.87733, 0.87733, 0.87733, 0.87733, 0.87733, 0.87733])

[16]:

psi_halfinf.L

[16]:

20


## modify model on left boundary

[17]:

model_params_defect = {
'J': 1. , 'g': [0.] + [model_params['g']] * (psi_halfinf.L-1),
'L': psi_halfinf.L,
'bc_MPS': 'segment',
'conserve': 'best',
}

M_s_defect = TFIChain(model_params_defect)

INFO    : TFIChain: reading 'bc_MPS'='segment'
INFO    : TFIChain: set conserve to parity
INFO    : TFIChain: reading 'g'=[0.0, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5]

[18]:

psi_defect = psi_halfinf.copy()
eng_defect = dmrg.TwoSiteDMRGEngine(psi_defect, M_s_defect, dmrg_params,
resume_data={'init_env_data': init_env_data_halfinf})
eng_defect.run()

INFO    : TwoSiteDMRGEngine: reading 'diag_method'='default'
INFO    : TwoSiteDMRGEngine: subconfig 'trunc_params'=Config(<5 options>, 'trunc_params')
INFO    : TwoSiteDMRGEngine: subconfig 'lanczos_params'=Config(<9 options>, 'lanczos_params')
WARNING : dropping init_LP with incompatible MPS legs
INFO    : TwoSiteDMRGEngine: subconfig 'mixer_params'=Config(<3 options>, 'mixer_params')
INFO    : Running sweep with optimization
INFO    : checkpoint after sweep 10
energy=-238.5696710150712363, max S=0.5073196916549362, age=144, norm_err=7.3e-09
Current memory usage 127.0MB, wall time: 9.3s
Delta E = nan, Delta S = 2.5631e-02 (per sweep)
max trunc_err = 3.5642e-20, max E_trunc = 4.5475e-13
chi: [1, 2, 4, 8, 16, 22, 22, 24, 25, 26, 25, 22, 25, 24, 25, 22, 25, 26, 24, 24, 21]
================================================================================
INFO    : Running sweep with optimization
INFO    : disable mixer after 15 sweeps, final amplitude 3.05e-10
INFO    : checkpoint after sweep 20
energy=-238.5696710150708100, max S=0.5073196916551133, age=144, norm_err=7.3e-09
Current memory usage 127.3MB, wall time: 7.1s
Delta E = 4.2633e-14, Delta S = -2.6677e-08 (per sweep)
max trunc_err = 1.9092e-20, max E_trunc = 6.8212e-13
chi: [1, 2, 4, 8, 15, 20, 23, 24, 25, 26, 26, 25, 24, 24, 24, 24, 24, 24, 24, 24, 21]
================================================================================
INFO    : DMRG finished after 20 sweeps, max chi=26

[18]:

(-238.5696710150708, <tenpy.networks.mps.MPS at 0x7fe6c1eb3070>)

[19]:

psi_defect.entanglement_entropy()

[19]:

array([-0.     ,  0.38126,  0.2482 ,  0.1929 ,  0.16987,  0.16032,  0.15635,  0.15469,  0.154  ,
0.15371,  0.15358,  0.15353,  0.15351,  0.1535 ,  0.15349,  0.15349,  0.15349,  0.15349,
0.15349,  0.15349,  0.15349])

[20]:

psi_defect.expectation_value('Sigmaz')

[20]:

array([0.74536, 0.74534, 0.83553, 0.86216, 0.87149, 0.87501, 0.87639, 0.87694, 0.87717, 0.87726,
0.8773 , 0.87732, 0.87732, 0.87733, 0.87733, 0.87733, 0.87733, 0.87733, 0.87733, 0.87733])

[ ]:



[ ]: