def ok(Ψ):
     for center in range(Ψ.size):
         ξ = CanonicalMPS(Ψ, center=center)
         #
         # All sites to the left and to the right are isometries
         #
         for i in range(center):
             self.assertTrue(approximateIsometry(ξ[i], +1))
         for i in range(center + 1, ξ.size):
             self.assertTrue(approximateIsometry(ξ[i], -1))
         #
         # Both states produce the same wavefunction
         #
         self.assertTrue(similar(ξ.tovector(), Ψ.tovector()))
         #
         # The norm is correct
         #
         self.assertAlmostEqual(ξ.norm2() / Ψ.norm2(), 1.0)
         #
         # Local observables give the same
         #
         O = np.array([[0, 0], [0, 1]])
         nrm2 = ξ.norm2()
         self.assertAlmostEqual(
             ξ.expectation1(O) / nrm2,
             Ψ.expectation1(O, center) / nrm2)
         #
         # The canonical form is the same when we use the
         # corresponding negative indices of 'center'
         #
         χ = CanonicalMPS(Ψ, center=center - Ψ.size)
         for i in range(Ψ.size):
             self.assertTrue(similar(ξ[i], χ[i]))
 def ok(Ψ):
     for center in range(Ψ.size):
         ξ1 = CanonicalMPS(Ψ, center=center, normalize=False)
         ξ2 = CanonicalMPS(Ψ, center=center, normalize=True)
         self.assertAlmostEqual(ξ2.norm2(), 1.0)
         self.assertTrue(
             similar(ξ1.tovector() / np.sqrt(ξ1.norm2()),
                     ξ2.tovector()))
Example #3
0
 def tensor2siteok(self, aϕ, O1, O2):
     for center in range(aϕ.size):
         ϕ = CanonicalMPS(aϕ, center=center, normalize=True)
         for n in range(ϕ.size - 1):
             #
             # Take an MPS Φ, construct a new state ψ = O1*ϕ with a local
             # operator on the 'n-th' site
             #
             ψ = mps.state.MPS(ϕ)
             ψ[n] = np.einsum('ij,ajb->aib', O1, ψ[n])
             ψ[n + 1] = np.einsum('ij,ajb->aib', O2, ψ[n + 1])
             #
             # and make sure that the AntilinearForm provides the right tensor to
             # compute <ϕ|ψ> = <ϕ|O1|ϕ>
             #
             Odesired = ϕ.expectation2(O1, O2, n)
             LF = AntilinearForm(ϕ, ψ, center)
             if center + 1 < ϕ.size:
                 D = np.einsum('ijk,klm->ijlm', ϕ[center], ϕ[center + 1])
                 Oestimate = np.einsum('aijb,aijb', D.conj(),
                                       LF.tensor2site(+1))
                 self.assertAlmostEqual(Oestimate, Odesired)
             if center > 0:
                 D = np.einsum('ijk,klm->ijlm', ϕ[center - 1], ϕ[center])
                 Oestimate = np.einsum('aijb,aijb', D.conj(),
                                       LF.tensor2site(-1))
                 self.assertAlmostEqual(Oestimate, Odesired)
             if n >= center:
                 self.assertTrue(almostIdentity(LF.L[center], +1))
             if n + 1 <= center:
                 self.assertTrue(almostIdentity(LF.R[center], +1))
 def ok(Ψ):
     for center in range(Ψ.size):
         ξ = CanonicalMPS(Ψ, center=center)
         Lenv = super(CanonicalMPS, ξ).left_environment(center)
         Renv = super(CanonicalMPS, ξ).left_environment(center)
         self.assertTrue(almostIdentity(Lenv))
         self.assertTrue(almostIdentity(Renv))
Example #5
0
 def inactive_test_apply_pairwise_unitaries(self):
     N = 2
     tt = -np.pi/2
     ω = np.pi
     dt = 0.1
     #
     # Numerically exact solution using Scipy's exponentiation routine
     ψwave = random_wavefunction(N)
     print(mps.state.wavepacket(ψwave).tovector())
     HMat = self.hopping_model_Trotter_matrix(N, tt, ω)
     ψwave_final = sp.linalg.expm_multiply(+1j * dt * HMat, ψwave)
     print(mps.state.wavepacket(ψwave_final).tovector())
     print(HMat.todense())
     #
     # Evolution using Trrotter
     H = self.hopping_model(N, tt, ω)
     U = pairwise_unitaries(H, dt)
     ψ = CanonicalMPS(mps.state.wavepacket(ψwave))
     start = 0
     direction = 1
     apply_pairwise_unitaries(U, ψ, start, direction, tol=DEFAULT_TOLERANCE)
     print(ψ.tovector())
     print(np.abs(mps.state.wavepacket(ψwave_final).tovector() - ψ.tovector()))
     
     self.assertTrue(similar(abs(mps.state.wavepacket(ψwave_final).tovector()), 
                             abs(ψ.tovector())))
Example #6
0
 def test_TEBD_evolution_second_order(self):
     #
     #
     #
     N = 21
     t = 0.1
     ω = 0.5
     dt = 1e-6
     Nt = int(1000)
     #ψwave = random_wavefunction(N)
     xx=np.arange(N)
     x0 = int(N//2)
     w0 = 5
     k0 = np.pi/2
     #
     # Approximate evolution of a wavepacket in a tight-binding model
     ψwave = np.exp(-(xx-x0)**2 / w0**2 + 1j * k0*xx) 
     ψwave = ψwave / np.linalg.norm(ψwave) 
     Hmat = self.hopping_model_matrix(N, t, ω)
     ψwave_final = sp.linalg.expm_multiply(-1j * dt * Nt * Hmat, ψwave)
     #
     # Trotter evolution
     H = self.hopping_model(N, t, ω)
     ψmps = CanonicalMPS(mps.state.wavepacket(ψwave))
     ψmps = TEBD_evolution(ψmps, H, dt, timesteps=Nt, order=2, tol=DEFAULT_TOLERANCE).evolve()
     
     self.assertTrue(similar(abs(mps.state.wavepacket(ψwave_final).tovector()), 
                             abs(ψmps.tovector())))
 def ok(Ψ):
     for center in range(Ψ.size):
         ψ = CanonicalMPS(Ψ, center=center, normalize=True)
         ξ = ψ.copy()
         self.assertEqual(ξ.size, ψ.size)
         self.assertEqual(ξ.center, ψ.center)
         for i in range(ξ.size):
             self.assertTrue(np.all(np.equal(ξ[i], ψ[i])))
Example #8
0
 def expected1_ok(ϕ, canonical=False):
     if canonical:
         for i in range(ϕ.size):
             expected1_ok(CanonicalMPS(ϕ, center=i), canonical=False)
     else:
         nrm2 = ϕ.norm2()
         for n in range(ϕ.size):
             ψ = ϕ.copy()
             ψ[n] = np.einsum('ij,kjl->kil', O1, ψ[n])
             desired= np.vdot(ϕ.tovector(), ψ.tovector())
             self.assertAlmostEqual(desired/nrm2, expectation1(ϕ, O1, n)/nrm2)
             self.assertAlmostEqual(desired/nrm2, ϕ.expectation1(O1, n)/nrm2)
Example #9
0
 def expected2_ok(ϕ, canonical=False):
     if canonical:
         for i in range(ϕ.size):
             CanonicalMPS(ϕ, center=i)
     nrm2 = ϕ.norm2()
     for n in range(1, ϕ.size):
         ψ = ϕ.copy()
         ψ[n-1] = np.einsum('ij,kjl->kil', O1, ψ[n-1])
         ψ[n]   = np.einsum('ij,kjl->kil', O2, ψ[n])
         desired= mps.expectation.scprod(ϕ, ψ)
         self.assertAlmostEqual(desired/nrm2, expectation2(ϕ, O1, O2, n-1)/nrm2)
         self.assertAlmostEqual(desired/nrm2, ϕ.expectation2(O1, O2, n-1)/nrm2)
Example #10
0
 def ok(ψ):
     global foo
     for center in range(ψ.size):
         ϕ = CanonicalMPS(ψ, center=center, normalize=True)
         LF = AntilinearForm(ϕ, ϕ, center)
         for i in range(ϕ.size):
             if i <= center:
                 self.assertTrue(similar(LF.L[i],
                                         ϕ.left_environment(i)))
                 self.assertTrue(almostIdentity(LF.L[i], +1))
             if i >= center:
                 self.assertTrue(
                     similar(LF.R[i], ϕ.right_environment(i)))
                 self.assertTrue(almostIdentity(LF.R[i], +1))
Example #11
0
 def tensor1siteok(self, aϕ, O):
     for center in range(aϕ.size):
         ϕ = CanonicalMPS(aϕ, center=center, normalize=True)
         for n in range(ϕ.size):
             #
             # Take an MPS Φ, construct a new state ψ = O1*ϕ with a local
             # operator on the 'n-th' site
             #
             ψ = mps.state.MPS(ϕ)
             ψ[n] = np.einsum('ij,ajb->aib', O, ψ[n])
             #
             # and make sure that the AntilinearForm provides the right tensor to
             # compute <ϕ|ψ> = <ϕ|O1|ϕ>
             #
             Odesired = expectation1(ϕ, O, n)
             LF = AntilinearForm(ϕ, ψ, center)
             Oestimate = np.einsum('aib,aib', ϕ[center].conj(),
                                   LF.tensor1site())
             self.assertAlmostEqual(Oestimate, Odesired)
             if n >= center:
                 self.assertTrue(almostIdentity(LF.L[center], +1))
             if n <= center:
                 self.assertTrue(almostIdentity(LF.R[center], +1))
Example #12
0
def wavefunction_product(ψ, ξ, conjugate=False, simplify=True, **kwdargs):
    """Implement a nonlinear transformation that multiplies two MPS, to
    create a new MPS with combined bond dimensions. In other words, act
    with the nonlinear transformation <s|ψξ> = ψ(s)ξ(s)|s> or
    <s|ψ*ξ> = ψ*(s)ξ(s)|s>
    
    Arguments
    ---------
    ψ, ξ      -- Two MPS or CanonicalMPS.
    conjugate -- Conjugate ψ or not.
    simplify  -- Simplify the state afterwards or not.
    kwdargs   -- Arguments to simplify() if simplify is True.
    
    Output
    ------
    mps       -- The MPS product ψξ or ψ*ξ.
    """
    def combine(A, B):
        # Combine both tensors
        a, d, b = A.shape
        c, d, e = B.shape
        if conjugate:
            A = A.conj()
        D = np.array([
            np.outer(A[:, i, :].flatten(), B[:, i, :].flatten())
            for i in range(d)
        ])
        D = np.einsum('iabce->acibe',
                      np.array(D).reshape(d, a, b, c,
                                          e)).reshape(a * c, d, b * e)
        return D

    out = MPS([combine(A, B) for A, B in zip(ψ, ξ)])
    if simplify:
        out = CanonicalMPS(out, center=0, **kwdargs)
        out, _, _ = mps.truncate.simplify(out, **kwdargs)
    return out