vprusso / toqito

|toqito> (Theory of Quantum Information Toolkit) in Python :snake:
https://toqito.readthedocs.io/en/latest/
MIT License
138 stars 54 forks source link

Feature: Vectorization and unvectorization for Hermitian matrix #243

Open vprusso opened 8 months ago

vprusso commented 8 months ago

The ability to vectorize and unvectorize a Hermitian matrix will be useful when generating random PPT states.

Something like this following:

Vectorize:

def vectorize_hermitian_matrix(X):
    """
    Vectorize a Hermitian matrix by scaling the off-diagonal elements.

    Args:
    X (numpy.ndarray): A Hermitian matrix (square, symmetric, complex).

    Returns:
    numpy.ndarray: A vectorized form of the Hermitian matrix.
    """
    n = X.shape[0]
    sX = np.diag(np.diag(X)) + np.sqrt(2) * (np.real(np.triu(X, k=1)) + np.imag(np.tril(X, k=-1)))
    return sX.reshape(n**2, 1)

Unvectorize:

def unvectorize_hermitian_matrix(symX):
    """
    Unvectorize a vectorized Hermitian matrix to its original form.

    Args:
    symX (numpy.ndarray): A vectorized Hermitian matrix.

    Returns:
    numpy.ndarray: The original Hermitian matrix.
    """
    n = int(np.round(np.sqrt(len(symX))))
    tmpX = np.reshape(symX, (n, n))
    triX = (np.triu(tmpX, k=1) + 1j * np.tril(tmpX, k=-1)) / np.sqrt(2)
    return np.diag(np.diag(tmpX)) + triX + triX.conj().T

The unvectorize function is the inverse of the vectorize one, so a set of tests that capture that, like the following, would be helpful:

def test_hermitian_vectorization():
    # Test case 1: 2x2 Hermitian matrix
    X1 = np.array([[1+1j, 2+2j], [2-2j, 3+3j]])
    sv1 = vectorize_hermitian_matrix(X1)
    X1_reconstructed = unvectorize_hermitian_matrix(sv1)
    assert np.allclose(X1, X1_reconstructed), "Test case 1 failed"

    # Test case 2: 3x3 Hermitian matrix
    X2 = np.array([[1+0j, 2-1j, 3+4j], [2+1j, 5+0j, 6-2j], [3-4j, 6+2j, 7+0j]])
    sv2 = vectorize_hermitian_matrix(X2)
    X2_reconstructed = unvectorize_hermitian_matrix(sv2)
    assert np.allclose(X2, X2_reconstructed), "Test case 2 failed"

    print("All test cases passed!")

# Run the tests
test_hermitian_vectorization()

This would most likely live in matrix_ops/ with the corresponding tests in test_matrix_ops/.

purva-thakre commented 8 months ago

When attempting to fix this issue, it might also be better to use the function's docstrings to distinguish between the functions described in the issue's description vs. the vec and unvec functions already in matrix_ops/.

https://github.com/vprusso/toqito/blob/5070ca5ccd18b91507892f307d311825fb39ed11/toqito/matrix_ops/unvec.py#L1

https://github.com/vprusso/toqito/blob/5070ca5ccd18b91507892f307d311825fb39ed11/toqito/matrix_ops/vec.py#L1

vprusso commented 8 months ago

Good point. I'll make sure to accentuate that vectorize_hermitian_matrix is specialized for Hermitian matrices and includes scaling to account for the complex structure of such matrices. In contrast, the vec operation is a general matrix-to-vector transformation without any modifications to the matrix elements.