def test_split_node_names(backend):
    a = tn.Node(np.zeros((2, 3, 4, 5, 6)), backend=backend)
    left_edges = []
    for i in range(3):
        left_edges.append(a[i])
    right_edges = []
    for i in range(3, 5):
        right_edges.append(a[i])
    left, right, _ = tn.split_node(a,
                                   left_edges,
                                   right_edges,
                                   left_name='left',
                                   right_name='right',
                                   edge_name='edge')
    assert left.name == 'left'
    assert right.name == 'right'
    assert left.edges[-1].name == 'edge'
    assert right.edges[0].name == 'edge'
Example #2
0
def test_reachable_disconnected_1(backend):
  nodes = [tn.Node(np.random.rand(2, 2, 2), backend=backend) for _ in range(4)]
  nodes[0][1] ^ nodes[1][0]
  nodes[2][1] ^ nodes[3][0]
  assert set(tn.reachable([nodes[0], nodes[2]])) == set(nodes)

  assert set(tn.reachable([nodes[0]])) == {nodes[0], nodes[1]}
  assert set(tn.reachable([nodes[1]])) == {nodes[0], nodes[1]}
  assert set(tn.reachable([nodes[0], nodes[1]])) == {nodes[0], nodes[1]}

  assert set(tn.reachable([nodes[2]])) == {nodes[2], nodes[3]}
  assert set(tn.reachable([nodes[3]])) == {nodes[2], nodes[3]}
  assert set(tn.reachable([nodes[2], nodes[3]])) == {nodes[2], nodes[3]}

  assert set(tn.reachable([nodes[0], nodes[1], nodes[2]])) == set(nodes)
  assert set(tn.reachable([nodes[0], nodes[1], nodes[3]])) == set(nodes)
  assert set(tn.reachable([nodes[0], nodes[2], nodes[3]])) == set(nodes)
  assert set(tn.reachable([nodes[1], nodes[2], nodes[3]])) == set(nodes)
Example #3
0
def test_split_node_full_svd_names(backend):
  a = tn.Node(np.random.rand(10, 10), backend=backend)
  e1 = a[0]
  e2 = a[1]
  left, s, right, _, = tn.split_node_full_svd(
      a, [e1], [e2],
      left_name='left',
      middle_name='center',
      right_name='right',
      left_edge_name='left_edge',
      right_edge_name='right_edge')
  assert left.name == 'left'
  assert s.name == 'center'
  assert right.name == 'right'
  assert left.edges[-1].name == 'left_edge'
  assert s[0].name == 'left_edge'
  assert s[1].name == 'right_edge'
  assert right.edges[0].name == 'right_edge'
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))
Example #5
0
def test_split_node_rq(dtype, num_charges):
    np.random.seed(10)
    a = tn.Node(get_random((6, 7, 8, 9, 10), num_charges, dtype=dtype),
                backend='symmetric')
    left_edges = []
    for i in range(3):
        left_edges.append(a[i])
    right_edges = []
    for i in range(3, 5):
        right_edges.append(a[i])
    left, right = tn.split_node_rq(a, left_edges, right_edges)
    tn.check_correct([left, right])
    result = tn.contract(left[3])
    np.testing.assert_allclose(result.tensor.data, a.tensor.data)
    assert np.all([
        charge_equal(result.tensor._charges[n], a.tensor._charges[n])
        for n in range(len(a.tensor._charges))
    ])
Example #6
0
 def f(input_vec, blocks, rank, dim, bond_dim, label_len):
     mps, edges = create_MPS_labeled(blocks, rank, dim, bond_dim)
     data_tensor = []
     for p in tf.unstack(input_vec):
         data_tensor.append(tn.Node([1 - p, p]))
     edges.append(data_tensor[0][0] ^ mps[0][0])
     half_len = np.int(rank / 2)
     [
         edges.append(data_tensor[i][0] ^ mps[i][1])
         for i in range(1, half_len)
     ]
     [edges.append(data_tensor[i-label_len][0] ^ mps[i][1]) \
          for i in range(half_len + label_len, rank + label_len)]
     for k in reversed(range(len(edges))):
         A = tn.contract(edges[k])
     #result = tf.math.log(A.tensor)
     result = A.tensor - tf.math.reduce_max(A.tensor)
     return result
Example #7
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
Example #8
0
def test_split_node_full_svd_names(num_charges):
    np.random.seed(10)
    a = tn.Node(get_random((10, 10), num_charges=num_charges),
                backend='symmetric')
    e1 = a[0]
    e2 = a[1]
    left, s, right, _, = tn.split_node_full_svd(a, [e1], [e2],
                                                left_name='left',
                                                middle_name='center',
                                                right_name='right',
                                                left_edge_name='left_edge',
                                                right_edge_name='right_edge')
    assert left.name == 'left'
    assert s.name == 'center'
    assert right.name == 'right'
    assert left.edges[-1].name == 'left_edge'
    assert s[0].name == 'left_edge'
    assert s[1].name == 'right_edge'
    assert right.edges[0].name == 'right_edge'
Example #9
0
def renyiEntropy(n,
                 w,
                 h,
                 M,
                 randOption,
                 theta,
                 phi,
                 estimateFunc,
                 arguments,
                 filename,
                 d=2,
                 excludeIndices=[]):
    start = datetime.now()
    avg = 0
    N = w * h
    for m in range(M * 2**N * 10):
        ops = [
            getNonUnitaryRandomOps(d, randOption, theta, phi, vecsNum=n)
            for i in range(N)
        ]
        for ind in excludeIndices:
            ops[ind] = [tn.Node(np.eye(d, dtype=complex)) for i in range(n)]
        estimation = 1
        for i in range(n):
            expectation = wrapper(estimateFunc,
                                  arguments + [[op[i] for op in ops]])
            estimation *= expectation
            if estimation > 40:
                b = 1
        avg += estimation
        if m % M == M - 1:
            with open(
                    filename + '_n_' + str(n) + '_w_' + str(w) + '_h_' +
                    str(h) + '_' + randOption + '_M_' + str(M) + '_m_' +
                    str(m), 'wb') as f:
                pickle.dump(avg, f)
                avg = 0
        for op in ops:
            bops.removeState(op)
    end = datetime.now()
    with open(filename + '_time_N_' + str(N) + '_M_' + str(M), 'wb') as f:
        pickle.dump((end - start).total_seconds(), f)
Example #10
0
def test_split_node_qr_names(num_charges):
    np.random.seed(10)
    a = tn.Node(get_random((2, 3, 4, 5, 6), num_charges=num_charges),
                backend='symmetric')
    left_edges = []
    for i in range(3):
        left_edges.append(a[i])
    right_edges = []
    for i in range(3, 5):
        right_edges.append(a[i])
    left, right = tn.split_node_qr(a,
                                   left_edges,
                                   right_edges,
                                   left_name='left',
                                   right_name='right',
                                   edge_name='edge')
    assert left.name == 'left'
    assert right.name == 'right'
    assert left.edges[-1].name == 'edge'
    assert right.edges[0].name == 'edge'
Example #11
0
def test_copy_method_with_trace_edges(backend):
  a = tn.Node(np.ones([3, 3, 3, 3, 3]), name='mynode', 
              axis_names=['a', 'b', 'c', 'd', 'e'], 
              backend=backend)
  a.add_edge(tn.Edge(a, 0, name='named_edge1'), 0)
  a.add_edge(tn.Edge(a, 1, name='named_edge2'), 1)
  a.add_edge(tn.Edge(a, 2, name='named_edge3'), 2)
  a.add_edge(tn.Edge(a, 3, name='named_edge4'), 3)
  a.add_edge(tn.Edge(a, 4, name='named_edge5'), 4)
  a[0] ^ a[3]
  a[1] ^ a[4]
  b = a.copy()
  assert a.name == b.name
  assert a.shape == b.shape
  assert a.axis_names == b.axis_names
  for i in range(len(a.edges)):
    assert a[i].name == b[i].name
  assert b[0] is b[3]
  assert b[1] is b[4]
  np.testing.assert_allclose(a.tensor, b.tensor)
Example #12
0
def test_constructor(backend):
    psi_tensor = np.random.rand(2, 2)
    psi_node = tn.Node(psi_tensor, backend=backend)

    op = qu.quantum_constructor([psi_node[0]], [psi_node[1]])
    assert not op.is_scalar()
    assert not op.is_vector()
    assert not op.is_adjoint_vector()
    assert len(op.out_edges) == 1
    assert len(op.in_edges) == 1
    assert op.out_edges[0] is psi_node[0]
    assert op.in_edges[0] is psi_node[1]

    op = qu.quantum_constructor([psi_node[0], psi_node[1]], [])
    assert not op.is_scalar()
    assert op.is_vector()
    assert not op.is_adjoint_vector()
    assert len(op.out_edges) == 2
    assert len(op.in_edges) == 0
    assert op.out_edges[0] is psi_node[0]
    assert op.out_edges[1] is psi_node[1]

    op = qu.quantum_constructor([], [psi_node[0], psi_node[1]])
    assert not op.is_scalar()
    assert not op.is_vector()
    assert op.is_adjoint_vector()
    assert len(op.out_edges) == 0
    assert len(op.in_edges) == 2
    assert op.in_edges[0] is psi_node[0]
    assert op.in_edges[1] is psi_node[1]

    with pytest.raises(ValueError):
        op = qu.quantum_constructor([], [], [psi_node])

    _ = psi_node[0] ^ psi_node[1]
    op = qu.quantum_constructor([], [], [psi_node])
    assert op.is_scalar()
    assert not op.is_vector()
    assert not op.is_adjoint_vector()
    assert len(op.out_edges) == 0
    assert len(op.in_edges) == 0
Example #13
0
    def __gradient__(self, input_idx: int) -> np.ndarray:
        """
        Calculates the gradient of the inner-product <MPS|input_tensor>
        with respect to the bond tensor.

        :param input_tensor: tensor formed from the input vector
        :return: d<MPS|input_tensor>/d{bond}
        """
        proj = self.__projection__(input_idx)
        bond = self.mps.get_contracted_bond()

        leftmost = self.__leftmost__()

        if leftmost:
            proj[0]['in'] ^ bond['in1']
            proj[1]['in'] ^ bond['in2']
            proj[2]['in'] ^ bond['r']
        else:
            proj[0]['in'] ^ bond['l']
            proj[1]['in'] ^ bond['in1']
            proj[2]['in'] ^ bond['in2']
            proj[3]['in'] ^ bond['r']

        mps_prod = tn.contractors.auto(proj + [bond]) - tn.Node(self.Ys[:, input_idx])
        mps_prod.add_axis_names(['out'])
        proj2 = tn.replicate_nodes(proj)

        if leftmost:
            in1_edge = proj2[0]['in']
            in2_edge = proj2[1]['in']
            r_edge = proj2[2]['in']
            edge_order = [r_edge, in1_edge, in2_edge]
        else:
            l_edge = proj2[0]['in']
            in1_edge = proj2[1]['in']
            in2_edge = proj2[2]['in']
            r_edge = proj2[3]['in']
            edge_order = [l_edge, r_edge, in1_edge, in2_edge]

        edge_order.append(mps_prod['out'])
        return tn.contractors.auto([mps_prod] + proj2, output_edge_order=edge_order).tensor
Example #14
0
def localVecsEstimate(psi: List[tn.Node],
                      vs: List[List[np.array]],
                      half='left'):
    vs = np.round(vs, 10)
    n = len(vs)
    result = 1
    for copy in range(n):
        if half == 'left':
            NA = len(vs[0])
            curr = bops.multiContraction(psi[NA], psi[NA], '12', '12*')
            sites = range(NA - 1, -1, -1)
        elif half == 'right':
            NA = len(psi) - len(vs[0])
            curr = bops.multiContraction(psi[len(psi) - NA - 1],
                                         psi[len(psi) - NA - 1], '01', '01*')
            sites = range(NA, len(psi))
        psiCopy = bops.copyState(psi)
        for alpha in sites:
            toEstimate = np.outer(vs[copy][alpha - NA],
                                  np.conj(vs[np.mod(copy + 1, n)][alpha - NA]))
            psiCopy[alpha] = bops.permute(bops.multiContraction(psiCopy[alpha], tn.Node(toEstimate), \
                                                   '1', '1'), [0, 2, 1])
            if half == 'left':
                curr = bops.multiContraction(bops.multiContraction(
                    psiCopy[alpha], curr, '2', '0', cleanOr2=True),
                                             psi[alpha],
                                             '12',
                                             '12*',
                                             cleanOr1=True)
            elif half == 'right':
                curr = bops.multiContraction(bops.multiContraction(
                    curr, psiCopy[alpha], '0', '0', cleanOr2=True),
                                             psi[alpha],
                                             '01',
                                             '01*',
                                             cleanOr1=True)
            # psiCopy = bops.shiftWorkingSite(psiCopy, alpha, '<<')
        result *= np.trace(curr.tensor)
        tn.remove_node(curr)
        bops.removeState(psiCopy)
    return result
Example #15
0
def wire_network(tensor_list, give_dense=False):
    """
    Convert list of tensor cores into fully wired network of TN Nodes

    If give_dense=True, the wired network is contracted together and a 
    single (large) tensor is returned
    """
    num_cores = len(tensor_list)
    assert valid_formatting(tensor_list)

    # Wire together all internal edges connecting cores
    node_list = [tn.Node(core) for core in tensor_list]
    for i in range(num_cores):
        for j in range(i + 1, num_cores):
            node_list[i][j] ^ node_list[j][i]

    if give_dense:
        edge_order = [node[i] for i, node in enumerate(node_list)]
        return contract_network(node_list, edge_order=edge_order)
    else:
        return node_list
Example #16
0
    def _add_node(self, A, wires, name="UnnamedNode"):
        """Adds a node to the underlying tensor network.

        The node is also added to ``self._nodes`` for bookkeeping.

        Args:
            A (array): numerical data values for the operator (i.e., matrix form)
            wires (list[int]): wires that this operator acts on
            name (str): optional name for the node

        Returns:
            tn.Node: the newly created node
        """
        name = "{}{}".format(name, tuple(w for w in wires))
        if isinstance(A, tn.Node):
            A.set_name(name)
            node = A
        else:
            node = tn.Node(A, name=name)
        self._nodes.append(node)
        return node
Example #17
0
    def apply_consecutive_gates(self, i, gate):
        """
        Applies a two-qubit gate to the i'th and the (i+1)'th qubit. 
        The gate must be either a 4x4 matrix or a 2x2x2x2 tensor.
        
        Comment: In tn.split_node, it may make sense to use max_truncation_err
                 option instead of max_singular_values option, in case there
                 was a mistake in my note.

        Args:
            i(int): Index of the qubit.
            gate(np.array): 4x4 matrix or 2x2x2x2 tensor.
        """
        gate = normalize_gate(gate)
        j = (i + 1) % self.n_qubits

        # get dimension of inner bond between i and i+1
        r = self.right_edges(i)[0].dimension

        gate = tn.Node(gate)

        # connect i and i+1 to the gate
        self.out_edge(i) ^ gate[0]
        self.out_edge(j) ^ gate[1]

        # Get non-dangling edges for each side
        left_edges = self.left_edges(i) + [gate[2]]
        right_edges = self.right_edges(j) + [gate[3]]

        # Contract edges
        C = (self.nodes[i] @ self.nodes[j])
        D = C @ gate

        self.nodes[i], self.nodes[j], _ = tn.split_node(
            D,
            left_edges=left_edges,
            right_edges=right_edges,
            max_singular_values=4 * r,
            left_name=str(i),
            right_name=str(j))
Example #18
0
def computational_basis_state(state: int, dim: int = 2) -> tn.Node:
    """Returns a computational basis state.

    Args:
        state: Integer which labels the state from the set {0, 1, ..., d - 1}.
        dim: Dimension of the qudit. Default is two for qubits.

    Raises:
        ValueError: If state < 0, dim < 0, or state >= dim.
    """
    if state < 0:
        raise ValueError(f"Argument state should be positive but is {state}.")

    if dim < 0:
        raise ValueError(f"Argument dim should be positive but is {dim}.")

    if state >= dim:
        raise ValueError(
            f"Requires state < dim but state = {state} and dim = {dim}.")
    vector = np.zeros((dim, ))
    vector[state] = 1.
    return tn.Node(vector, name=f"|{state}>")
Example #19
0
def put_mps(tensors):
    '''
    returns
        a set of tensor cores connected in MPS
        a set of connected edges
    '''
    mps = []
    for i in range(len(tensors)):
        mps.append(
            tn.Node(tensors[i].detach().clone().squeeze(), backend=backend))

    if len(tensors) == 1:
        return mps, []

    connected_edges = []
    conn = mps[0][-1] ^ mps[1][0]
    if len(mps) > 2:
        for k in range(1, len(tensors) - 1):
            conn = mps[k][-1] ^ mps[k + 1][0]
            connected_edges.append(conn)

    return mps, connected_edges
def test_split_node(dtype, num_charges):
    np.random.seed(111)
    a = tn.Node(get_zeros((2, 3, 4, 5, 6), num_charges, dtype),
                backend='symmetric')

    left_edges = []
    for i in range(3):
        left_edges.append(a[i])
    right_edges = []
    for i in range(3, 5):
        right_edges.append(a[i])
    left, right, _ = tn.split_node(a, left_edges, right_edges)
    tn.check_correct({left, right})
    actual = left @ right
    np.testing.assert_allclose(actual.tensor.shape, (2, 3, 4, 5, 6))
    np.testing.assert_allclose(a.tensor.shape, (2, 3, 4, 5, 6))
    np.testing.assert_allclose(left.tensor.data, 0)
    np.testing.assert_allclose(right.tensor.data, 0)
    assert np.all([
        charge_equal(a.tensor._charges[n], actual.tensor._charges[n])
        for n in range(len(a.tensor._charges))
    ])
Example #21
0
def getPurity(l):
    with open('results/toricBoundaries', 'rb') as f:
        [upRow, downRow, leftRow, rightRow, openA, openB] = pickle.load(f)

    upRow = tn.Node(upRow)
    downRow = tn.Node(downRow)
    leftRow = tn.Node(leftRow)
    rightRow = tn.Node(rightRow)
    openA = tn.Node(openA)
    openB = tn.Node(openB)
    [cUp, dUp, te] = bops.svdTruncation(upRow, [0, 1], [2, 3], '>>')
    [cDown, dDown, te] = bops.svdTruncation(downRow, [0, 1], [2, 3], '>>')

    norm = applyLocalOperators(cUp, dUp, cDown, dDown, leftRow, rightRow, A, B,
                               l, [tn.Node(np.eye(d)) for i in range(l * 4)])
    leftRow = bops.multNode(leftRow, 1 / norm)
    res = applyLocalOperators(cUp, dUp, cDown, dDown, leftRow, rightRow, A, B,
                              l,
                              [tn.Node(ru.proj0Tensor) for i in range(l * 4)])
    # The density matrix is constructed of blocks of ones of size N and normalized by res.
    # Squaring it adds a factor of N * res.
    N = 2**l
    purity = N * res
    return purity
Example #22
0
def apply_circuit(circ, qubits=None, init_state=None):
    if 'tn' not in globals():
        raise ImportError('Please install tensornetwork first.')

    all_nodes, left_edges, right_edges, N = circuit_network(circ)
    if qubits is not None:
        assert len(qubits) == N
    else:
        qubits = list(range(N))
    if init_state is None:
        init_state_nodes = [
            tn.Node(np.array([1, 0], dtype=complex)) for i in range(N)
        ]
        init_state_edges = [init_state_nodes[i][0] for i in range(N)]
    else:
        init_state_nodes, init_state_edges = init_state

    all_nodes.extend(init_state_nodes)
    qubit_edges = [left_edges[q] for q in qubits]
    for i, q in enumerate(qubits):
        tn.connect(right_edges[i], init_state_edges[q])
    result = tn.contractors.optimal(all_nodes, output_edge_order=qubit_edges)
    return result.tensor.reshape(-1)
Example #23
0
def rgate(seed: Optional[int] = None, angle_scale: float = 1.0):
    """Returns the random single qubit gate described in
    https://arxiv.org/abs/2002.07730.
    
    Args:
        seed: Seed for random number generator.
        angle_scale: Floating point value to scale angles by. Default 1.
    """
    if seed:
        np.random.seed(seed)

    # Get the random parameters
    theta, alpha, phi = np.random.rand(3) * 2 * np.pi
    mx = np.sin(alpha) * np.cos(phi)
    my = np.sin(alpha) * np.sin(phi)
    mz = np.cos(alpha)

    theta *= angle_scale

    # Get the unitary
    unitary = expm(-1j * theta *
                   (mx * _xmatrix + my * _ymatrix * mz * _zmatrix))
    return tn.Node(unitary)
Example #24
0
def computational_basis_projector(state: int, dim: int = 2) -> tn.Node:
    """Returns a projector onto a computational basis state which acts on a
    single qudit of dimension dim.

    Args:
        state: Basis state to project onto.
        dim: Dimension of the qudit. Default is two for qubits.

    Raises:
        ValueError: If state < 0, dim < 0, or state >= dim.
    """
    if state < 0:
        raise ValueError(f"Argument state should be positive but is {state}.")

    if dim < 0:
        raise ValueError(f"Argument dim should be positive but is {dim}.")

    if state >= dim:
        raise ValueError(
            f"Requires state < dim but state = {state} and dim = {dim}.")
    projector = np.zeros((dim, dim))
    projector[state, state] = 1.
    return tn.Node(projector, name=f"|{state}><{state}|")
Example #25
0
    def translate(self, alpha: float, max_singular_values: int, num_threads: int) -> bool:
        B = self.Xs.shape[1]
        num_per_thd = int(B / num_threads)
        bond = self.mps.get_contracted_bond()
        bond_shape = bond.shape
        leftmost = self.__leftmost__()

        if leftmost:
            grads = np.zeros((num_threads, bond_shape[0], bond_shape[1], bond_shape[2], bond_shape[3]))
        else:
            grads = np.zeros((num_threads, bond_shape[0], bond_shape[1], bond_shape[2], bond_shape[3], bond_shape[4]))

        iter_barrier = threading.Barrier(num_threads + 1)

        def thread_main(ithread):
            grad = np.zeros(bond_shape)
            for i in np.arange(ithread * num_per_thd, (ithread + 1) * num_per_thd):
                grad = grad + self.__gradient__(i)
            grads[ithread] = grad
            iter_barrier.wait()

        worker_threads = [threading.Thread(target=thread_main, args=(it,)) for it in range(num_threads)]
        for t in worker_threads:
            t.start()
        iter_barrier.wait()

        for t in worker_threads:
            t.join()

        # Here, all gradients have been calculated
        total_grad = np.sum(grads, axis=0)
        new_bond = tn.Node(bond.tensor - alpha * total_grad)
        self.__add_newbond_names__(new_bond)
        self.mps.update_bond(new_bond, max_singular_values)
        for i in range(B):
            self.__precompute_projections__(i)
        return self.mps.output_idx < len(self.mps.tensors) - 2
Example #26
0
def haar_random_unitary(nqudits: int = 2,
                        qudit_dimension: int = 2,
                        name: str = "Haar",
                        seed: Optional[int] = None) -> tn.Node:
    """Returns a Haar random unitary matrix of dimension 2**nqubits using
    the algorithm in https://arxiv.org/abs/math-ph/0609050.

    Args:
        nqudits: Number of qudits the unitary acts on.
        qudit_dimension: Dimension of each qudit.
        name: Name for the gate.
        seed: Seed for random number generator.

    Notes:
        See also
            http://qutip.org/docs/4.3/apidoc/functions.html#qutip.random_objects
        which was used as a template for this function.
    """
    # Seed for random number generator
    rng = np.random.RandomState(seed)

    # Generate an N x N matrix of complex standard normal random variables
    units = np.array([1, 1j])
    shape = (qudit_dimension**nqudits, qudit_dimension**nqudits)
    mat = np.sum(rng.randn(*(shape + (2, ))) * units, axis=-1) / np.sqrt(2)

    # Do the QR decomposition
    qmat, rmat = np.linalg.qr(mat)

    # Create a diagonal matrix by rescaling the diagonal elements of rmat
    diag = np.diag(rmat).copy()
    diag /= np.abs(diag)

    # Reshape the tensor
    tensor = qmat * diag
    tensor = np.reshape(tensor, newshape=[qudit_dimension] * 2 * nqudits)
    return tn.Node(tensor, name=name)
Example #27
0
def randomMeasurement(psi, startInd, endInd):
    d = psi[0].tensor.shape[1]
    res = [-1] * (endInd - startInd)
    psiCopy = bops.copyState(psi)
    for k in [len(psiCopy) - 1 - i for i in range(len(psiCopy) - startInd - 1)]:
        psiCopy = bops.shiftWorkingSite(psiCopy, k, '<<')
    for i in range(startInd, endInd):
        rho = bops.multiContraction(psiCopy[i], psiCopy[i], '02', '02*')
        measurement = np.random.uniform(low=0, high=1)
        covered = 0
        for s in range(len(rho.tensor)):
            if covered < measurement < covered + rho.tensor[s, s]:
                res[i - startInd] = s
                break
            covered += rho.tensor[s, s]
        projectorTensor = np.zeros((d, d), dtype=complex)
        projectorTensor[res[i - startInd], res[i - startInd]] = 1
        projector = tn.Node(projectorTensor, backend=None)
        bops.applySingleSiteOp(psiCopy, projector, i)
        psiCopy = bops.shiftWorkingSite(psiCopy, i, '>>')
        psiCopy[i + 1].tensor /= np.sqrt(bops.getOverlap(psiCopy, psiCopy))
        tn.remove_node(rho)
    bops.removeState(psiCopy)
    return res
Example #28
0
def test_real_physics(dtype, num_charges):
    # Calcuate the expected value in numpy
    t1 = get_random_symmetric((20, 20, 20, 20), [False, False, False, False],
                              num_charges,
                              dtype=dtype)
    t2 = get_random_symmetric((20, 20, 20), [True, False, True],
                              num_charges,
                              dtype=dtype)
    t3 = get_random_symmetric((20, 20, 20), [True, True, False],
                              num_charges,
                              dtype=dtype)

    t1_dense = t1.todense()
    t2_dense = t2.todense()
    t3_dense = t3.todense()
    adense = tn.Node(t1_dense, name="T", backend='numpy')
    bdense = tn.Node(t2_dense, name="A", backend='numpy')
    cdense = tn.Node(t3_dense, name="B", backend='numpy')

    e1 = tn.connect(adense[2], bdense[0], "edge")
    e2 = tn.connect(cdense[0], adense[3], "edge2")
    e3 = tn.connect(bdense[1], cdense[1], "edge3")
    node_result = tn.contract(e1)
    node_result = tn.contract(e2)
    final_result = tn.contract(e3)

    # Build the network
    a = tn.Node(t1, name="T", backend='symmetric')
    b = tn.Node(t2, name="A", backend='symmetric')
    c = tn.Node(t3, name="B", backend='symmetric')
    e1 = tn.connect(a[2], b[0], "edge")
    e2 = tn.connect(c[0], a[3], "edge2")
    e3 = tn.connect(b[1], c[1], "edge3")
    tn.check_correct(tn.reachable(a))
    node_result = tn.contract(e1)
    tn.check_correct(tn.reachable(node_result))
    node_result = tn.contract(e2)
    tn.check_correct(tn.reachable(node_result))
    val = tn.contract(e3)
    tn.check_correct(tn.reachable(val))
    np.testing.assert_allclose(val.tensor.todense(), final_result.tensor)
Example #29
0
def test_split_node_qr_orig_shape(backend):
    n1 = tn.Node(np.random.rand(3, 4, 5), backend=backend)
    tn.split_node_qr(n1, [n1[0], n1[2]], [n1[1]])
    np.testing.assert_allclose(n1.shape, (3, 4, 5))
Example #30
0
def test_switch_backend_raises_error(backend):
    a = tn.Node(np.random.rand(3, 3, 3))
    a.backend = BaseBackend()
    with pytest.raises(NotImplementedError):
        tn.switch_backend({a}, backend)