MPS Algebra
Construct MPO (set flat=False
if you want to test pure python code):
from pyblock3.hamiltonian import Hamiltonian
from pyblock3.fcidump import FCIDUMP
fd = 'data/HUBBARD-L8.FCIDUMP'
hamil = Hamiltonian(FCIDUMP(pg='c1').read(fd), flat=True)
mpo = hamil.build_qc_mpo()
Construct (random initial) MPS:
bond_dim = 100
mps = hamil.build_mps(bond_dim)
Expectation value:
import numpy as np
np.dot(mps, mpo @ mps)
Block-sparse tensor algebra:
np.tensordot(mps[0], mps[1], axes=1)
MPS canonicalization:
print("MPS = ", mps.show_bond_dims())
mps = mps.canonicalize(center=0)
mps /= mps.norm()
print("MPS = ", mps.show_bond_dims()
Check norm after normalization:
np.dot(mps, mps)
MPO Compression:
print("MPO = ", mpo.show_bond_dims())
mpo, _ = mpo.compress(left=True, cutoff=1E-12, norm_cutoff=1E-12)
print("MPO = ", mpo.show_bond_dims())
DMRG:
from pyblock3.algebra.mpe import MPE
dmrg = MPE(mps, mpo, mps).dmrg(bdims=[bond_dim], noises=[1E-6, 0], dav_thrds=[1E-3], iprint=2, n_sweeps=10)
ener = dmrg.energies[-1]
print("Energy = %20.12f" % ener)
Check ground-state energy:
print('MPS energy = ', np.dot(mps, mpo @ mps))
Check that ground-state MPS is normalized:
print('MPS = ', mps.show_bond_dims())
print('MPS norm = ', mps.norm())
MPS Scaling
MPS scaling (by scaling the first MPS tensor):
mps.opts = {}
print('2 MPS = ', (2 * mps).show_bond_dims())
print((2 * mps).norm())
Check the first MPS tensor:
mps[0]
and
(2 * mps)[0]
MPS Addition
MPS addition will increase the bond dimension:
mps_add = mps + mps
print('MPS + MPS = ', mps_add.show_bond_dims())
print(mps_add.norm())
Check the overlap \(<2MPS|MPS+MPS>\):
mps_add @ (2 * mps)
MPS Canonicalization
Left canonicalization:
lmps = mps_add.canonicalize(center=mps_add.n_sites - 1)
print('L-MPS = ', lmps.show_bond_dims())
Right canonicalization:
rmps = mps_add.canonicalize(center=0)
print('R-MPS = ', rmps.show_bond_dims())
Check the overlap \(<LMPS|RMPS>\):
lmps @ rmps
MPS Compression
Compression will first do canonicalization from left to right, then do SVD from right to left.
This can further decrease bond dimension of MPS.
print('MPS + MPS = ', mps_add.show_bond_dims())
mps_add, _ = mps_add.compress(cutoff=1E-9)
print('MPS + MPS = ', mps_add.show_bond_dims())
print(mps_add.norm())
MPS Subtraction
Subtractoin will also increase bond dimension:
mps_minus = mps - mps
print('MPS - MPS = ', mps_minus.show_bond_dims())
After compression, this is zero:
mps_minus, _ = mps_minus.compress(cutoff=1E-12)
print('MPS - MPS = ', mps_minus.show_bond_dims())
print(mps_minus.norm())
MPS Bond Dimension Truncation
Apply MPO two times to MPS:
hhmps = mpo @ (mpo @ mps)
print(hhmps.show_bond_dims())
print(np.sqrt(hhmps @ mps))
MPS compression can be used to reduce bond dimension (to FCI):
hhmps, cps_error = hhmps.compress(cutoff=1E-12)
print('error = ', cps_error)
print(hhmps.show_bond_dims())
print(np.sqrt(hhmps @ mps))
Truncation to bond dimension 100 will introduce a small error:
hhmps, cps_error = hhmps.compress(max_bond_dim=100, cutoff=1E-12)
print('error = ', cps_error)
print(hhmps.show_bond_dims())
print(np.sqrt(hhmps @ mps))
Truncation to bond dimension 30 will introduce a larger error:
hhmps, cps_error = hhmps.compress(max_bond_dim=30, cutoff=1E-12)
print('error = ', cps_error)
print(hhmps.show_bond_dims())
print(np.sqrt(hhmps @ mps))
MPO-MPO Contraction
One can also first contract two MPO:
h2 = mpo @ mpo
print(h2.show_bond_dims())
Check expectation value:
print(np.sqrt((h2 @ mps) @ mps))
MPO Bond Dimension Truncation
Compression MPO (keeping accuracy):
h2, cps_error = h2.compress(cutoff=1E-12)
print('error = ', cps_error)
print(h2.show_bond_dims())
print(np.sqrt((h2 @ mps) @ mps))
MPO Truncated to bond dimension 15:
h2, cps_error = h2.compress(max_bond_dim=15, cutoff=1E-12)
print('error = ', cps_error)
print(h2.show_bond_dims())
print(np.sqrt((h2 @ mps) @ mps))
MPO Truncated to bond dimension 12:
h2, cps_error = h2.compress(max_bond_dim=12, cutoff=1E-12)
print('error = ', cps_error)
print(h2.show_bond_dims())
print(np.sqrt((h2 @ mps) @ mps))