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() * ξ))
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))
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}')
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))
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
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())
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), ψ