Source code for povm_toolbox.quantum_info.multi_qubit_povm

# (C) Copyright IBM 2024.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""MultiQubitPOVM."""

from __future__ import annotations

import numpy as np
from matplotlib.axes import Axes
from matplotlib.figure import Figure

from .base import BasePOVM
from .multi_qubit_dual import MultiQubitDual
from .multi_qubit_frame import MultiQubitFrame


[docs] class MultiQubitPOVM(MultiQubitFrame, BasePOVM): """Class that collects all information that any POVM over multiple qubits should specify. This is a representation of a positive operator-valued measure (POVM). The effects are specified as a list of :class:`~qiskit.quantum_info.Operator`. Below is a simple example showing how you define some 2-qubit POVM: >>> from qiskit.quantum_info import Operator >>> from povm_toolbox.quantum_info import MultiQubitPOVM >>> povm = MultiQubitPOVM( ... [ ... Operator.from_label("00"), ... Operator.from_label("01"), ... Operator.from_label("10"), ... Operator.from_label("11"), ... ] ... ) >>> print(povm) MultiQubitPOVM(num_qubits=2)<4> at 0x... """ default_dual_class = MultiQubitDual def _check_validity(self) -> None: """Check if POVM axioms are fulfilled. Raises: ValueError: if any of the POVM operators is not hermitian. ValueError: if any of the POVM operators has a negative eigenvalue. ValueError: if all POVM operators do not sum to the identity. """ summed_op: np.ndarray = np.zeros((self.dimension, self.dimension), dtype=complex) for k, op in enumerate(self.operators): if not np.allclose(op, op.adjoint(), atol=1e-5): raise ValueError(f"POVM operator {k} is not hermitian.") for eigval in np.linalg.eigvalsh(op.data): if eigval.real < -1e-6 or np.abs(eigval.imag) > 1e-5: raise ValueError(f"Negative eigenvalue {eigval} in POVM operator {k}.") summed_op += op.data if not np.allclose(summed_op, np.identity(self.dimension, dtype=complex), atol=1e-5): raise ValueError(f"POVM operators not summing up to the identity : \n{summed_op}")
[docs] def draw_bloch( self, *, title: str = "", figure: Figure | None = None, axes: Axes | list[Axes] | None = None, figsize: tuple[float, float] | None = None, font_size: float | None = None, colorbar: bool = False, ) -> Figure: """Plot the Bloch vector of each effect of the POVM. .. warning:: This method is not actually implemented for a generic multi-qubit POVM. However, it is available for single-qubit POVMs (see :meth:`.SingleQubitPOVM.draw_bloch`) as well as products of such single-qubit POVMs (see :meth:`.ProductPOVM.draw_bloch`). Args: title: A string that represents the plot title. figure: User supplied Matplotlib Figure instance for plotting Bloch sphere. axes: User supplied Matplotlib axes to render the bloch sphere. figsize: Figure size in inches. Has no effect if passing ``ax``. font_size: Size of font used for Bloch sphere labels. colorbar: If ``True``, normalize the vectors on the Bloch sphere and add a colormap to keep track of the norm of the vectors. It can help to visualize the vector if they have a small norm. Returns: The resulting figure. """ raise NotImplementedError