Beispiel #1
0
def gf_cost_func_v1(B, AL, AR):
    Bn = tn.Node(B, axis_names=["p", "L", "R"])
    ALn = tn.Node(AL, axis_names=["p", "L", "R"])
    ARn = tn.Node(AR, axis_names=["p", "L", "R"])

    ALn_c = tn.conj(ALn)
    ALn["L"] ^ ALn_c["L"]
    ALn["R"] ^ ALn_c["R"]
    PLn = tn.contract_between(ALn,
                              ALn_c,
                              output_edge_order=[ALn_c["p"], ALn["p"]],
                              axis_names=["p_in", "p_out"])

    ARn_c = tn.conj(ARn)
    ARn["L"] ^ ARn_c["L"]
    ARn["R"] ^ ARn_c["R"]
    PRn = tn.contract_between(ARn,
                              ARn_c,
                              output_edge_order=[ARn_c["p"], ARn["p"]],
                              axis_names=["p_in", "p_out"])

    PLRn = tn.Node(PLn.get_tensor() + PRn.get_tensor(),
                   axis_names=["p_in", "p_out"])

    Bn_c = tn.conj(Bn)
    Bn["L"] ^ Bn_c["L"]
    Bn["R"] ^ Bn_c["R"]
    Bn["p"] ^ PLRn["p_in"]
    Bn_c["p"] ^ PLRn["p_out"]
    res = Bn @ PLRn @ Bn_c
    return res.get_tensor()
Beispiel #2
0
def test_split_node_qr_unitarity(dtype, num_charges):
    np.random.seed(10)
    a = tn.Node(get_square_matrix(50, num_charges, dtype=dtype),
                backend='symmetric')
    q, r = tn.split_node_qr(a, [a[0]], [a[1]])
    r[0] | q[1]
    qbar = tn.conj(q)
    q[1] ^ qbar[1]
    u1 = q @ qbar
    qbar[0] ^ q[0]
    u2 = qbar @ q
    blocks, _, shapes = _find_diagonal_sparse_blocks(u1.tensor.flat_charges,
                                                     u1.tensor.flat_flows,
                                                     len(u1.tensor._order[0]))
    for n, block in enumerate(blocks):
        np.testing.assert_almost_equal(
            np.reshape(u1.tensor.data[block], shapes[:, n]),
            np.eye(N=shapes[0, n], M=shapes[1, n]))

    blocks, _, shapes = _find_diagonal_sparse_blocks(u2.tensor.flat_charges,
                                                     u2.tensor.flat_flows,
                                                     len(u2.tensor._order[0]))
    for n, block in enumerate(blocks):
        np.testing.assert_almost_equal(
            np.reshape(u2.tensor.data[block], shapes[:, n]),
            np.eye(N=shapes[0, n], M=shapes[1, n]))
def test_conj(backend):
  if backend == "pytorch":
    pytest.skip("Complex numbers currently not supported in PyTorch")

  a = tn.Node(np.random.rand(3, 3) + 1j * np.random.rand(3, 3), backend=backend)
  abar = tn.conj(a)
  np.testing.assert_allclose(abar.tensor, a.backend.conj(a.tensor))
def get_Cost_mpsII(gamma_beta):

    Cost = 0
    Sz = tn.Node(g.get_Z())

    for i in range(n):

        g_b = tn.FiniteMPS(gamma_beta.nodes)
        g_b.apply_one_site_gate(Sz, i)

        C = exp.exp_MPS(g_b, gamma_beta)
        C = np.real(C)
        C = h[i] * C
        Cost = Cost + C

    SzSz = np.tensordot(g.get_Z(), g.get_Z(), axes=0)
    SzSz = tn.Node(SzSz)

    for i in range(n - 1):

        for j in range((n - 1), i, -1):

            g_b = gamma_beta.nodes
            g_bcon = [tn.conj(g_b[i]) for i in range(n)]

            for k in range(n):

                if (k == i):

                    g_b[k][1] ^ SzSz[0]
                    g_bcon[k][1] ^ SzSz[1]

                elif (k == j):

                    g_b[k][1] ^ SzSz[2]
                    g_bcon[k][1] ^ SzSz[3]

                else:

                    g_bcon[k][1] ^ g_b[k][1]

                if (k == (n - 1)):

                    g_bcon[k][2] ^ g_bcon[0][0]
                    g_b[k][2] ^ g_b[0][0]

                else:

                    g_bcon[k][2] ^ g_bcon[k + 1][0]
                    g_b[k][2] ^ g_b[k + 1][0]

            C = tn.contractors.greedy((g_bcon + [SzSz] + g_b))
            C = C.tensor
            C = np.real(C.item())
            C = J[i, j] * C
            Cost = Cost + C
            del g_b, g_bcon

    return Cost
Beispiel #5
0
    def _ev_mps(self, obs_nodes, wires):
        r"""Expectation value of observables on specified wires using a MPS representation.

         Args:
            obs_nodes (Sequence[tn.Node]): the observables as TensorNetwork Nodes
            wires (Sequence[Sequence[int]]): measured subsystems for each observable
         Returns:
            complex: expectation value :math:`\expect{A} = \bra{\psi}A\ket{\psi}`
        """
        if any(len(wires_seq) > 2 for wires_seq in wires):
            raise NotImplementedError(
                "Multi-wire measurement only supported for nearest-neighbour wire pairs."
            )
        if len(obs_nodes) == 1 and len(wires[0]) == 1:
            # TODO: can measure multiple local expectation values at once,
            # but this would require change of `expval` behaviour and
            # refactor of `execute` logic from parent class
            expval = self.mps.measure_local_operator(obs_nodes, wires[0])[0]
        else:
            conj_nodes = [tn.conj(node) for node in self.mps.nodes]
            meas_wires = []
            # connect measured bra and ket nodes with observables
            for obs_node, wire_seq in zip(obs_nodes, wires):
                if len(wire_seq) == 2 and abs(wire_seq[0] - wire_seq[1]) > 1:
                    raise NotImplementedError(
                        "Multi-wire measurement only supported for nearest-neighbour wire pairs."
                    )
                offset = len(wire_seq)
                for idx, wire in enumerate(wire_seq):
                    tn.connect(conj_nodes[wire][1], obs_node[idx])
                    tn.connect(obs_node[offset + idx], self.mps.nodes[wire][1])
                meas_wires.extend(wire_seq)
            for wire in range(self.num_wires):
                # connect unmeasured ket nodes with bra nodes
                if wire not in meas_wires:
                    tn.connect(conj_nodes[wire][1], self.mps.nodes[wire][1])
                # connect local nodes of MPS (not connected by default in tn)
                if wire != self.num_wires - 1:
                    tn.connect(self.mps.nodes[wire][2], self.mps.nodes[wire + 1][0])
                    tn.connect(conj_nodes[wire][2], conj_nodes[wire + 1][0])

            # contract MPS bonds first
            bra_node = conj_nodes[0]
            ket_node = self.mps.nodes[0]
            for wire in range(self.num_wires - 1):
                bra_node = tn.contract_between(bra_node, conj_nodes[wire + 1])
                ket_node = tn.contract_between(ket_node, self.mps.nodes[wire + 1])
            # contract observables into ket
            for obs_node in obs_nodes:
                ket_node = tn.contract_between(obs_node, ket_node)
            # contract bra into observables/ket
            expval_node = tn.contract_between(bra_node, ket_node)
            # remove dangling singleton edges
            expval = self._squeeze(expval_node.tensor)
        return expval
def test_split_node_rq_unitarity_complex(backend):
    if backend == "pytorch":
        pytest.skip("Complex numbers currently not supported in PyTorch")
    if backend == "jax":
        pytest.skip("Complex QR crashes jax")

    a = tn.Node(np.random.rand(3, 3) + 1j * np.random.rand(3, 3),
                backend=backend)
    _, q = tn.split_node_rq(a, [a[0]], [a[1]])
    n1 = tn.Node(q.tensor, backend=backend)
    n2 = tn.conj(q)
    n1[1] ^ n2[1]
    u1 = tn.contract_between(n1, n2)
    n1 = tn.Node(q.tensor, backend=backend)
    n2 = tn.conj(q)
    n2[0] ^ n1[0]
    u2 = tn.contract_between(n1, n2)

    np.testing.assert_almost_equal(u1.tensor, np.eye(3))
    np.testing.assert_almost_equal(u2.tensor, np.eye(3))
Beispiel #7
0
def inner(B1, B2, stateL, stateR):
    B1n = tn.Node(B1, axis_names=["p", "L", "R"])
    B2nc = tn.conj(tn.Node(B2, axis_names=["p", "L", "R"]))
    ln = tn.Node(np.asarray(stateL.l[0]), axis_names=["B", "T"])
    rn = tn.Node(np.asarray(stateR.r[0]), axis_names=["T", "B"])
    B1n["p"] ^ B2nc["p"]
    B1n["L"] ^ ln["T"]
    B2nc["L"] ^ ln["B"]
    B1n["R"] ^ rn["T"]
    B2nc["R"] ^ rn["B"]
    return (ln @ B1n @ rn @ B2nc).get_tensor()
Beispiel #8
0
def test_conj(dtype, num_charges):
    np.random.seed(10)
    a = tn.Node(get_random((6, 7, 8, 9, 10),
                           num_charges=num_charges,
                           dtype=dtype),
                backend='symmetric')
    abar = tn.conj(a)
    np.testing.assert_allclose(abar.tensor.data, a.backend.conj(a.tensor.data))
    assert np.all([
        charge_equal(abar.tensor._charges[n], a.tensor._charges[n])
        for n in range(len(a.tensor._charges))
    ])
Beispiel #9
0
def test_split_node_qr_unitarity_float(backend):
    a = tn.Node(np.random.rand(3, 3), backend=backend)
    q, r = tn.split_node_qr(a, [a[0]], [a[1]])
    q[1] | r[0]
    qbar = tn.conj(q)
    q[1] ^ qbar[1]
    u1 = q @ qbar
    qbar[0] ^ q[0]
    u2 = qbar @ q

    np.testing.assert_almost_equal(u1.tensor, np.eye(3))
    np.testing.assert_almost_equal(u2.tensor, np.eye(3))
def test_split_node_rq_unitarity_float(backend):
    a = tn.Node(np.random.rand(3, 3), backend=backend)
    _, q = tn.split_node_rq(a, [a[0]], [a[1]])
    n1 = tn.Node(q.tensor, backend=backend)
    n2 = tn.conj(q)
    n1[1] ^ n2[1]
    u1 = tn.contract_between(n1, n2)
    n1 = tn.Node(q.tensor, backend=backend)
    n2 = tn.Node(q.tensor, backend=backend)
    n2[0] ^ n1[0]
    u2 = tn.contract_between(n1, n2)

    np.testing.assert_almost_equal(u1.tensor, np.eye(3))
    np.testing.assert_almost_equal(u2.tensor, np.eye(3))
Beispiel #11
0
 def _shift_position_right(self, pos):
     self.renvs = self.renvs[:-(pos - self.pos)]
     while self.pos < pos:
         self.psi.position(self.pos + 1)
         nodes = [
             self.lenvs[-1], self.psi.nodes[self.pos],
             self.H.nodes[self.pos],
             tn.conj(self.psi.nodes[self.pos])
         ]
         L = tn.ncon(nodes, [(1, 3, 5), (1, 2, -1), (3, 2, 4, -2),
                             (5, 4, -3)],
                     backend=self.backend)
         L.set_name('left_env_{}'.format(self.pos + 1))
         self.lenvs.append(L)
         self.pos += 1
Beispiel #12
0
 def _shift_position_left(self, pos):
     self.lenvs = self.lenvs[0:pos + 1]
     while self.pos > pos:
         self.psi.position(self.pos)
         nodes = [
             self.renvs[-1], self.psi.nodes[self.pos + 1],
             self.H.nodes[self.pos + 1],
             tn.conj(self.psi.nodes[self.pos + 1])
         ]
         R = tn.ncon(nodes, [(1, 3, 5), (-1, 2, 1), (-2, 2, 4, 3),
                             (-3, 4, 5)],
                     backend=self.backend)
         R.set_name('right_env_{}'.format(self.pos + 1))
         self.renvs.append(R)
         self.pos -= 1
Beispiel #13
0
    def _build_left_envs(self, lpos):
        L = tn.Node(np.array([[[1]]]), backend=self.backend, name='left_env_0')
        lenvs = [L]
        for i in range(lpos):
            self.psi.postion(i + 1)
            nodes = [
                L, self.psi.nodes[i], self.H.nodes[i],
                tn.conj(self.psi.nodes[i])
            ]
            L = tn.ncon(nodes, [(1, 3, 5), (1, 2, -1), (3, 2, 4, -2),
                                (5, 4, -3)],
                        backend=self.backend)
            L.set_name('left_env_{}'.format(i + 1))
            lenvs.append(L)

        return lenvs
Beispiel #14
0
    def _ev_exact(self, obs_nodes, obs_wires):
        r"""Expectation value of observables on specified wires using an exact representation.

        Args:
           obs_nodes (Sequence[tn.Node]): the observables as TensorNetwork Nodes
           obs_wires (Sequence[Wires]): measured wires for each observable

        Returns:
           complex: expectation value :math:`\expect{A} = \bra{\psi}A\ket{\psi}`
        """
        self._contract_premeasurement_network()
        ket = self._contracted_state_node
        bra = tn.conj(ket, name="Bra")

        all_device_wires = Wires(range(self.num_wires))
        meas_device_wires = []
        # For wires which are measured, add edges between
        # the ket node, the observable nodes, and the bra node
        for obs_node, wires in zip(obs_nodes, obs_wires):

            # translate to consecutive wire labels used by device
            device_wires = self.map_wires(wires)

            meas_device_wires.append(device_wires)
            for idx, l in enumerate(device_wires.labels):
                # Use convention that the indices of a tensor are ordered like
                # [output_idx1, output_idx2, ..., input_idx1, input_idx2, ...]
                output_idx = idx
                input_idx = len(device_wires) + idx
                tn.connect(obs_node[input_idx], ket[l])  # A|psi>
                tn.connect(bra[l], obs_node[output_idx])  # <psi|A

        meas_device_wires = Wires(meas_device_wires)

        # unmeasured wires are contracted directly between bra and ket
        unmeasured_device_wires = Wires.unique_wires(
            [all_device_wires, meas_device_wires])
        for w in unmeasured_device_wires.labels:
            tn.connect(bra[w], ket[w])

        # At this stage, all nodes are connected, and the contraction yields a
        # scalar value.
        ket_and_observable_node = ket
        for obs_node in obs_nodes:
            ket_and_observable_node = tn.contract_between(
                obs_node, ket_and_observable_node)
        return tn.contract_between(bra, ket_and_observable_node).tensor
Beispiel #15
0
    def energy(self):
        """
        Measure the energy expectation value by completing the network contraction.
        """
        E = self.renvs[-1]
        self.psi.position(self.pos)
        for i in [self.pos + 1, self.pos]:
            nodes = [
                E, self.psi.nodes[i], self.H.nodes[i],
                tn.conj(self.psi.nodes[i])
            ]
            E = tn.ncon(nodes, [(1, 3, 5), (-1, 2, 1), (-2, 2, 4, 3),
                                (-3, 4, 5)],
                        backend=self.backend)

        E = tn.ncon([self.lenvs[-1], E], [(1, 2, 3), (1, 2, 3)])
        return E.tensor.item()
def test_split_node_qr_unitarity_complex(backend):
  if backend == "pytorch":
    pytest.skip("Complex numbers currently not supported in PyTorch")
  if backend == "jax":
    pytest.skip("Complex QR crashes jax")

  a = tn.Node(np.random.rand(3, 3) + 1j * np.random.rand(3, 3), backend=backend)
  q, r = tn.split_node_qr(a, [a[0]], [a[1]])
  q[1] | r[0]
  qbar = tn.conj(q)
  q[1] ^ qbar[1]
  u1 = q @ qbar
  qbar[0] ^ q[0]
  u2 = qbar @ q

  np.testing.assert_almost_equal(u1.tensor, np.eye(3))
  np.testing.assert_almost_equal(u2.tensor, np.eye(3))
Beispiel #17
0
    def _build_right_envs(self, rpos):
        R = tn.Node(np.array([[[1]]]),
                    backend=self.backend,
                    name='right_env_{}'.format(self._len))
        renvs = [R]
        for i in reversed(range(rpos, self._len)):
            self.psi.position(i - 1)
            nodes = [
                R, self.psi.nodes[i], self.H.nodes[i],
                tn.conj(self.psi.nodes[i])
            ]
            R = tn.ncon(nodes, [(1, 3, 5), (-1, 2, 1), (-2, 2, 4, 3),
                                (-3, 4, 5)],
                        backend=self.backend)
            R.set_name('right_env_{}'.format(i))
            renvs.append(R)

        return renvs
    def ev(self, obs_nodes, wires):
        r"""Expectation value of observables on specified wires.

         Args:
            obs_nodes (Sequence[tn.Node]): the observables as tensornetwork Nodes
            wires (Sequence[Sequence[[int]]): measured subsystems for each observable
         Returns:
            float: expectation value :math:`\expect{A} = \bra{\psi}A\ket{\psi}`
        """

        all_wires = tuple(w for w in range(self.num_wires))
        ket = self._add_node(self._state, wires=all_wires, name="Ket")
        bra = self._add_node(tn.conj(ket), wires=all_wires, name="Bra")
        meas_wires = []
        # We need to build up <psi|A|psi> step-by-step.
        # For wires which are measured, we need to connect edges between
        # bra, obs_node, and ket.
        # For wires which are not measured, we need to connect edges between
        # bra and ket.
        # We use the convention that the indices of a tensor are ordered like
        # [output_idx1, output_idx2, ..., input_idx1, input_idx2, ...]
        for obs_node, obs_wires in zip(obs_nodes, wires):
            meas_wires.extend(obs_wires)
            for idx, w in enumerate(obs_wires):
                output_idx = idx
                input_idx = len(obs_wires) + idx
                self._add_edge(obs_node, input_idx, ket, w)  # A|psi>
                self._add_edge(bra, w, obs_node, output_idx)  # <psi|A
        for w in set(all_wires) - set(meas_wires):
            self._add_edge(bra, w, ket, w)  # |psi[w]|**2

        # At this stage, all nodes are connected, and the contraction yields a
        # scalar value.
        contracted_ket = ket
        for obs_node in obs_nodes:
            contracted_ket = tn.contract_between(obs_node, contracted_ket)
        expval = tn.contract_between(bra, contracted_ket).tensor
        if np.abs(expval.imag) > tolerance:
            warnings.warn(
                "Nonvanishing imaginary part {} in expectation value.".format(
                    expval.imag),
                RuntimeWarning,
            )
        return expval.real
Beispiel #19
0
    def _ev_exact(self, obs_nodes, wires):
        r"""Expectation value of observables on specified wires using an exact representation.

         Args:
            obs_nodes (Sequence[tn.Node]): the observables as TensorNetwork Nodes
            wires (Sequence[Sequence[int]]): measured subsystems for each observable

         Returns:
            complex: expectation value :math:`\expect{A} = \bra{\psi}A\ket{\psi}`
        """
        self._contract_premeasurement_network()
        ket = self._contracted_state_node
        bra = tn.conj(ket, name="Bra")

        all_wires = tuple(range(self.num_wires))
        meas_wires = []
        # For wires which are measured, add edges between
        # the ket node, the observable nodes, and the bra node
        for obs_node, obs_wires in zip(obs_nodes, wires):
            meas_wires.extend(obs_wires)
            for idx, w in enumerate(obs_wires):
                # Use convention that the indices of a tensor are ordered like
                # [output_idx1, output_idx2, ..., input_idx1, input_idx2, ...]
                output_idx = idx
                input_idx = len(obs_wires) + idx
                tn.connect(obs_node[input_idx], ket[w])  # A|psi>
                tn.connect(bra[w], obs_node[output_idx])  # <psi|A
        # unmeasured wires are contracted directly between bra and ket
        for w in set(all_wires) - set(meas_wires):
            tn.connect(bra[w], ket[w])

        # At this stage, all nodes are connected, and the contraction yields a
        # scalar value.
        ket_and_observable_node = ket
        for obs_node in obs_nodes:
            ket_and_observable_node = tn.contract_between(obs_node, ket_and_observable_node)
        return tn.contract_between(bra, ket_and_observable_node).tensor
Beispiel #20
0
def test_conj_of_node_without_backend_raises_error():
    node = np.random.rand(3, 3, 3)
    with pytest.raises(AttributeError):
        tn.conj(node)
Beispiel #21
0
def regauge_B_symm_linear_problem_v1(B, AL, AR, p=0):
    Bn = tn.Node(B, axis_names=["p", "L", "R"])
    ALn = tn.Node(AL, axis_names=["p", "L", "R"])
    ARn = tn.Node(AR * np.exp(-1.j * p), axis_names=["p", "L", "R"])

    D = B.shape[2]

    ALn_c = tn.conj(ALn)
    ALn["L"] ^ ALn_c["L"]
    ALn["R"] ^ ALn_c["R"]
    PLn = tn.contract_between(ALn,
                              ALn_c,
                              output_edge_order=[ALn_c["p"], ALn["p"]],
                              axis_names=["p_in", "p_out"])

    ARn_c = tn.conj(ARn)
    ARn["L"] ^ ARn_c["L"]
    ARn["R"] ^ ARn_c["R"]
    PRn = tn.contract_between(ARn,
                              ARn_c,
                              output_edge_order=[ARn_c["p"], ARn["p"]],
                              axis_names=["p_in", "p_out"])

    PLRn = tn.Node(PLn.get_tensor() + PRn.get_tensor(),
                   axis_names=["p_in", "p_out"])

    E = tn.CopyNode(2, D, dtype=B.dtype)

    PLRn["p_out"] ^ ALn_c["p"]
    MLn = tn.contract_between(
        PLRn,
        ALn_c,
        output_edge_order=[PLRn["p_in"], ALn_c["L"], ALn_c["R"]],
        axis_names=["p_in", "L_in", "L_out"])
    MLn = tn.contract_between(
        MLn,
        E,
        output_edge_order=[MLn["L_out"], E[0], MLn["p_in"], MLn["L_in"], E[1]],
        axis_names=["L_out", "R_out", "p_in", "L_in", "R_in"],
        allow_outer_product=True)

    PLRn["p_out"] ^ ARn_c["p"]
    MRn = tn.contract_between(
        PLRn,
        ARn_c,
        output_edge_order=[PLRn["p_in"], ARn_c["L"], ARn_c["R"]],
        axis_names=["p_in", "R_out", "R_in"])
    MRn = tn.contract_between(
        MRn,
        E,
        output_edge_order=[E[0], MRn["R_out"], MRn["p_in"], E[1], MRn["R_in"]],
        axis_names=["L_out", "R_out", "p_in", "L_in", "R_in"],
        allow_outer_product=True)

    MLRn = tn.Node(MLn.get_tensor() - MRn.get_tensor(),
                   axis_names=["L_out", "R_out", "p_in", "L_in", "R_in"])

    MLRn["p_in"] ^ Bn["p"]
    MLRn["L_in"] ^ Bn["L"]
    MLRn["R_in"] ^ Bn["R"]
    target_n = tn.contract_between(
        MLRn, Bn, output_edge_order=[MLRn["L_out"], MLRn["R_out"]])
    target_vec = target_n.get_tensor().ravel()

    ARn["p"] ^ MLRn["p_in"]
    ARn["R"] ^ MLRn["R_in"]

    bigM_Rn = tn.contract_between(ARn,
                                  MLRn,
                                  output_edge_order=[
                                      MLRn["L_out"], MLRn["R_out"],
                                      MLRn["L_in"], ARn["L"]
                                  ])

    ALn["p"] ^ MLRn["p_in"]
    ALn["L"] ^ MLRn["L_in"]

    bigM_Ln = tn.contract_between(ALn,
                                  MLRn,
                                  output_edge_order=[
                                      MLRn["L_out"], MLRn["R_out"], ALn["R"],
                                      MLRn["R_in"]
                                  ])

    bigMn = tn.Node(bigM_Rn.get_tensor() - bigM_Ln.get_tensor(),
                    axis_names=["L_out", "R_out", "L_in", "R_in"])
    mat = bigMn.get_tensor().reshape((D**2, D**2))

    return mat, target_vec
Beispiel #22
0
def binary_mera_energy(hamiltonian, state, isometry, disentangler):
  """Computes the energy using a layer of uniform binary MERA.

  Args:
    hamiltonian: The hamiltonian (rank-6 tensor) defined at the bottom of the
      MERA layer.
    state: The 3-site reduced state (rank-6 tensor) defined at the top of the
      MERA layer.
    isometry: The isometry tensor (rank 3) of the binary MERA.
    disentangler: The disentangler tensor (rank 4) of the binary MERA.

  Returns:
    The energy.
  """
  backend = "jax"

  out = []
  for dirn in ('left', 'right'):
    iso_l = tensornetwork.Node(isometry, backend=backend)
    iso_c = tensornetwork.Node(isometry, backend=backend)
    iso_r = tensornetwork.Node(isometry, backend=backend)

    iso_l_con = tensornetwork.conj(iso_l)
    iso_c_con = tensornetwork.conj(iso_c)
    iso_r_con = tensornetwork.conj(iso_r)

    op = tensornetwork.Node(hamiltonian, backend=backend)
    rho = tensornetwork.Node(state, backend=backend)

    un_l = tensornetwork.Node(disentangler, backend=backend)
    un_l_con = tensornetwork.conj(un_l)

    un_r = tensornetwork.Node(disentangler, backend=backend)
    un_r_con = tensornetwork.conj(un_r)

    tensornetwork.connect(iso_l[2], rho[0])
    tensornetwork.connect(iso_c[2], rho[1])
    tensornetwork.connect(iso_r[2], rho[2])

    tensornetwork.connect(iso_l[0], iso_l_con[0])
    tensornetwork.connect(iso_l[1], un_l[2])
    tensornetwork.connect(iso_c[0], un_l[3])
    tensornetwork.connect(iso_c[1], un_r[2])
    tensornetwork.connect(iso_r[0], un_r[3])
    tensornetwork.connect(iso_r[1], iso_r_con[1])

    if dirn == 'right':
      tensornetwork.connect(un_l[0], un_l_con[0])
      tensornetwork.connect(un_l[1], op[3])
      tensornetwork.connect(un_r[0], op[4])
      tensornetwork.connect(un_r[1], op[5])
      tensornetwork.connect(op[0], un_l_con[1])
      tensornetwork.connect(op[1], un_r_con[0])
      tensornetwork.connect(op[2], un_r_con[1])
    elif dirn == 'left':
      tensornetwork.connect(un_l[0], op[3])
      tensornetwork.connect(un_l[1], op[4])
      tensornetwork.connect(un_r[0], op[5])
      tensornetwork.connect(un_r[1], un_r_con[1])
      tensornetwork.connect(op[0], un_l_con[0])
      tensornetwork.connect(op[1], un_l_con[1])
      tensornetwork.connect(op[2], un_r_con[0])

    tensornetwork.connect(un_l_con[2], iso_l_con[1])
    tensornetwork.connect(un_l_con[3], iso_c_con[0])
    tensornetwork.connect(un_r_con[2], iso_c_con[1])
    tensornetwork.connect(un_r_con[3], iso_r_con[0])

    tensornetwork.connect(iso_l_con[2], rho[3])
    tensornetwork.connect(iso_c_con[2], rho[4])
    tensornetwork.connect(iso_r_con[2], rho[5])

    # FIXME: Check that this is giving us a good path!
    out.append(
        contractors.branch(tensornetwork.reachable(rho),
                           nbranch=2).get_tensor())

  return 0.5 * sum(out)
Beispiel #23
0
# solve order and contract network using opt_einsum
t0 = time.time()
T1 = oe.contract(*comb_list, [-1, -2, -3, -4, -5, -6], optimize='branch-all')
print("opt_einsum: time to contract = ", time.time() - t0)
"""
For a final comparison, we demonstrate how the example network can be solved
for the optimal order and contracted using the node/edge API with opt_einsum
"""

# define network nodes
backend = "numpy"
iso_l = tn.Node(w, backend=backend)
iso_c = tn.Node(w, backend=backend)
iso_r = tn.Node(w, backend=backend)
iso_l_con = tn.conj(iso_l)
iso_c_con = tn.conj(iso_c)
iso_r_con = tn.conj(iso_r)
op = tn.Node(ham, backend=backend)
un_l = tn.Node(u, backend=backend)
un_l_con = tn.conj(un_l)
un_r = tn.Node(u, backend=backend)
un_r_con = tn.conj(un_r)

# define network edges
tn.connect(iso_l[0], iso_l_con[0])
tn.connect(iso_l[1], un_l[2])
tn.connect(iso_c[0], un_l[3])
tn.connect(iso_c[1], un_r[2])
tn.connect(iso_r[0], un_r[3])
tn.connect(iso_r[1], iso_r_con[1])