Source code for qiskit_experiments.library.tomography.basis.pauli_basis

# This code is part of Qiskit.
#
# (C) Copyright IBM 2021.
#
# 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.
"""
Pauli preparation and measurement tomography bases.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import HGate, XGate, ZGate, SGate, SdgGate
from qiskit.quantum_info import DensityMatrix
from qiskit.exceptions import QiskitError
from qiskit_experiments.data_processing import LocalReadoutMitigator
from .local_basis import LocalMeasurementBasis, LocalPreparationBasis

if TYPE_CHECKING:
    from typing import Any, Self


[docs] class PauliMeasurementBasis(LocalMeasurementBasis): r"""Standard Pauli measurement basis. This basis has 3 indices each with with 2 measurement outcomes. The corresponding single-qubit measurement circuits and outcome POVM matrices are: .. table:: Single-qubit measurement circuits and POVM matrices +-------+-------+---------------+---------+-------------------------------+ | Index | Basis | Circuit | Outcome | POVM Matrix | +=======+=======+===============+=========+===============================+ | 0 | Z |``-[I]-`` | 0 |``[[1, 0], [0, 0]]`` | +-------+-------+---------------+---------+-------------------------------+ | | | | 1 |``[[0, 0], [0, 1]]`` | +-------+-------+---------------+---------+-------------------------------+ | 1 | X | ``-[H]-`` | 0 |``[[0.5, 0.5], [0.5, 0.5]]`` | +-------+-------+---------------+---------+-------------------------------+ | | | | 1 |``[[0.5, -0.5], [-0.5, 0.5]]`` | +-------+-------+---------------+---------+-------------------------------+ | 2 | Y |``-[SDG]-[H]-``| 0 |``[[0.5, -0.5j], [0.5j, 0.5]]``| +-------+-------+---------------+---------+-------------------------------+ | | | | 1 |``[[0.5, 0.5j], [-0.5j, 0.5]]``| +-------+-------+---------------+---------+-------------------------------+ """ def __init__(self, mitigator: LocalReadoutMitigator | None = None): """Initialize Pauli measurement basis""" # Z-meas rotation meas_z = QuantumCircuit(1, name="PauliMeasZ") # X-meas rotation meas_x = QuantumCircuit(1, name="PauliMeasX") meas_x.append(HGate(), [0]) # Y-meas rotation meas_y = QuantumCircuit(1, name="PauliMeasY") meas_y.append(SdgGate(), [0]) meas_y.append(HGate(), [0]) instructions = [meas_z, meas_x, meas_y] self._mitigator = mitigator super().__init__( "PauliMeasurementBasis", instructions, qubit_povms=self._mitigator_povm(self._mitigator) ) @staticmethod def _mitigator_povm(mitigator: LocalReadoutMitigator | None = None): """Construct LocalMeasurementBasis qubit_povm from mitigator.""" if mitigator is None: return None povm = {} if isinstance(mitigator, LocalReadoutMitigator): povm = {} for qubit in mitigator.qubits: amat = mitigator.assignment_matrix(qubit) povm[(qubit,)] = {(0,): [DensityMatrix(np.diag(row)) for row in amat]} else: raise QiskitError("Invalid mitigator: must be LocalReadoutMitigator") return povm def __json_encode__(self) -> dict[str, Any]: # Override LocalMeasurementBasis's encoder if self._mitigator is not None: return {"mitigator": self._mitigator} return {} @classmethod def __json_decode__(cls: Self, value: dict[str, Any]) -> Self: return cls(**value)
[docs] class PauliPreparationBasis(LocalPreparationBasis): """Minimal 4-element Pauli measurement basis. This is a minimal size 4 preparation basis where each qubit index corresponds to the following initial state preparation circuits and density matrices: .. table:: Single-qubit preparation circuits and states +-------+-------+---------------------+---------------------------------+ | Index | State | Preparation Circuit | Density Matrix | +=======+=======+=====================+=================================+ | 0 | Zp | ``-[I]-`` | ``[[1, 0], [0, 0]]`` | +-------+-------+---------------------+---------------------------------+ | 1 | Zm | ``-[X]-`` | ``[[0, 0], [0, 1]]`` | +-------+-------+---------------------+---------------------------------+ | 2 | Xp | ``-[H]-`` | ``[[0.5, 0.5], [0.5, 0.5]]`` | +-------+-------+---------------------+---------------------------------+ | 3 | Yp | ``-[H]-[S]-`` | ``[[0.5, -0.5j], [0.5j, 0.5]]`` | +-------+-------+---------------------+---------------------------------+ """ def __init__(self): """Initialize Pauli preparation basis""" # |0> Zp rotation prep_zp = QuantumCircuit(1, name="PauliPrepZp") # |1> Zm rotation prep_zm = QuantumCircuit(1, name="PauliPrepZm") prep_zm.append(XGate(), [0]) # |+> Xp rotation prep_xp = QuantumCircuit(1, name="PauliPrepXp") prep_xp.append(HGate(), [0]) # |+i> Yp rotation prep_yp = QuantumCircuit(1, name="PauliPrepYp") prep_yp.append(HGate(), [0]) prep_yp.append(SGate(), [0]) super().__init__("PauliPreparationBasis", [prep_zp, prep_zm, prep_xp, prep_yp]) def __json_encode__(self) -> dict[str, Any]: # Override LocalPreparationBasis's encoder return {} @classmethod def __json_decode__(cls: Self, value: dict[str, Any]) -> Self: return cls(**value)
[docs] class Pauli6PreparationBasis(LocalPreparationBasis): """Over-complete 6-element Pauli preparation basis. This is an over-complete size 6 preparation basis where each qubit index corresponds to the following initial state density matrices: .. table:: Single-qubit preparation circuits and states +-------+-------+---------------------+---------------------------------+ | Index | State | Preparation Circuit | Density Matrix | +=======+=======+=====================+=================================+ | 0 | Zp | ``-[I]-`` | ``[[1, 0], [0, 0]]`` | +-------+-------+---------------------+---------------------------------+ | 1 | Zm | ``-[X]-`` | ``[[0, 0], [0, 1]]`` | +-------+-------+---------------------+---------------------------------+ | 2 | Xp | ``-[H]-`` | ``[[0.5, 0.5], [0.5, 0.5]]`` | +-------+-------+---------------------+---------------------------------+ | 3 | Xm | ``-[H]-[Z]-`` | ``[[0.5, -0.5], [-0.5, 0.5]]`` | +-------+-------+---------------------+---------------------------------+ | 2 | Yp | ``-[H]-[S]-`` | ``[[0.5, -0.5j], [0.5j, 0.5]]`` | +-------+-------+---------------------+---------------------------------+ | 3 | Ym | ``-[H]-[Sdg]-`` | ``[[0.5, 0.5j], [-0.5j, 0.5]]`` | +-------+-------+---------------------+---------------------------------+ """ def __init__(self): # |0> Zp rotation prep_zp = QuantumCircuit(1, name="PauliPrepZp") # |1> Zm rotation prep_zm = QuantumCircuit(1, name="PauliPrepZm") prep_zm.append(XGate(), [0]) # |+> Xp rotation prep_xp = QuantumCircuit(1, name="PauliPrepXp") prep_xp.append(HGate(), [0]) # |-> Xm rotation prep_xm = QuantumCircuit(1, name="PauliPrepXm") prep_xm.append(HGate(), [0]) prep_xm.append(ZGate(), [0]) # |+i> Yp rotation prep_yp = QuantumCircuit(1, name="PauliPrepYp") prep_yp.append(HGate(), [0]) prep_yp.append(SGate(), [0]) # |-i> Ym rotation prep_ym = QuantumCircuit(1, name="PauliPrepYm") prep_ym.append(HGate(), [0]) prep_ym.append(SdgGate(), [0]) super().__init__( "Pauli6PreparationBasis", [ prep_zp, prep_zm, prep_xp, prep_xm, prep_yp, prep_ym, ], ) def __json_encode__(self) -> dict[str, Any]: # Override LocalPreparationBasis's encoder return {} @classmethod def __json_decode__(cls: Self, value: dict[str, Any]) -> Self: return cls(**value)