Example #1
0
def is_idempotent(mat: np.ndarray,
                  rtol: float = 1e-05,
                  atol: float = 1e-8) -> bool:
    r"""
    Check if matrix is the idempotent matrix [WikIdempotent]_.

    An *idempotent matrix* is a square matrix, which, when multiplied by itself, yields itself.
    That is, the matrix :math:`A` is idempotent if and only if :math:`A^2 = A`.

    Examples
    ==========

    The following is an example of a :math:`2 x 2` idempotent matrix:

    .. math::
        A = \begin{pmatrix}
            3 & -6 \\
            1 & -2
        \end{pmatrix}

    >>> from toqito.matrix_props import is_idempotent
    >>> import numpy as np
    >>> mat = np.array([[3, -6], [1, -2]])
    >>> is_idempotent(mat)

    Alternatively, the following matrix

    .. math::
        B = \begin{pmatrix}
                1 & 2 & 3 \\
                4 & 5 & 6 \\
                7 & 8 & 9
            \end{pmatrix}

    is not idempotent.

    >>> from toqito.matrix_props import is_idempotent
    >>> import numpy as np
    >>> mat = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    >>> is_idempotent(mat)
    False

    References
    ==========
    .. [WikIdempotent] Wikipedia: Idempotent matrix
        https://en.wikipedia.org/wiki/Idempotent_matrix

    :param mat: Matrix to check.
    :param rtol: The relative tolerance parameter (default 1e-05).
    :param atol: The absolute tolerance parameter (default 1e-08).
    :return: Return :code:`True` if matrix is the idempotent matrix, and
            :code:`False` otherwise.
    """
    if not is_square(mat):
        return False
    return np.allclose(mat, mat @ mat, rtol=rtol, atol=atol)
Example #2
0
def is_psd(mat: np.ndarray, tol: float = 1e-8) -> bool:
    r"""
    Check if matrix is positive semidefinite (PSD) [WikPSD]_.

    Examples
    ==========

    Consider the following matrix

    .. math::
        A = \begin{pmatrix}
                1 & -1 \\
                -1 & 1
            \end{pmatrix}

    our function indicates that this is indeed a positive semidefinite matrix.

    >>> from toqito.matrix_props import is_psd
    >>> import numpy as np
    >>> A = np.array([[1, -1], [-1, 1]])
    >>> is_psd(A)
    True

    Alternatively, the following example matrix :math:`B` defined as

    .. math::
        B = \begin{pmatrix}
                -1 & -1 \\
                -1 & -1
            \end{pmatrix}

    is not positive semidefinite.

    >>> from toqito.matrix_props import is_psd
    >>> import numpy as np
    >>> B = np.array([[-1, -1], [-1, -1]])
    >>> is_psd(B)
    False

    References
    ==========
    .. [WikPSD] Wikipedia: Definiteness of a matrix.
        https://en.wikipedia.org/wiki/Definiteness_of_a_matrix

    :param mat: Matrix to check.
    :param tol: Tolerance for numerical accuracy.
    :return: Return True if matrix is PSD, and False otherwise.
    """
    if not is_square(mat):
        return False
    return np.all(np.linalg.eigvalsh(mat) > -tol)
Example #3
0
def is_diagonal(mat: np.ndarray) -> bool:
    r"""
    Determine if a matrix is diagonal [WikDiag]_.

    A matrix is diagonal if the matrix is square and if the diagonal of the matrix is non-zero,
    while the off-diagonal elements are all zero.

    The following is an example of a 3-by-3 diagonal matrix:

    .. math::
        \begin{equation}
            \begin{pmatrix}
                1 & 0 & 0 \\
                0 & 2 & 0 \\
                0 & 0 & 3
            \end{pmatrix}
        \end{equation}

    This quick implementation is given by Daniel F. from StackOverflow in [SODIA]_.

    Examples
    ==========

    Consider the following diagonal matrix:

    .. math::
        A = \begin{pmatrix}
                1 & 0 \\
                0 & 1
            \end{pmatrix}.

    Our function indicates that this is indeed a diagonal matrix:

    >>> from toqito.matrix_props import is_diagonal
    >>> import numpy as np
    >>> A = np.array([[1, 0], [0, 1]])
    >>> is_diagonal(A)
    True

    Alternatively, the following example matrix

    .. math::
        B = \begin{pmatrix}
                1 & 2 \\
                3 & 4
            \end{pmatrix}

    is not diagonal, as shown using :code:`toqito`.

    >>> from toqito.matrix_props import is_diagonal
    >>> import numpy as np
    >>> B = np.array([[1, 2], [3, 4]])
    >>> is_diagonal(B)
    False

    References
    ==========
    .. [WikDiag] Wikipedia: Diagonal matrix
        https://en.wikipedia.org/wiki/Diagonal_matrix

    .. [SODIA] StackOverflow post
        https://stackoverflow.com/questions/43884189/

    :param mat: The matrix to check.
    :return: Returns :code:`True` if the matrix is diagonal
             and :code:`False` otherwise.
    """
    if not is_square(mat):
        return False
    i, j = mat.shape
    test = mat.reshape(-1)[:-1].reshape(i - 1, j + 1)
    return ~np.any(test[:, 1:])
Example #4
0
def is_hermitian(mat: np.ndarray,
                 rtol: float = 1e-05,
                 atol: float = 1e-08) -> bool:
    r"""
    Check if matrix is Hermitian [WikHerm]_.

    A Hermitian matrix is a complex square matrix that is equal to its own conjugate transpose.

    Examples
    ==========

    Consider the following matrix:

    .. math::
        A = \begin{pmatrix}
                2 & 2 +1j & 4 \\
                2 - 1j & 3 & 1j \\
                4 & -1j & 1
            \end{pmatrix}

    our function indicates that this is indeed a Hermitian matrix as it holds that

    .. math::
        A = A^*.

    >>> from toqito.matrix_props import is_hermitian
    >>> import numpy as np
    >>> mat = np.array([[2, 2 + 1j, 4], [2 - 1j, 3, 1j], [4, -1j, 1]])
    >>> is_hermitian(mat)
    True

    Alternatively, the following example matrix :math:`B` defined as

    .. math::
        B = \begin{pmatrix}
                1 & 2 & 3 \\
                4 & 5 & 6 \\
                7 & 8 & 9
            \end{pmatrix}

    is not Hermitian.

    >>> from toqito.matrix_props import is_hermitian
    >>> import numpy as np
    >>> mat = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    >>> is_hermitian(mat)
    False

    References
    ==========
    .. [WikHerm] Wikipedia: Hermitian matrix.
        https://en.wikipedia.org/wiki/Hermitian_matrix

    :param mat: Matrix to check.
    :param rtol: The relative tolerance parameter (default 1e-05).
    :param atol: The absolute tolerance parameter (default 1e-08).
    :return: Return True if matrix is Hermitian, and False otherwise.
    """
    if not is_square(mat):
        return False
    return np.allclose(mat, mat.conj().T, rtol=rtol, atol=atol)
Example #5
0
def test_is_square():
    """Test that square matrix returns True."""
    mat = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    np.testing.assert_equal(is_square(mat), True)
Example #6
0
def test_is_not_square():
    """Test that non-square matrix returns False."""
    mat = np.array([[1, 2, 3], [4, 5, 6]])
    np.testing.assert_equal(is_square(mat), False)
Example #7
0
def is_projection(mat: np.ndarray, rtol: float = 1e-05, atol: float = 1e-08) -> bool:
    r"""
    Check if matrix is a projection matrix [WikProj]_.

    A matrix is a projection matrix if it is positive semidefinite (PSD) and if

    .. math::
        \begin{equation}
            X^2 = X
        \end{equation}

    where :math:`X` is the matrix in question.

    Examples
    ==========

    Consider the following matrix

    .. math::
        A = \begin{pmatrix}
                0 & 1 \\
                0 & 1
            \end{pmatrix}

    our function indicates that this is indeed a projection matrix.

    >>> from toqito.matrix_props import is_projection
    >>> import numpy as np
    >>> A = np.array([[0, 1], [0, 1]])
    >>> is_projection(A)
    True

    Alternatively, the following example matrix :math:`B` defined as

    .. math::
        B = \begin{pmatrix}
                -1 & -1 \\
                -1 & -1
            \end{pmatrix}

    is not positive definite.

    >>> from toqito.matrix_props import is_projection
    >>> import numpy as np
    >>> B = np.array([[-1, -1], [-1, -1]])
    >>> is_projection(B)
    False

    References
    ==========
    .. [WikProj] Wikipedia: Projection matrix.
        https://en.wikipedia.org/wiki/Projection_matrix

    :param mat: Matrix to check.
    :param rtol: The relative tolerance parameter (default 1e-05).
    :param atol: The absolute tolerance parameter (default 1e-08).
    :return: Return :code:`True` if matrix is a projection matrix, and :code:`False` otherwise.
    """
    if not is_square(mat):
        return False

    if not is_positive_semidefinite(mat):
        return False
    return np.allclose(np.linalg.matrix_power(mat, 2), mat, rtol=rtol, atol=atol)
Example #8
0
def is_unitary(mat: np.ndarray,
               rtol: float = 1e-05,
               atol: float = 1e-08) -> bool:
    r"""
    Check if matrix is unitary [WikUnitary]_.

    A matrix is unitary if its inverse is equal to its conjugate transpose.

    Alternatively, a complex square matrix :math:`U` is unitary if its conjugate transpose
    :math:`U^*` is also its inverse, that is, if

    .. math::
        \begin{equation}
            U^* U = U U^* = \mathbb{I},
        \end{equation}

    where :math:`\mathbb{I}` is the identity matrix.

    Examples
    ==========

    Consider the following matrix

    .. math::
        X = \begin{pmatrix}
            0 & 1 \\
            1 & 0
            \end{pmatrix}

    our function indicates that this is indeed a unitary matrix.

    >>> from toqito.matrix_props import is_unitary
    >>> import numpy as np
    >>> A = np.array([[0, 1], [1, 0]])
    >>> is_unitary(A)
    True

    We may also use the `random_unitary` function from `toqito`, and can verify that a randomly
    generated matrix is unitary

    >>> from toqito.matrix_props import is_unitary
    >>> from toqito.random import random_unitary
    >>> mat = random_unitary(2)
    >>> is_unitary(mat)
    True

    Alternatively, the following example matrix :math:`B` defined as

    .. math::
        B = \begin{pmatrix}
            1 & 0 \\
            1 & 1
            \end{pmatrix}

    is not unitary.

    >>> from toqito.matrix_props import is_unitary
    >>> import numpy as np
    >>> B = np.array([[1, 0], [1, 1]])
    >>> is_unitary(B)
    False

    References
    ==========
    .. [WikUnitary] Wikipedia: Unitary matrix.
        https://en.wikipedia.org/wiki/Unitary_matrix

    :param mat: Matrix to check.
    :param rtol: The relative tolerance parameter (default 1e-05).
    :param atol: The absolute tolerance parameter (default 1e-08).
    :return: Return :code:`True` if matrix is unitary, and :code:`False` otherwise.
    """
    if not is_square(mat):
        return False

    uc_u_mat = mat.conj().T @ mat
    u_uc_mat = mat @ mat.conj().T
    id_mat = np.eye(len(mat))

    # If U^* * U = I U * U^*, the matrix "U" is unitary.
    return np.allclose(uc_u_mat, id_mat, rtol=rtol, atol=atol) and np.allclose(
        u_uc_mat, id_mat, rtol=rtol, atol=atol)
Example #9
0
def test_is_square_invalid():
    """Input must be a matrix."""
    with np.testing.assert_raises(ValueError):
        is_square(np.array([-1, 1]))
Example #10
0
def is_symmetric(mat: np.ndarray,
                 rtol: float = 1e-05,
                 atol: float = 1e-08) -> bool:
    r"""
    Determine if a matrix is symmetric [WikSym]_.

    The following 3x3 matrix is an example of a symmetric matrix:

    .. math::

        \begin{pmatrix}
            1 & 7 & 3 \\
            7 & 4 & -5 \\
            3 &-5 & 6
        \end{pmatrix}

    Examples
    ==========

    Consider the following matrix

    .. math::
        A = \begin{pmatrix}
                1 & 7 & 3 \\
                7 & 4 & -5 \\
                3 & -5 & 6
            \end{pmatrix}

    our function indicates that this is indeed a symmetric matrix.

    >>> from toqito.matrix_props import is_symmetric
    >>> import numpy as np
    >>> A = np.array([[1, 7, 3], [7, 4, -5], [3, -5, 6]])
    >>> is_symmetric(A)
    True

    Alternatively, the following example matrix :math:`B` defined as

    .. math::
        B = \begin{pmatrix}
                1 & 2 \\
                4 & 5
            \end{pmatrix}

    is not symmetric.

    >>> from toqito.matrix_props import is_symmetric
    >>> import numpy as np
    >>> B = np.array([[1, 2], [3, 4]])
    >>> is_symmetric(B)
    False

    References
    ==========
    .. [WikSym] Wikipedia: Symmetric matrix
        https://en.wikipedia.org/wiki/Symmetric_matrix

    :param mat: The matrix to check.
    :param rtol: The relative tolerance parameter (default 1e-05).
    :param atol: The absolute tolerance parameter (default 1e-08).
    :return: Returns :code:`True` if the matrix is symmetric and :code:`False` otherwise.
    """
    if not is_square(mat):
        return False
    return np.allclose(mat, mat.T, rtol=rtol, atol=atol)
Example #11
0
def is_normal(mat: np.ndarray,
              rtol: float = 1e-05,
              atol: float = 1e-08) -> bool:
    r"""
    Determine if a matrix is normal [WikNormal]_.

    A matrix is normal if it commutes with its adjoint

    .. math::
        \begin{equation}
            [X, X^*] = 0,
        \end{equation}

    or, equivalently if

    .. math::
        \begin{equation}
            X^* X = X X^*
        \end{equation}.

    Examples
    ==========

    Consider the following matrix

    .. math::
        A = \begin{pmatrix}
                1 & 0 & 0 & 0 \\
                0 & 1 & 0 & 0 \\
                0 & 0 & 1 & 0 \\
                0 & 0 & 0 & 1
            \end{pmatrix}

    our function indicates that this is indeed a normal matrix.

    >>> from toqito.matrix_props import is_normal
    >>> import numpy as np
    >>> A = np.identity(4)
    >>> is_normal(A)
    True

    Alternatively, the following example matrix :math:`B` defined as

    .. math::
        B = \begin{pmatrix}
                1 & 2 & 3 \\
                4 & 5 & 6 \\
                7 & 8 & 9
            \end{pmatrix}

    is not normal.

    >>> from toqito.matrix_props import is_normal
    >>> import numpy as np
    >>> B = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    >>> is_normal(B)
    False

    References
    ==========
    .. [WikNormal] Wikipedia: Normal matrix.
        https://en.wikipedia.org/wiki/Normal_matrix

    :param mat: The matrix to check.
    :param rtol: The relative tolerance parameter (default 1e-05).
    :param atol: The absolute tolerance parameter (default 1e-08).
    :return: Returns :code:`True` if the matrix is normal and :code:`False` otherwise.
    """
    if not is_square(mat):
        return False
    return np.allclose(mat @ mat.conj().T,
                       mat.conj().T @ mat,
                       rtol=rtol,
                       atol=atol)
Example #12
0
def dual_channel(
    phi_op: Union[np.ndarray, List[np.ndarray], List[List[np.ndarray]]],
    dims: List[int] = None
) -> Union[np.ndarray, List[List[np.ndarray]]]:
    r"""
    Compute the dual of a map (quantum channel) [WatDChan18]_.

    The map can be represented as a Choi matrix, with optional specification of input
    and output dimensions. In this case the Choi matrix of the dual channel is
    returned, obtained by swapping input and output (see :func:`toqito.perms.swap`),
    and complex conjugating all elements.

    The map can also be represented as a list of Kraus operators.
    A list of lists, each containing two elements, corresponds to the families
    of operators :math:`\{(A_a, B_a)\}` representing the map

    .. math::
        \Phi(X) = \sum_a A_a X B^*_a.

    The dual map is obtained by taking the Hermitian adjoint of each operator.
    If :code:`phi_op` is given as a one-dimensional list, :math:`\{A_a\}`,
    it is interpreted as the completely positive map

    .. math::
        \Phi(X) = \sum_a A_a X A^*_a.

    References
    ==========
    .. [WatDChan18] Watrous, John.
        The theory of quantum information.
        Section: Representations and characterizations of channels.
        Cambridge University Press, 2018.

    :param phi_op: A superoperator. It should be provided either as a Choi matrix,
                   or as a (1d or 2d) list of numpy arrays whose entries are its Kraus operators.
    :param dims: Dimension of the input and output systems, for Choi matrix representation.
                 If :code:`None`, try to infer them from :code:`phi_op.shape`.
    :return: The map dual to :code:`phi_op`, in the same representation.
    """
    # If phi_op is a list, assume it contains couples of Kraus operators
    # and take the Hermitian conjugate.
    if isinstance(phi_op, list):
        if isinstance(phi_op[0], list):
            return [[a.conj().T for a in x] for x in phi_op]
        if isinstance(phi_op[0], np.ndarray):
            return [a.conj().T for a in phi_op]

    # If phi_op is a `ndarray`, assume it is a Choi matrix.
    if isinstance(phi_op, np.ndarray):
        if len(phi_op.shape) == 2:
            if not is_square(phi_op):
                raise ValueError("Invalid: `phi_op` is not a valid Choi matrix (not square).")
            if dims is None:
                sqr = np.sqrt(phi_op.shape[0])
                if sqr.is_integer():
                    dims = [int(round(sqr))] * 2
                else:
                    raise ValueError(
                        "The dimensions `dims` of the input and output should be specified."
                        )
            return swap(phi_op.conj(), dim=dims)
    raise ValueError(
        "Invalid: The variable `phi_op` must either be a list of "
        "Kraus operators or as a Choi matrix."
    )
Example #13
0
def is_identity(mat: np.ndarray,
                rtol: float = 1e-05,
                atol: float = 1e-8) -> bool:
    r"""
    Check if matrix is the identity matrix [WikIdentity]_.

    For dimension :math:`n`, the :math:`n \times n` identity matrix is defined as

    .. math::
        I_n =
        \begin{pmatrix}
            1 & 0 & 0 & \ldots & 0 \\
            0 & 1 & 0 & \ldots & 0 \\
            0 & 0 & 1 & \ldots & 0 \\
            \vdots & \vdots & \vdots & \ddots & \vdots \\
            0 & 0 & 0 & \ldots & 1
        \end{pmatrix}.

    Examples
    ==========

    Consider the following matrix:

    .. math::
        A = \begin{pmatrix}
                1 & 0 & 0 \\
                0 & 1 & 0 \\
                0 & 0 & 1
            \end{pmatrix}

    our function indicates that this is indeed the identity matrix of dimension
    3.

    >>> from toqito.matrix_props import is_identity
    >>> import numpy as np
    >>> mat = np.eye(3)
    >>> is_identity(mat)
    True

    Alternatively, the following example matrix :math:`B` defined as

    .. math::
        B = \begin{pmatrix}
                1 & 2 & 3 \\
                4 & 5 & 6 \\
                7 & 8 & 9
            \end{pmatrix}

    is not an identity matrix.

    >>> from toqito.matrix_props import is_identity
    >>> import numpy as np
    >>> mat = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    >>> is_identity(mat)
    False

    References
    ==========
    .. [WikIdentity] Wikipedia: Identity matrix
        https://en.wikipedia.org/wiki/Identity_matrix

    :param mat: Matrix to check.
    :param rtol: The relative tolerance parameter (default 1e-05).
    :param atol: The absolute tolerance parameter (default 1e-08).
    :return: Return :code:`True` if matrix is the identity matrix, and
            :code:`False` otherwise.
    """
    if not is_square(mat):
        return False
    id_mat = np.eye(len(mat))
    return np.allclose(mat, id_mat, rtol=rtol, atol=atol)