コード例 #1
0
    def test_partial_trace_16_by_16(self):
        """Test for 16-by-16 matrix."""
        test_input_mat = np.arange(1, 257).reshape(16, 16)
        res = partial_trace(test_input_mat, [1, 3], [2, 2, 2, 2])

        expected_res = np.array([
            [344, 348, 360, 364],
            [408, 412, 424, 428],
            [600, 604, 616, 620],
            [664, 668, 680, 684],
        ])

        bool_mat = np.isclose(expected_res, res)
        self.assertEqual(np.all(bool_mat), True)
コード例 #2
0
    def test_partial_trace_16_by_16_2(self):
        """Test for 16-by-16 matrix."""
        test_input_mat = np.arange(1, 257).reshape(16, 16)
        res = partial_trace(test_input_mat, [1, 2], [2, 2, 2, 2])

        expected_res = np.array([
            [412, 416, 420, 424],
            [476, 480, 484, 488],
            [540, 544, 548, 552],
            [604, 608, 612, 616],
        ])

        bool_mat = np.isclose(expected_res, res)
        self.assertEqual(np.all(bool_mat), True)
コード例 #3
0
    def test_partial_trace(self):
        """
        Standard call to partial_trace.

        By default, the partial_trace function takes the trace over the second
        subsystem.
        """
        test_input_mat = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12],
                                   [13, 14, 15, 16]])

        expected_res = np.array([[7, 11], [23, 27]])

        res = partial_trace(test_input_mat)

        bool_mat = np.isclose(expected_res, res)
        self.assertEqual(np.all(bool_mat), True)
コード例 #4
0
    def test_partial_trace_sys_int_dim_int_2(self):
        """
        Default second subsystem.

        By default, the partial_transpose function takes the trace over
        the second subsystem.
        """
        test_input_mat = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12],
                                   [13, 14, 15, 16]])

        expected_res = 34

        res = partial_trace(test_input_mat, 2, 1)

        bool_mat = np.isclose(expected_res, res)
        self.assertEqual(np.all(bool_mat), True)
コード例 #5
0
    def test_partial_trace_sys(self):
        """
        Specify the `sys` argument.

        By specifying the `sys` argument, you can perform the partial trace
        the first subsystem instead:
        """
        test_input_mat = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12],
                                   [13, 14, 15, 16]])

        expected_res = np.array([[12, 14], [20, 22]])

        res = partial_trace(test_input_mat, 1)

        bool_mat = np.isclose(expected_res, res)
        self.assertEqual(np.all(bool_mat), True)
コード例 #6
0
def schmidt_rank(
    vec: np.ndarray, dim: Union[int, List[int], np.ndarray] = None
) -> float:
    r"""
    Compute the Schmidt rank.

    For complex Euclidean spaces :math:`\mathcal{X}` and :math:`\mathcal{Y}`, a
    pure state :math:`u \in \mathcal{X} \otimes \mathcal{Y}` possesses an
    expansion of the form:

    .. math::
        u = \sum_{i} \lambda_i v_i w_i

    where :math:`v_i \in \mathcal{X}` and :math:`w_i \in \mathcal{Y}` are
    orthonormal states.

    The Schmidt coefficients are calculated from

    .. math::
        A = \text{Tr}_{\mathcal{B}}(u^* u).

    The Schmidt rank is the number of non-zero eigenvalues of A. The Schmidt
    rank allows us to determine if a given state is entangled or separable.
    For instance:

        - If the Schmidt rank is 1: The state is separable
        - If the Schmidt rank > 1: The state is entangled.

    Compute the Schmidt rank of the vector `vec`, assumed to live in bipartite
    space, where both subsystems have dimension equal to `sqrt(len(vec))`.

    The dimension may be specified by the 1-by-2 vector `dim` and the rank in
    that case is determined as the number of Schmidt coefficients larger than
    `tol`.

    References:
        [1] Wikipedia: Schmidt rank
        https://en.wikipedia.org/wiki/Schmidt_decomposition#Schmidt_rank_and_entanglement

    :param vec: A bipartite vector to have its Schmidt rank computed.
    :param dim: A 1-by-2 vector.
    :return: The Schmidt rank of vector `vec`.
    """
    eps = np.finfo(float).eps
    slv = int(np.round(np.sqrt(len(vec))))

    if dim is None:
        dim = slv

    if isinstance(dim, int):
        dim = np.array([dim, len(vec) / dim])
        if np.abs(dim[1] - np.round(dim[1])) >= 2 * len(vec) * eps:
            raise ValueError(
                "Invalid: The value of `dim` must evenly divide "
                "`len(vec)`; please provide a `dim` array "
                "containing the dimensions of the subsystems"
            )
        dim[1] = np.round(dim[1])

    rho = vec.conj().T * vec
    rho_a = partial_trace(rho, 2)

    # Return the number of non-zero eigenvalues of the
    # matrix that traced out the second party's portion.
    return len(np.nonzero(np.linalg.eigvalsh(rho_a))[0])
コード例 #7
0
 def test_non_square_matrix_dim_2(self):
     """Matrix must be square for partial trace."""
     with self.assertRaises(ValueError):
         rho = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
         partial_trace(rho, 2, [2])
コード例 #8
0
 def test_invalid_sys_arg(self):
     """The `sys` argument must be either a list or int."""
     with self.assertRaises(ValueError):
         rho = np.array([[1 / 2, 0, 0, 1 / 2], [0, 0, 0, 0], [0, 0, 0, 0],
                         [1 / 2, 0, 0, 1 / 2]])
         partial_trace(rho, "invalid_input")