"""Examples using segment boundary conditions
This code shows the general structure of DMRG with segment boundary conditions, which allows
to find topologically non-trivial excitations on a "finite" segment between two different
degenerate ground states.
For production, you should probably use the
:class:`~tenpy.simulations.GroundStateSearch.OrthogonalExcitations` class,
but this example might be helpful to see the general idea.
"""
# Copyright (C) TeNPy Developers, Apache license
import matplotlib.pyplot as plt
import numpy as np
import tenpy.linalg.np_conserved as npc
from tenpy.algorithms import dmrg
from tenpy.models.tf_ising import TFIChain
from tenpy.networks.mps import MPS
from tenpy.tools.params import Config
def calc_infinite_groundstates(dmrg_params, g=0.1):
L = 2
model_params = dict(L=L, J=1.0, g=g, bc_MPS='infinite', conserve=None, verbose=0)
model = TFIChain(model_params)
plus_x = np.array([1.0, 1.0]) / np.sqrt(2)
minus_x = np.array([1.0, -1.0]) / np.sqrt(2)
psi_plus = MPS.from_product_state(
model.lat.mps_sites(), [plus_x] * L, model.lat.bc_MPS, unit_cell_width=model.lat.mps_unit_cell_width
)
psi_minus = MPS.from_product_state(
model.lat.mps_sites(), [minus_x] * L, model.lat.bc_MPS, unit_cell_width=model.lat.mps_unit_cell_width
)
engine_plus = dmrg.TwoSiteDMRGEngine(psi_plus, model, dmrg_params)
engine_plus.run()
print('<Sx> =', psi_plus.expectation_value('Sigmax'))
engine_minus = dmrg.TwoSiteDMRGEngine(psi_minus, model, dmrg_params)
engine_minus.run()
print('<Sx> =', psi_minus.expectation_value('Sigmax'))
data_plus = {'psi': psi_plus}
data_plus.update(**engine_plus.env.get_initialization_data())
data_minus = {'psi': psi_minus}
data_minus.update(**engine_minus.env.get_initialization_data())
return model, data_plus, data_minus
def prepare_segment(model, data_L, data_R, repeat_L=20, repeat_R=20):
psi_L = data_L['psi'].copy()
psi_R = data_R['psi'].copy()
psi_L.convert_form('B')
psi_R.convert_form('B')
psi_L.enlarge_mps_unit_cell(repeat_L)
psi_R.enlarge_mps_unit_cell(repeat_R)
psi_L.bc = 'segment'
psi_R.bc = 'segment'
model.enlarge_mps_unit_cell(repeat_L + repeat_R)
model.lat.bc_MPS = 'segment'
model.H_MPO.bc = 'segment'
init_env_data = {
'init_LP': data_L['init_LP'],
'age_LP': data_L['age_LP'],
'init_RP': data_R['init_RP'],
'age_RP': data_R['age_RP'],
}
Bs_L = [psi_L.get_B(i) for i in range(psi_L.L)]
Bs_R = [psi_R.get_B(i) for i in range(psi_R.L)]
joint = npc.Array.from_func(
np.ones,
[Bs_L[-1].get_leg('vR').conj(), Bs_R[0].get_leg('vL').conj()],
psi_L.dtype,
qtotal=None,
labels=['vL', 'vR'],
)
Bs_L[-1] = npc.tensordot(Bs_L[-1], joint, axes=['vR', 'vL'])
S = psi_L._S[:-1] + psi_R._S
psi = MPS(psi_L.sites + psi_R.sites, Bs_L + Bs_R, S, 'segment', unit_cell_width=model.lat.mps_unit_cell_width)
# UL, UR = psi.canonical_form_finite()
return psi, model, init_env_data
def calc_segment_groundstate(psi, model, dmrg_params):
engine = dmrg.TwoSiteDMRGEngine(psi, model, dmrg_params)
E, psi = engine.run()
return psi
def plot(psi, filename):
x = np.arange(psi.L)
meas = psi.expectation_value('Sigmax')
fig = plt.figure() # noqa F841
ax = plt.gca()
ax.plot(x, meas)
ax.set_ylabel('<sigma_x>')
ax.set_xlabel('$x$')
plt.savefig(filename)
print('saved to ' + filename)
if __name__ == '__main__':
dmrg_params = Config(
{
'trunc_params': {'chi_max': 50, 'svd_min': 1.0e-10, 'trunc_cut': None},
'update_env': 0,
'start_env': 2,
'max_E_err': 1.0e-6,
'max_S_err': 1.0e-5,
'max_sweeps': 100,
'verbose': 1,
'mixer': False,
},
'DMRG',
)
model, psi_plus, psi_minus = calc_infinite_groundstates(dmrg_params)
psi, model, init_env_data = prepare_segment(model, psi_plus, psi_minus)
dmrg_params['init_env_data'] = init_env_data
results = calc_segment_groundstate(psi, model, dmrg_params)
plot(results, 'tfi_segment.pdf')