Ejemplo n.º 1
0
    def test_product(self):
        np.random.seed(1034)
        for N in range(1, 10):
            ψ = np.random.rand(2**N, 2) - 0.5
            ψ = ψ[:, 0] + 1j * ψ[:, 1]
            ψ /= np.linalg.norm(ψ)
            ψmps = MPS.fromvector(ψ, [2] * N)
            ψ = ψmps.tovector()

            ξ = np.random.rand(2**N, 2) - 0.5
            ξ = ξ[:, 0] + 1j * ξ[:, 1]
            ξ /= np.linalg.norm(ξ)
            ξmps = MPS.fromvector(ξ, [2] * N)
            ξ = ξmps.tovector()

            ψξ = wavefunction_product(ψmps,
                                      ξmps,
                                      simplify=True,
                                      normalize=False).tovector()
            self.assertTrue(similar(ψξ, ψ * ξ))

            ψcξ = wavefunction_product(ψmps,
                                       ξmps,
                                       conjugate=True,
                                       simplify=False,
                                       normalize=False).tovector()
            self.assertTrue(similar(ψcξ, ψ.conj() * ξ))
Ejemplo n.º 2
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(ϕ)
             ψ[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))
Ejemplo n.º 3
0
 def apply(self, b):
     """Implement multiplication A @ b between an MPO 'A' and
     a Matrix Product State 'b'."""
     if isinstance(b, MPS):
         assert self.size == b.size
         log(f'Total error before applying MPO {b.error()}')
         err = 0.
         b = MPS([mpo_multiply_tensor(A, B) for A, B in zip(self._data, b)],
                 error=b.error())
         if self.simplify:
             b, err, _ = simplify(b,
                                  maxsweeps=self.maxsweeps,
                                  tolerance=self.tolerance,
                                  normalize=self.normalize,
                                  dimension=self.dimension)
         log(f'Total error after applying MPO {b.error()}, incremented by {err}'
             )
         return b
     else:
         raise Exception(f'Cannot multiply MPO with {b}')
Ejemplo n.º 4
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(ϕ)
             ψ[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))
Ejemplo n.º 5
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
Ejemplo n.º 6
0
def qft_flip(Ψmps):
    """Swap the qubits in the quantum register, to fix the reversal
    suffered during the quantum Fourier transform."""
    return MPS([np.moveaxis(A, [0, 1, 2], [2, 1, 0]) for A in reversed(Ψmps)],
               error=Ψmps.error())
Ejemplo n.º 7
0
 def gaussian_mps(N):
     x = np.linspace(-4, 4, 2**N + 1)[:-1]
     ψ = np.exp(-(x**2) / 2.)
     ψ /= np.linalg.norm(ψ)
     return MPS.fromvector(ψ, [2] * N), ψ