Пример #1
0
def von_neumann_entropy(
    state: 'cirq.QUANTUM_STATE_LIKE',
    qid_shape: Optional[Tuple[int, ...]] = None,
    validate: bool = True,
    atol: float = 1e-7,
) -> float:
    """Calculates the von Neumann entropy of a quantum state in bits.

    If `state` is a square matrix, it is assumed to be a density matrix rather
    than a (pure) state tensor.

    Args:
        state: The quantum state.
        qid_shape: The qid shape of the given state.
        validate: Whether to check if the given state is a valid quantum state.
        atol: Absolute numerical tolerance to use for validation.

    Returns:
        The calculated von Neumann entropy.

    Raises:
        ValueError: Invalid quantum state.
    """
    if isinstance(state, QuantumState) and state._is_density_matrix():
        state = state.data
    if isinstance(state, np.ndarray) and state.ndim == 2 and state.shape[0] == state.shape[1]:
        if validate:
            if qid_shape is None:
                qid_shape = (state.shape[0],)
            validate_density_matrix(state, qid_shape=qid_shape, dtype=state.dtype, atol=atol)
        eigenvalues = np.linalg.eigvalsh(state)
        return stats.entropy(np.abs(eigenvalues), base=2)
    if validate:
        _ = quantum_state(state, qid_shape=qid_shape, copy=False, validate=True, atol=atol)
    return 0.0
Пример #2
0
def plot_density_matrix(
    matrix: np.ndarray,
    ax: Optional[plt.Axes] = None,
    *,
    show_text: bool = False,
    title: Optional[str] = None,
) -> plt.Axes:
    """Generates a plot for a given density matrix.

    1. Each entry of the density matrix, a complex number, is plotted as an
    Argand Diagram where the partially filled red circle represents the magnitude
    and the line represents the phase angle, going anti-clockwise from positive x - axis.
    2. The blue rectangles on the diagonal elements represent the probability
    of measuring the system in state $|i\rangle$.
    Rendering scheme is inspired from https://algassert.com/quirk

    Args:
        matrix: The density matrix to visualize
        show_text: If true, the density matrix values are also shown as text labels
        ax: The axes to plot on
        title: Title of the plot
    """
    plt.style.use('ggplot')

    _padding_around_plot = 0.001

    matrix = matrix.astype(np.complex128)
    num_qubits = int(np.log2(matrix.shape[0]))
    validate_density_matrix(matrix, qid_shape=(2**num_qubits, ))

    if ax is None:
        _, ax = plt.subplots(figsize=(10, 10))
    ax.set_xlim(0 - _padding_around_plot, 2**num_qubits + _padding_around_plot)
    ax.set_ylim(0 - _padding_around_plot, 2**num_qubits + _padding_around_plot)

    for i in range(matrix.shape[0]):
        for j in range(matrix.shape[1]):
            _plot_element_of_density_matrix(
                ax,
                i,
                j,
                np.abs(matrix[i][-j - 1]),
                np.angle(matrix[i][-j - 1]),
                show_rect=(i == matrix.shape[1] - j - 1),
                show_text=show_text,
            )

    ticks, labels = np.arange(0.5, matrix.shape[0]), [
        f"{'0'*(num_qubits - len(f'{i:b}'))}{i:b}"
        for i in range(matrix.shape[0])
    ]
    ax.set_xticks(ticks)
    ax.set_xticklabels(labels, rotation=90)
    ax.set_yticks(ticks)
    ax.set_yticklabels(reversed(labels))
    ax.set_facecolor('#eeeeee')
    if title is not None:
        ax.set_title(title)
    return ax
Пример #3
0
def _numpy_arrays_to_state_vectors_or_density_matrices(
    state1: np.ndarray,
    state2: np.ndarray,
    qid_shape: Optional[Tuple[int, ...]],
    validate: bool,
    atol: float,
) -> Tuple[np.ndarray, np.ndarray]:
    if state1.ndim > 2 or (state1.ndim == 2 and state1.shape[0] != state1.shape[1]):
        # State tensor, convert to state vector
        state1 = np.reshape(state1, (np.prod(state1.shape, dtype=np.int64).item(),))
    if state2.ndim > 2 or (state2.ndim == 2 and state2.shape[0] != state2.shape[1]):
        # State tensor, convert to state vector
        state2 = np.reshape(state2, (np.prod(state2.shape, dtype=np.int64).item(),))
    if state1.ndim == 2 and state2.ndim == 2:
        # Must be square matrices
        if state1.shape == state2.shape:
            if qid_shape is None:
                # Ambiguous whether state tensor or density matrix
                raise ValueError(
                    'The qid shape of the given states is ambiguous. '
                    'Try specifying the qid shape explicitly or '
                    'using a wrapper function like cirq.density_matrix.'
                )
            if state1.shape == qid_shape:
                # State tensors, convert to state vectors
                state1 = np.reshape(state1, (np.prod(qid_shape, dtype=np.int64).item(),))
                state2 = np.reshape(state2, (np.prod(qid_shape, dtype=np.int64).item(),))
        elif state1.shape[0] < state2.shape[0]:
            # state1 is state tensor and state2 is density matrix.
            # Convert state1 to state vector
            state1 = np.reshape(state1, (np.prod(state1.shape, dtype=np.int64).item(),))
        else:  # state1.shape[0] > state2.shape[0]
            # state2 is state tensor and state1 is density matrix.
            # Convert state2 to state vector
            state2 = np.reshape(state2, (np.prod(state2.shape, dtype=np.int64).item(),))
    elif (
        state1.ndim == 2
        and state2.ndim < 2
        and np.prod(state1.shape, dtype=np.int64) == np.prod(state2.shape, dtype=np.int64)
    ):
        # state1 is state tensor, convert to state vector
        state1 = np.reshape(state1, (np.prod(state1.shape, dtype=np.int64).item(),))
    elif (
        state1.ndim < 2
        and state2.ndim == 2
        and np.prod(state1.shape, dtype=np.int64) == np.prod(state2.shape, dtype=np.int64)
    ):
        # state2 is state tensor, convert to state vector
        state2 = np.reshape(state2, (np.prod(state2.shape, dtype=np.int64).item(),))

    if validate:
        dim1: int = (
            state1.shape[0] if state1.ndim == 2 else np.prod(state1.shape, dtype=np.int64).item()
        )
        dim2: int = (
            state2.shape[0] if state2.ndim == 2 else np.prod(state2.shape, dtype=np.int64).item()
        )
        if dim1 != dim2:
            raise ValueError('Mismatched dimensions in given states: ' f'{dim1} and {dim2}.')
        if qid_shape is None:
            qid_shape = (dim1,)
        else:
            expected_dim = np.prod(qid_shape, dtype=np.int64)
            if dim1 != expected_dim:
                raise ValueError(
                    'Invalid state dimension for given qid shape: '
                    f'Expected dimension {expected_dim} but '
                    f'got dimension {dim1}.'
                )
        for state in (state1, state2):
            if state.ndim == 2:
                validate_density_matrix(state, qid_shape=qid_shape, atol=atol)
            else:
                validate_normalized_state_vector(state, qid_shape=qid_shape, atol=atol)

    return state1, state2