Пример #1
0
def trace(op):
    """
    Return the trace of an MPO without approximation.
    """
    L = op.L
    s = op.s
    idMPO = MPO.MPO(L, 1, s)
    idMPO.setProductOperator(np.identity(s))
    opMPS = MPO.MPSfromMPO(op)
    idMPS = MPO.MPSfromMPO(idMPO)
    return contractMPS(opMPS, idMPS)
Пример #2
0
def getSumNMPO(L, Nmax):
    """
    Input: system size L, maximum occupation number Nmax.
    Return: the MPO of sum of occupation numbers at all sites.
    """
    d = Nmax + 1
    Z = np.zeros((2, d, d), dtype=complex)
    Z[0, :, :] = np.identity(d, dtype=complex)  # Id
    Z[1, :, :] = np.diag(np.arange(d) + 0j)  # n
    sumN = MPO.MPO(L, 2, d)
    opL = np.zeros((1, 2, 2), dtype=complex)
    opL[0, 0, 0] = 1
    opL[0, 1, 1] = 1
    sumN.setA(0, np.einsum('ijk,kmn->mnij', opL, Z))
    opR = np.zeros((2, 1, 2), dtype=complex)
    opR[0, 0, 1] = 1
    opR[1, 0, 0] = 1
    sumN.setA(L - 1, np.einsum('ijk,kmn->mnij', opR, Z))
    for i in range(1, L - 1):
        opM = np.zeros((2, 2, 2), dtype=complex)
        opM[0, 0, 0] = 1
        opM[0, 1, 1] = 1
        opM[1, 1, 0] = 1
        sumN.setA(i, np.einsum('ijk,kmn->mnij', opM, Z))
    return sumN
Пример #3
0
    def __init__(self, L, Nmax, t, U, mu, V, Vint, offset):
        """
        Initialization.
        Input: system size L (int), maximum occupation number N (int), t, U, mu, V, Vint
               (all are either float or numpy float array of length L) and offset (float).
        Will generate the MPO of Hamiltonian in self.hamil.
        """
        self.L = L
        self.d = Nmax + 1
        self.t = Common.toArray(L, t)
        self.U = Common.toArray(L, U)
        self.mu = Common.toArray(L, mu)
        self.V = Common.toArray(L, V)
        self.Vint = Common.toArray(L, Vint)
        self.hamil = MPO.MPO(L, 5, self.d)
        self.offset = offset
        delta = offset / L

        self.Z = np.zeros((5, self.d, self.d), dtype=complex)
        self.Z[0, :, :] = np.identity(self.d, dtype=complex)  # Id
        self.Z[1, :, :] = np.diag(
            np.arange(self.d) * (np.arange(self.d) - 1) + 0j)  # n(n-1)
        self.Z[2, :, :] = np.diag(np.sqrt(np.arange(self.d - 1) + 1) + 0j,
                                  -1)  # b^dag
        self.Z[3, :, :] = np.diag(np.sqrt(np.arange(self.d - 1) + 1) + 0j,
                                  1)  # b
        self.Z[4, :, :] = np.diag(np.arange(self.d) + 0j)  # n

        opL = np.zeros((1, 5, 5), dtype=complex)
        opL[0, 0, 0] = 1
        opL[0, 1, 2] = 1
        opL[0, 2, 3] = 1
        opL[0, 3, 4] = 1
        opL[0, 4, 4] = self.V[0] - self.mu[0]
        opL[0, 4, 1] = self.U[0] / 2
        opL[0, 4, 0] = delta
        self.hamil.setA(0, np.einsum('ijk,kmn->mnij', opL, self.Z))
        opR = np.zeros((5, 1, 5), dtype=complex)
        opR[0, 0, 4] = self.V[self.L - 1] - self.mu[self.L - 1]
        opR[0, 0, 1] = self.U[self.L - 1] / 2
        opR[0, 0, 0] = delta
        opR[1, 0, 3] = -self.t[self.L - 1]
        opR[2, 0, 2] = -self.t[self.L - 1]
        opR[3, 0, 4] = self.Vint[self.L - 2]
        opR[4, 0, 0] = 1
        self.hamil.setA(L - 1, np.einsum('ijk,kmn->mnij', opR, self.Z))
        for i in range(1, L - 1):
            opM = np.zeros((5, 5, 5), dtype=complex)
            opM[0, 0, 0] = 1
            opM[0, 1, 2] = 1
            opM[0, 2, 3] = 1
            opM[0, 3, 4] = 1
            opM[0, 4, 4] = self.V[i] - self.mu[i]
            opM[0, 4, 1] = self.U[i] / 2
            opM[0, 4, 0] = delta
            opM[1, 4, 3] = -self.t[i]
            opM[2, 4, 2] = -self.t[i]
            opM[3, 4, 4] = self.Vint[i - 1]
            opM[4, 4, 0] = 1
            self.hamil.setA(i, np.einsum('ijk,kmn->mnij', opM, self.Z))
Пример #4
0
 def __init__(self, L, Jx, Jy, Jz, g, h, offset):
     """
     Initialization.
     Input: system size L (int), interaction Jx, Jy and Jz, longitudinal field g, transverse field h 
            (Jx, Jy, Jz, g and h are either float or numpy float array of length L) and offset (float).
     Will generate the MPO of Hamiltonian in self.hamil.
     """
     self.L = L
     self.Jx = Common.toArray(L, Jx)
     self.Jy = Common.toArray(L, Jy)
     self.Jz = Common.toArray(L, Jz)
     self.g = Common.toArray(L, g)
     self.h = Common.toArray(L, h)
     self.offset = offset
     self.hamil = MPO.MPO(L, 5, 2)
     opL = np.array([[[1, 0, 0, 0], [0, self.Jx[0], 0, 0], [0, 0, self.Jy[0], 0], [0, 0, 0, self.Jz[0]],
                      [offset / L, self.g[0], 0, self.h[0]]]])
     opR = np.array([[[offset / L, self.g[L - 1], 0, self.h[L - 1]]], [[0, 1, 0, 0]], [[0, 0, 1, 0]],
                     [[0, 0, 0, 1]], [[1, 0, 0, 0]]])
     self.hamil.ops[0].A = np.einsum('ijk,kml->mlij', opL, PauliSigma)
     self.hamil.ops[L - 1].A = np.einsum('ijk,kml->mlij', opR, PauliSigma)
     for i in range(1, L - 1):
         opM = np.array([[[1, 0, 0, 0], [0, self.Jx[i], 0, 0], [0, 0, self.Jy[i], 0],
                          [0, 0, 0, self.Jz[i]], [offset / L, self.g[i], 0, self.h[i]]],
                         [[0, 0, 0, 0], [0, 0, 0, 0], [
                             0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 0, 0]],
                         [[0, 0, 0, 0], [0, 0, 0, 0], [
                             0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 0]],
                         [[0, 0, 0, 0], [0, 0, 0, 0], [
                             0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]],
                         [[0, 0, 0, 0], [0, 0, 0, 0], [
                             0, 0, 0, 0], [0, 0, 0, 0], [1, 0, 0, 0]]
                         ])
         self.hamil.ops[i].A = np.einsum('ijk,kml->mlij', opM, PauliSigma)
Пример #5
0
def getSumSzProjector(L, S):
    """
    Return the projector of total spin S. S is twice the physical spin (so that it is an integer).
    L and S have to be simultaneously even or odd.
    """
    if (L % 2 != S % 2):
        print("Error: impossible total spin")
        exit(2)
    Z = np.zeros((2, 2, 2), dtype=complex)
    Z[0, 0, 0] = 1
    Z[1, 1, 1] = 1
    P = MPO.MPO(L, 1, 2)
    Smin = 0
    Smax = 0
    for i in range(L):
        Dl = (Smax - Smin) // 2 + 1
        tmpA = np.zeros((Dl, Dl + 1, 2))
        np.fill_diagonal(tmpA[:, :, 0], 1)
        np.fill_diagonal(tmpA[:, 1:, 1], 1)

        if (Smax + 2 - L + i <= S):
            Smax += 1
        else:
            Smax -= 1
            tmpA = tmpA[:, 1:]
        if (Smin - 2 + L - i >= S):
            Smin -= 1
        else:
            Smin += 1
            tmpA = tmpA[:, :-1]
        tmpA = np.einsum('ijk,mnk->mnij', tmpA, Z)
        P.setA(i, tmpA)
    return P
Пример #6
0
    def getUMPOIsing(self, t, imag=True, cutD=0):
        """
        Return the time-evolution unitary MPO of Ising model.
        Works only when the model is translational invariant!
        """
        hi = self.J[0] * np.kron(PauliSigma[3, :, :], PauliSigma[3, :, :]) + \
            self.h[0] * np.kron(PauliSigma[3, :, :], PauliSigma[0, :, :]) + \
            self.g[0] * np.kron(PauliSigma[1, :, :],
                                PauliSigma[0, :, :])

        hL = self.h[0] * PauliSigma[3, :, :] + self.g[0] * PauliSigma[1, :, :]
        hR = self.h[0] * PauliSigma[3, :, :] + self.g[0] * PauliSigma[1, :, :]
        return MPO.getUMPO(self.L, 2, hi, hL, hR, t, imag=imag, cutD=cutD)
Пример #7
0
def getSumSzMPO(L):
    """
    Return \sum_{i=1}^L sigma_i^z.
    """
    sumSz = MPO.MPO(L, 2, 2)
    opL = np.array([[[1, 0, 0, 0], [0, 0, 0, 1]]])
    opR = np.array([[[0, 0, 0, 1]], [[1, 0, 0, 0]]])
    sumSz.ops[0].A = np.einsum('ijk,kml->mlij', opL, PauliSigma)
    sumSz.ops[L - 1].A = np.einsum('ijk,kml->mlij', opR, PauliSigma)
    for i in range(1, L - 1):
        opM = np.array([[[1, 0, 0, 0], [0, 0, 0, 1]],
                        [[0, 0, 0, 0], [1, 0, 0, 0]]])
        sumSz.ops[i].A = np.einsum('ijk,kml->mlij', opM, PauliSigma)
    return sumSz
Пример #8
0
def joinMPO(opA, opB, cutD=0):
    """
    Return the product of two MPOs. Will make approximation if cutD is set nonzero.
    """
    if (opA.L != opB.L or opA.s != opB.s):
        print("Error: inconsistent length / physical dimension!")
        exit(2)
    else:
        L = opA.L
        s = opA.s
    newMPO = MPO.MPO(L, 1, s)
    for i in range(L):
        tmpA = np.einsum('ijkl,jmpq->imkplq', opA.ops[i].A, opB.ops[i].A)
        tmpA = tmpA.reshape((s, s, opA.ops[i].Dl * opB.ops[i].Dl,
                             opA.ops[i].Dr * opB.ops[i].Dr))
        newMPO.setA(i, tmpA)

    if (cutD > 0):
        # Compress MPO
        newMPS = MPO.MPSfromMPO(newMPO)
        compressNewMPS = compressMPS(newMPS, cutD, silent=True)
        newMPO = MPO.MPOfromMPS(compressNewMPS)

    return newMPO
Пример #9
0
# Test of DMRG & fitApplyMPO & entanglement entropy & total spin projector
#H = IsingModel.hamil
H = HeisenbergModel.hamil
gs = MPS.MPS(L, D, 2)
# gs.setProductState(Sp.Up)

#H = BoseHubbardModel.hamil
#gs = MPS.MPS(L, D, Nmax+1)
gs.setRandomState()
Emin = ct.dmrg(H, gs, D)
gs.saveMPS("saveGsMPS")
H.saveMPO("saveHMPO")
applyH = ct.fitApplyMPO(H, gs, D, tol=1e-4, silent=False, maxRound=20)
gsFile = MPS.loadMPS("saveGsMPS")
HFile = MPO.loadMPO("saveHMPO")
print("Emin =", Emin)
print("<gsF|HF|gsF> =", np.real(ct.contractMPSMPO(gsFile, HFile, gsFile)))
print("<gs|H gs> =", np.real(ct.contractMPS(gs, applyH)))
print("Ground state entanglement entropy is",
      np.exp(gs.getEntanglementEntropy(L // 2)))
print()

totSzMPO = Sp.getSumSzMPO(L)
print("Total spin of ground state if",
      np.real(ct.contractMPSMPO(gs, totSzMPO, gs)))
print()
totS = 2
P = Sp.getSumSzProjector(L, totS)
gsp = ct.exactApplyMPO(P, gs)
print(