Esempio n. 1
0
def minimize_one_norm(
    ideal_matrix: np.ndarray,
    basis_matrices: List[np.ndarray],
    tol: float = 1.0e-8,
    initial_guess: Optional[np.ndarray] = None,
) -> np.ndarray:
    r"""
    Returns the list of real coefficients :math:`[x_0, x_1, \dots]`,
    which minimizes :math:`\sum_j |x_j|` with the contraint that
    the following representation of the input ``ideal_matrix`` holds:

    .. math::
        \text{ideal_matrix} = x_0 A_0 + x_1 A_1 + ...,

    where :math:`\{A_j\}` are the basis matrices, i.e., the elements of
    the input ``basis_matrices``.

    This function can be used to compute the optimal representation
    of an ideal superoperator (or Choi state) as a linear
    combination of real noisy superoperators (or Choi states).

    Args:
        ideal_matrix: The ideal matrix to represent.
        basis_matrices: The list of basis matrices.
        tol: The error tolerance for each matrix element
            of the represented matrix.
        initial_guess: Optional initial guess for the coefficients
            :math:`[x_0, x_1, \dots]`.

    Returns:
        The list of optimal coefficients :math:`[x_0, x_1, \dots]`.
    """

    # Map complex matrices to extended real matrices
    ideal_matrix_real = np.hstack(
        (np.real(ideal_matrix), np.imag(ideal_matrix)))
    basis_matrices_real = [
        np.hstack((np.real(mat), np.imag(mat))) for mat in basis_matrices
    ]

    # Express the representation constraint written in the docstring in the
    # form of a matrix multiplication applied to the x vector: A @ x == b.
    matrix_a = np.array([matrix_to_vector(mat)
                         for mat in basis_matrices_real]).T
    array_b = matrix_to_vector(ideal_matrix_real)

    constraint = LinearConstraint(matrix_a, lb=array_b - tol, ub=array_b + tol)

    def one_norm(x):
        return np.linalg.norm(x, 1)

    if initial_guess is None:
        initial_guess = np.zeros(len(basis_matrices))

    result = minimize(one_norm, x0=initial_guess, constraints=constraint)

    if not result.success:
        raise RuntimeError("The search for an optimal representation failed.")

    return result.x
Esempio n. 2
0
def test_kraus_to_super():
    """Tests the function on random channels acting on random states.
    Channels and states are non-physical, but this is irrelevant for the test.
    """
    for num_qubits in (1, 2, 3, 4, 5):
        d = 2**num_qubits
        fake_kraus_ops = [
            np.random.rand(d, d) + 1.0j * np.random.rand(d, d)
            for _ in range(7)
        ]
        super_op = kraus_to_super(fake_kraus_ops)
        fake_state = np.random.rand(d, d) + 1.0j * np.random.rand(d, d)
        result_with_kraus = sum(
            [k @ fake_state @ k.conj().T for k in fake_kraus_ops])
        result_with_super = vector_to_matrix(
            super_op @ matrix_to_vector(fake_state))
        assert np.allclose(result_with_kraus, result_with_super)
Esempio n. 3
0
def test_vector_to_matrix():
    for d in [1, 2, 3, 4]:
        vec = np.random.rand(d**2)
        assert vector_to_matrix(vec).shape == (d, d)
        assert (matrix_to_vector(vector_to_matrix(vec)) == vec).all
Esempio n. 4
0
def test_matrix_to_vector():
    for d in [1, 2, 3, 4]:
        mat = np.random.rand(d, d)
        assert matrix_to_vector(mat).shape == (d**2, )
        assert (vector_to_matrix(matrix_to_vector(mat)) == mat).all