From 62467839e8d4e263465c42118414e6e5eca3c776 Mon Sep 17 00:00:00 2001 From: adigaboy <56532882+adigaboy@users.noreply.github.com> Date: Tue, 17 Oct 2023 03:25:29 +0300 Subject: [PATCH] removed deprecated PauliTable, StabilizerTable and tests (#10815) * removed deprecated PauliTable, StabilizerTable and tests * remove deprecated PauliTable * add release note * Revert removal of pauli_basis * fix a test * Update releasenotes/notes/remove-deprecated-in-quantum-info-0f9bd2b0c093307d.yaml Co-authored-by: Jake Lishman --------- Co-authored-by: ikkoham Co-authored-by: Jake Lishman --- qiskit/quantum_info/__init__.py | 6 - qiskit/quantum_info/operators/__init__.py | 2 - qiskit/quantum_info/operators/random.py | 8 +- .../operators/symplectic/__init__.py | 5 +- .../operators/symplectic/clifford.py | 79 - .../operators/symplectic/pauli_list.py | 8 - .../operators/symplectic/pauli_table.py | 1144 ------------ .../operators/symplectic/pauli_utils.py | 3 +- .../operators/symplectic/random.py | 28 +- .../operators/symplectic/stabilizer_table.py | 1099 ------------ qiskit/quantum_info/random.py | 1 - qiskit/test/base.py | 1 - ...ated-in-quantum-info-0f9bd2b0c093307d.yaml | 7 + test/python/opflow/test_pauli_sum_op.py | 14 +- .../operators/symplectic/test_clifford.py | 14 - .../operators/symplectic/test_pauli_list.py | 30 - .../operators/symplectic/test_pauli_table.py | 1570 ----------------- .../operators/symplectic/test_pauli_utils.py | 16 +- .../symplectic/test_sparse_pauli_op.py | 17 +- .../symplectic/test_stabilizer_table.py | 1213 ------------- .../quantum_info/operators/test_random.py | 49 +- 21 files changed, 32 insertions(+), 5282 deletions(-) delete mode 100644 qiskit/quantum_info/operators/symplectic/pauli_table.py delete mode 100644 qiskit/quantum_info/operators/symplectic/stabilizer_table.py create mode 100644 releasenotes/notes/remove-deprecated-in-quantum-info-0f9bd2b0c093307d.yaml delete mode 100644 test/python/quantum_info/operators/symplectic/test_pauli_table.py delete mode 100644 test/python/quantum_info/operators/symplectic/test_stabilizer_table.py diff --git a/qiskit/quantum_info/__init__.py b/qiskit/quantum_info/__init__.py index b906908f855d..55d5576da533 100644 --- a/qiskit/quantum_info/__init__.py +++ b/qiskit/quantum_info/__init__.py @@ -31,8 +31,6 @@ SparsePauliOp CNOTDihedral PauliList - PauliTable - StabilizerTable pauli_basis .. _quantum_info_states: @@ -94,7 +92,6 @@ .. autofunction:: random_clifford .. autofunction:: random_quantum_channel .. autofunction:: random_cnotdihedral -.. autofunction:: random_pauli_table .. autofunction:: random_pauli_list Analysis @@ -130,10 +127,8 @@ Operator, Pauli, PauliList, - PauliTable, ScalarOp, SparsePauliOp, - StabilizerTable, anti_commutator, commutator, double_commutator, @@ -149,7 +144,6 @@ random_hermitian, random_pauli, random_pauli_list, - random_pauli_table, random_quantum_channel, random_statevector, random_unitary, diff --git a/qiskit/quantum_info/operators/__init__.py b/qiskit/quantum_info/operators/__init__.py index 7a4d0596aa86..1362dfbb8dc7 100644 --- a/qiskit/quantum_info/operators/__init__.py +++ b/qiskit/quantum_info/operators/__init__.py @@ -22,9 +22,7 @@ Clifford, Pauli, PauliList, - PauliTable, SparsePauliOp, - StabilizerTable, pauli_basis, ) from .utils import anti_commutator, commutator, double_commutator diff --git a/qiskit/quantum_info/operators/random.py b/qiskit/quantum_info/operators/random.py index bb9baad93930..bde10e308d57 100644 --- a/qiskit/quantum_info/operators/random.py +++ b/qiskit/quantum_info/operators/random.py @@ -15,6 +15,7 @@ """ from __future__ import annotations + import numpy as np from numpy.random import default_rng @@ -23,12 +24,7 @@ # pylint: disable=unused-import from .dihedral.random import random_cnotdihedral -from .symplectic.random import ( - random_clifford, - random_pauli, - random_pauli_list, - random_pauli_table, -) +from .symplectic.random import random_clifford, random_pauli, random_pauli_list DEFAULT_RNG = default_rng() diff --git a/qiskit/quantum_info/operators/symplectic/__init__.py b/qiskit/quantum_info/operators/symplectic/__init__.py index c26cb018e291..2213617b11c8 100644 --- a/qiskit/quantum_info/operators/symplectic/__init__.py +++ b/qiskit/quantum_info/operators/symplectic/__init__.py @@ -15,10 +15,9 @@ """ from __future__ import annotations + +from .clifford import Clifford from .pauli import Pauli -from .pauli_table import PauliTable from .pauli_list import PauliList from .pauli_utils import pauli_basis -from .stabilizer_table import StabilizerTable -from .clifford import Clifford from .sparse_pauli_op import SparsePauliOp diff --git a/qiskit/quantum_info/operators/symplectic/clifford.py b/qiskit/quantum_info/operators/symplectic/clifford.py index 30166530337c..e84253b80b7b 100644 --- a/qiskit/quantum_info/operators/symplectic/clifford.py +++ b/qiskit/quantum_info/operators/symplectic/clifford.py @@ -35,7 +35,6 @@ from .base_pauli import BasePauli from .clifford_circuits import _append_circuit, _append_operation -from .stabilizer_table import StabilizerTable class Clifford(BaseOperator, AdjointMixin, Operation): @@ -164,10 +163,6 @@ def __init__(self, data, validate=True, copy=True): num_qubits = data.num_qubits self.tableau = Clifford.from_circuit(data).tableau - # DEPRECATED: data is StabilizerTable - elif isinstance(data, StabilizerTable): - self.tableau = self._stack_table_phase(data.array, data.phase) - num_qubits = data.num_qubits # Initialize StabilizerTable directly from the data else: if isinstance(data, (list, np.ndarray)) and np.asarray(data, dtype=bool).ndim == 2: @@ -246,80 +241,6 @@ def __setitem__(self, key, value): """Set a stabilizer Pauli row""" self.tableau.__setitem__(key, self._stack_table_phase(value.array, value.phase)) - @property - @deprecate_func( - since="0.24.0", - additional_msg="Use Clifford.stab and Clifford.destab properties instead.", - is_property=True, - ) - def table(self): - """Return StabilizerTable""" - return StabilizerTable(self.symplectic_matrix, phase=self.phase) - - @table.setter - @deprecate_func( - since="0.24.0", - additional_msg="Use Clifford.stab and Clifford.destab properties instead.", - is_property=True, - ) - def table(self, value): - """Set the stabilizer table""" - # Note this setter cannot change the size of the Clifford - # It can only replace the contents of the StabilizerTable with - # another StabilizerTable of the same size. - if not isinstance(value, StabilizerTable): - value = StabilizerTable(value) - self.symplectic_matrix = value._table._array - self.phase = value._table._phase - - @property - @deprecate_func( - since="0.24.0", - additional_msg="Use Clifford.stab properties instead.", - is_property=True, - ) - def stabilizer(self): - """Return the stabilizer block of the StabilizerTable.""" - array = self.tableau[self.num_qubits : 2 * self.num_qubits, :-1] - phase = self.tableau[self.num_qubits : 2 * self.num_qubits, -1].reshape(self.num_qubits) - return StabilizerTable(array, phase) - - @stabilizer.setter - @deprecate_func( - since="0.24.0", - additional_msg="Use Clifford.stab properties instead.", - is_property=True, - ) - def stabilizer(self, value): - """Set the value of stabilizer block of the StabilizerTable""" - if not isinstance(value, StabilizerTable): - value = StabilizerTable(value) - self.tableau[self.num_qubits : 2 * self.num_qubits, :-1] = value.array - - @property - @deprecate_func( - since="0.24.0", - additional_msg="Use Clifford.destab properties instead.", - is_property=True, - ) - def destabilizer(self): - """Return the destabilizer block of the StabilizerTable.""" - array = self.tableau[0 : self.num_qubits, :-1] - phase = self.tableau[0 : self.num_qubits, -1].reshape(self.num_qubits) - return StabilizerTable(array, phase) - - @destabilizer.setter - @deprecate_func( - since="0.24.0", - additional_msg="Use Clifford.destab properties instead.", - is_property=True, - ) - def destabilizer(self, value): - """Set the value of destabilizer block of the StabilizerTable""" - if not isinstance(value, StabilizerTable): - value = StabilizerTable(value) - self.tableau[: self.num_qubits, :-1] = value.array - @property def symplectic_matrix(self): """Return boolean symplectic matrix.""" diff --git a/qiskit/quantum_info/operators/symplectic/pauli_list.py b/qiskit/quantum_info/operators/symplectic/pauli_list.py index bc21af5c3770..08d8ff28ba53 100644 --- a/qiskit/quantum_info/operators/symplectic/pauli_list.py +++ b/qiskit/quantum_info/operators/symplectic/pauli_list.py @@ -28,8 +28,6 @@ from qiskit.quantum_info.operators.symplectic.base_pauli import BasePauli from qiskit.quantum_info.operators.symplectic.clifford import Clifford from qiskit.quantum_info.operators.symplectic.pauli import Pauli -from qiskit.quantum_info.operators.symplectic.pauli_table import PauliTable -from qiskit.quantum_info.operators.symplectic.stabilizer_table import StabilizerTable class PauliList(BasePauli, LinearMixin, GroupMixin): @@ -134,12 +132,6 @@ def __init__(self, data: Pauli | list): """ if isinstance(data, BasePauli): base_z, base_x, base_phase = data._z, data._x, data._phase - elif isinstance(data, StabilizerTable): - # Conversion from legacy StabilizerTable - base_z, base_x, base_phase = self._from_array(data.Z, data.X, 2 * data.phase) - elif isinstance(data, PauliTable): - # Conversion from legacy PauliTable - base_z, base_x, base_phase = self._from_array(data.Z, data.X) else: # Conversion as iterable of Paulis base_z, base_x, base_phase = self._from_paulis(data) diff --git a/qiskit/quantum_info/operators/symplectic/pauli_table.py b/qiskit/quantum_info/operators/symplectic/pauli_table.py deleted file mode 100644 index 3e99d11d6a33..000000000000 --- a/qiskit/quantum_info/operators/symplectic/pauli_table.py +++ /dev/null @@ -1,1144 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017, 2020 -# -# 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. -""" -Symplectic Pauli Table Class -""" -# pylint: disable=invalid-name - -from __future__ import annotations - -import numpy as np - -from qiskit.exceptions import QiskitError -from qiskit.quantum_info.operators.base_operator import BaseOperator -from qiskit.quantum_info.operators.custom_iterator import CustomIterator -from qiskit.quantum_info.operators.mixins import AdjointMixin, generate_apidocs -from qiskit.quantum_info.operators.scalar_op import ScalarOp -from qiskit.quantum_info.operators.symplectic.pauli import Pauli -from qiskit.utils.deprecation import deprecate_func - - -class PauliTable(BaseOperator, AdjointMixin): - r"""DEPRECATED: Symplectic representation of a list Pauli matrices. - - **Symplectic Representation** - - The symplectic representation of a single-qubit Pauli matrix - is a pair of boolean values :math:`[x, z]` such that the Pauli matrix - is given by :math:`P = (-i)^{z * x} \sigma_z^z.\sigma_x^x`. - The correspondence between labels, symplectic representation, - and matrices for single-qubit Paulis are shown in Table 1. - - .. list-table:: Pauli Representations - :header-rows: 1 - - * - Label - - Symplectic - - Matrix - * - ``"I"`` - - :math:`[0, 0]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}` - * - ``"X"`` - - :math:`[1, 0]` - - :math:`\begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix}` - * - ``"Y"`` - - :math:`[1, 1]` - - :math:`\begin{bmatrix} 0 & -i \\ i & 0 \end{bmatrix}` - * - ``"Z"`` - - :math:`[0, 1]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}` - - The full Pauli table is a M x 2N boolean matrix: - - .. math:: - - \left(\begin{array}{ccc|ccc} - x_{0,0} & ... & x_{0,N-1} & z_{0,0} & ... & z_{0,N-1} \\ - x_{1,0} & ... & x_{1,N-1} & z_{1,0} & ... & z_{1,N-1} \\ - \vdots & \ddots & \vdots & \vdots & \ddots & \vdots \\ - x_{M-1,0} & ... & x_{M-1,N-1} & z_{M-1,0} & ... & z_{M-1,N-1} - \end{array}\right) - - where each row is a block vector :math:`[X_i, Z_i]` with - :math:`X = [x_{i,0}, ..., x_{i,N-1}]`, :math:`Z = [z_{i,0}, ..., z_{i,N-1}]` - is the symplectic representation of an `N`-qubit Pauli. - This representation is based on reference [1]. - - PauliTable's can be created from a list of labels using :meth:`from_labels`, - and converted to a list of labels or a list of matrices using - :meth:`to_labels` and :meth:`to_matrix` respectively. - - **Group Product** - - The Pauli's in the Pauli table do not represent the full Pauli as they are - restricted to having `+1` phase. The dot-product for the Pauli's is defined - to discard any phase obtained from matrix multiplication so that we have - :math:`X.Z = Z.X = Y`, etc. This means that for the PauliTable class the - operator methods :meth:`compose` and :meth:`dot` are equivalent. - - +-------+---+---+---+---+ - | A.B | I | X | Y | Z | - +=======+===+===+===+===+ - | **I** | I | X | Y | Z | - +-------+---+---+---+---+ - | **X** | X | I | Z | Y | - +-------+---+---+---+---+ - | **Y** | Y | Z | I | X | - +-------+---+---+---+---+ - | **Z** | Z | Y | X | I | - +-------+---+---+---+---+ - - **Qubit Ordering** - - The qubits are ordered in the table such the least significant qubit - `[x_{i, 0}, z_{i, 0}]` is the first element of each of the :math:`X_i, Z_i` - vector blocks. This is the opposite order to position in string labels or - matrix tensor products where the least significant qubit is the right-most - string character. For example Pauli ``"ZX"`` has ``"X"`` on qubit-0 - and ``"Z"`` on qubit 1, and would have symplectic vectors :math:`x=[1, 0]`, - :math:`z=[0, 1]`. - - **Data Access** - - Subsets of rows can be accessed using the list access ``[]`` operator and - will return a table view of part of the PauliTable. The underlying Numpy - array can be directly accessed using the :attr:`array` property, and the - sub-arrays for only the `X` or `Z` blocks can be accessed using the - :attr:`X` and :attr:`Z` properties respectively. - - **Iteration** - - Rows in the Pauli table can be iterated over like a list. Iteration can - also be done using the label or matrix representation of each row using the - :meth:`label_iter` and :meth:`matrix_iter` methods. - - References: - 1. S. Aaronson, D. Gottesman, *Improved Simulation of Stabilizer Circuits*, - Phys. Rev. A 70, 052328 (2004). - `arXiv:quant-ph/0406196 `_ - """ - - @deprecate_func(additional_msg="Instead, use the class PauliList", since="0.24.0") - def __init__(self, data: np.ndarray | str | ScalarOp | PauliTable): - """Initialize the PauliTable. - - Args: - data (array or str or ScalarOp or PauliTable): input data. - - Raises: - QiskitError: if input array is invalid shape. - - Additional Information: - The input array is not copied so multiple Pauli tables - can share the same underlying array. - """ - if isinstance(data, (np.ndarray, list)): - self._array = np.asarray(data, dtype=bool) - elif isinstance(data, str): - # If input is a single Pauli string we convert to table - self._array = PauliTable._from_label(data) - elif isinstance(data, PauliTable): - # Share underlying array - self._array = data._array - elif isinstance(data, Pauli): - self._array = np.hstack([data.x, data.z]) - elif isinstance(data, ScalarOp): - # Initialize an N-qubit identity - if data.num_qubits is None: - raise QiskitError(f"{data} is not an N-qubit identity") - self._array = np.zeros((1, 2 * data.num_qubits), dtype=bool) - else: - raise QiskitError("Invalid input data for PauliTable.") - - # Input must be a (K, 2*N) shape matrix for M N-qubit Paulis. - if self._array.ndim == 1: - self._array = np.reshape(self._array, (1, self._array.size)) - if self._array.ndim != 2 or self._array.shape[1] % 2 != 0: - raise QiskitError("Invalid shape for PauliTable.") - - # Set size properties - self._num_paulis = self._array.shape[0] - num_qubits = self._array.shape[1] // 2 - super().__init__(num_qubits=num_qubits) - - def __repr__(self): - """Display representation.""" - prefix = "PauliTable(" - return "{}{})".format(prefix, np.array2string(self._array, separator=",", prefix=prefix)) - - def __str__(self): - """String representation.""" - return f"PauliTable: {self.to_labels()}" - - def __eq__(self, other): - """Test if two Pauli tables are equal.""" - if isinstance(other, PauliTable): - return np.all(self._array == other._array) - return False - - @property - def settings(self) -> dict: - """Return settings.""" - return {"data": self._array} - - # --------------------------------------------------------------------- - # Direct array access - # --------------------------------------------------------------------- - - @property - def array(self): - """The underlying boolean array.""" - return self._array - - @array.setter - def array(self, value): - """Set the underlying boolean array.""" - # We use [:, :] array view so that setting the array cannot - # change the arrays shape. - self._array[:, :] = value - - @property - def X(self): - """The X block of the :attr:`array`.""" - return self._array[:, 0 : self.num_qubits] - - @X.setter - def X(self, val): - self._array[:, 0 : self.num_qubits] = val - - @property - def Z(self): - """The Z block of the :attr:`array`.""" - return self._array[:, self.num_qubits : 2 * self.num_qubits] - - @Z.setter - def Z(self, val): - self._array[:, self.num_qubits : 2 * self.num_qubits] = val - - # --------------------------------------------------------------------- - # Size Properties - # --------------------------------------------------------------------- - - @property - def shape(self): - """The full shape of the :meth:`array`""" - return self._array.shape - - @property - def size(self): - """The number of Pauli rows in the table.""" - return self._num_paulis - - def __len__(self): - """Return the number of Pauli rows in the table.""" - return self.size - - # --------------------------------------------------------------------- - # Pauli Array methods - # --------------------------------------------------------------------- - - def __getitem__(self, key): - """Return a view of the PauliTable.""" - # Returns a view of specified rows of the PauliTable - # This supports all slicing operations the underlying array supports. - if isinstance(key, (int, np.integer)): - key = [key] - return PauliTable(self._array[key]) - - def __setitem__(self, key, value): - """Update PauliTable.""" - # Modify specified rows of the PauliTable - if not isinstance(value, PauliTable): - value = PauliTable(value) - self._array[key] = value.array - - def delete(self, ind: int | list, qubit: bool = False) -> PauliTable: - """Return a copy with Pauli rows deleted from table. - - When deleting qubits the qubit index is the same as the - column index of the underlying :attr:`X` and :attr:`Z` arrays. - - Args: - ind (int or list): index(es) to delete. - qubit (bool): if True delete qubit columns, otherwise delete - Pauli rows (Default: False). - - Returns: - PauliTable: the resulting table with the entries removed. - - Raises: - QiskitError: if ind is out of bounds for the array size or - number of qubits. - """ - if isinstance(ind, (int, np.integer)): - ind = [ind] - if len(ind) == 0: - return PauliTable(self._array) - # Row deletion - if not qubit: - if max(ind) >= self.size: - raise QiskitError( - "Indices {} are not all less than the size" - " of the PauliTable ({})".format(ind, self.size) - ) - return PauliTable(np.delete(self._array, ind, axis=0)) - - # Column (qubit) deletion - if max(ind) >= self.num_qubits: - raise QiskitError( - "Indices {} are not all less than the number of" - " qubits in the PauliTable ({})".format(ind, self.num_qubits) - ) - cols = ind + [self.num_qubits + i for i in ind] - return PauliTable(np.delete(self._array, cols, axis=1)) - - def insert(self, ind: int, value: PauliTable, qubit: bool = False) -> PauliTable: - """Insert Pauli's into the table. - - When inserting qubits the qubit index is the same as the - column index of the underlying :attr:`X` and :attr:`Z` arrays. - - Args: - ind (int): index to insert at. - value (PauliTable): values to insert. - qubit (bool): if True delete qubit columns, otherwise delete - Pauli rows (Default: False). - - Returns: - PauliTable: the resulting table with the entries inserted. - - Raises: - QiskitError: if the insertion index is invalid. - """ - if not isinstance(ind, (int, np.integer)): - raise QiskitError("Insert index must be an integer.") - - if not isinstance(value, PauliTable): - value = PauliTable(value) - - # Row insertion - if not qubit: - if ind > self.size: - raise QiskitError( - "Index {} is larger than the number of rows in the" - " PauliTable ({}).".format(ind, self.num_qubits) - ) - return PauliTable(np.insert(self.array, ind, value.array, axis=0)) - - # Column insertion - if ind > self.num_qubits: - raise QiskitError( - "Index {} is greater than number of qubits" - " in the PauliTable ({})".format(ind, self.num_qubits) - ) - if value.size == 1: - # Pad blocks to correct size - value_x = np.vstack(self.size * [value.X]) - value_z = np.vstack(self.size * [value.Z]) - elif value.size == self.size: - # Blocks are already correct size - value_x = value.X - value_z = value.Z - else: - # Blocks are incorrect size - raise QiskitError( - "Input PauliTable must have a single row, or" - " the same number of rows as the Pauli Table" - " ({}).".format(self.size) - ) - # Build new array by blocks - return PauliTable( - np.hstack( - ( - self.X[:, :ind], - value_x, - self.X[:, ind:], - self.Z[:, :ind], - value_z, - self.Z[:, ind:], - ) - ) - ) - - def argsort(self, weight: bool = False) -> np.ndarray: - """Return indices for sorting the rows of the table. - - The default sort method is lexicographic sorting by qubit number. - By using the `weight` kwarg the output can additionally be sorted - by the number of non-identity terms in the Pauli, where the set of - all Pauli's of a given weight are still ordered lexicographically. - - Args: - weight (bool): optionally sort by weight if True (Default: False). - - Returns: - array: the indices for sorting the table. - """ - # Get order of each Pauli using - # I => 0, X => 1, Y => 2, Z => 3 - x = self.X - z = self.Z - order = 1 * (x & ~z) + 2 * (x & z) + 3 * (~x & z) - # Optionally get the weight of Pauli - # This is the number of non identity terms - if weight: - weights = np.sum(x | z, axis=1) - - # Sort by order - # To preserve ordering between successive sorts we - # are use the 'stable' sort method - indices = np.arange(self.size) - for i in range(self.num_qubits): - sort_inds = order[:, i].argsort(kind="stable") - order = order[sort_inds] - indices = indices[sort_inds] - if weight: - weights = weights[sort_inds] - - # If using weights we implement a final sort by total number - # of non-identity Paulis - if weight: - indices = indices[weights.argsort(kind="stable")] - return indices - - def sort(self, weight: bool = False) -> PauliTable: - """Sort the rows of the table. - - The default sort method is lexicographic sorting by qubit number. - By using the `weight` kwarg the output can additionally be sorted - by the number of non-identity terms in the Pauli, where the set of - all Pauli's of a given weight are still ordered lexicographically. - - **Example** - - Consider sorting all a random ordering of all 2-qubit Paulis - - .. code-block:: - - from numpy.random import shuffle - from qiskit.quantum_info.operators import PauliTable - - # 2-qubit labels - labels = ['II', 'IX', 'IY', 'IZ', 'XI', 'XX', 'XY', 'XZ', - 'YI', 'YX', 'YY', 'YZ', 'ZI', 'ZX', 'ZY', 'ZZ'] - # Shuffle Labels - shuffle(labels) - pt = PauliTable.from_labels(labels) - print('Initial Ordering') - print(pt) - - # Lexicographic Ordering - srt = pt.sort() - print('Lexicographically sorted') - print(srt) - - # Weight Ordering - srt = pt.sort(weight=True) - print('Weight sorted') - print(srt) - - - .. parsed-literal:: - - Initial Ordering - PauliTable: [ - 'IZ', 'XZ', 'ZY', 'YI', 'YZ', 'IX', 'II', 'ZI', 'IY', 'XY', 'XI', 'YY', 'ZX', - 'XX', 'ZZ', 'YX' - ] - Lexicographically sorted - PauliTable: [ - 'II', 'IX', 'IY', 'IZ', 'XI', 'XX', 'XY', 'XZ', 'YI', 'YX', 'YY', 'YZ', 'ZI', - 'ZX', 'ZY', 'ZZ' - ] - Weight sorted - PauliTable: [ - 'II', 'IX', 'IY', 'IZ', 'XI', 'YI', 'ZI', 'XX', 'XY', 'XZ', 'YX', 'YY', 'YZ', - 'ZX', 'ZY', 'ZZ' - ] - - Args: - weight (bool): optionally sort by weight if True (Default: False). - - Returns: - PauliTable: a sorted copy of the original table. - """ - return self[self.argsort(weight=weight)] - - def unique(self, return_index: bool = False, return_counts: bool = False) -> PauliTable: - """Return unique Paulis from the table. - - **Example** - - .. code-block:: - - from qiskit.quantum_info.operators import PauliTable - - pt = PauliTable.from_labels(['X', 'Y', 'X', 'I', 'I', 'Z', 'X', 'Z']) - unique = pt.unique() - print(unique) - - .. parsed-literal:: - - PauliTable: ['X', 'Y', 'I', 'Z'] - - Args: - return_index (bool): If True, also return the indices that - result in the unique array. - (Default: False) - return_counts (bool): If True, also return the number of times - each unique item appears in the table. - - Returns: - PauliTable: unique - the table of the unique rows. - - unique_indices: np.ndarray, optional - The indices of the first occurrences of the unique values in - the original array. Only provided if ``return_index`` is True.\ - - unique_counts: np.array, optional - The number of times each of the unique values comes up in the - original array. Only provided if ``return_counts`` is True. - """ - if return_counts: - _, index, counts = np.unique(self.array, return_index=True, return_counts=True, axis=0) - else: - _, index = np.unique(self.array, return_index=True, axis=0) - # Sort the index so we return unique rows in the original array order - sort_inds = index.argsort() - index = index[sort_inds] - unique = self[index] - # Concatenate return tuples - ret = (unique,) - if return_index: - ret += (index,) - if return_counts: - ret += (counts[sort_inds],) - if len(ret) == 1: - return ret[0] - return ret - - # --------------------------------------------------------------------- - # BaseOperator methods - # --------------------------------------------------------------------- - - def tensor(self, other: PauliTable) -> PauliTable: - """Return the tensor output product of two tables. - - This returns the combination of the tensor product of all Paulis - in the current table with all Pauli's in the other table, with the - other tables qubits being the least-significant in the returned table. - This is the opposite tensor order to :meth:`expand`. - - **Example** - - .. code-block:: - - from qiskit.quantum_info.operators import PauliTable - - current = PauliTable.from_labels(['I', 'X']) - other = PauliTable.from_labels(['Y', 'Z']) - print(current.tensor(other)) - - .. parsed-literal:: - - PauliTable: ['IY', 'IZ', 'XY', 'XZ'] - - Args: - other (PauliTable): another PauliTable. - - Returns: - PauliTable: the tensor outer product table. - - Raises: - QiskitError: if other cannot be converted to a PauliTable. - """ - if not isinstance(other, PauliTable): - other = PauliTable(other) - return self._tensor(self, other) - - def expand(self, other: PauliTable) -> PauliTable: - """Return the expand output product of two tables. - - This returns the combination of the tensor product of all Paulis - in the other table with all Pauli's in the current table, with the - current tables qubits being the least-significant in the returned table. - This is the opposite tensor order to :meth:`tensor`. - - **Example** - - .. code-block:: - - from qiskit.quantum_info.operators import PauliTable - - current = PauliTable.from_labels(['I', 'X']) - other = PauliTable.from_labels(['Y', 'Z']) - print(current.expand(other)) - - .. parsed-literal:: - - PauliTable: ['YI', 'YX', 'ZI', 'ZX'] - - Args: - other (PauliTable): another PauliTable. - - Returns: - PauliTable: the expand outer product table. - - Raises: - QiskitError: if other cannot be converted to a PauliTable. - """ - if not isinstance(other, PauliTable): - other = PauliTable(other) - return self._tensor(other, self) - - def compose( - self, other: PauliTable, qargs: None | list = None, front: bool = True - ) -> PauliTable: - """Return the compose output product of two tables. - - This returns the combination of the dot product of all Paulis - in the current table with all Pauli's in the other table and - discards the complex phase from the product. Note that for - PauliTables this method is equivalent to :meth:`dot` and hence - the ``front`` kwarg does not change the output. - - **Example** - - .. code-block:: - - from qiskit.quantum_info.operators import PauliTable - - current = PauliTable.from_labels(['I', 'X']) - other = PauliTable.from_labels(['Y', 'Z']) - print(current.compose(other)) - - .. parsed-literal:: - - PauliTable: ['Y', 'Z', 'Z', 'Y'] - - Args: - other (PauliTable): another PauliTable. - qargs (None or list): qubits to apply dot product on (Default: None). - front (bool): If True use `dot` composition method [default: False]. - - Returns: - PauliTable: the compose outer product table. - - Raises: - QiskitError: if other cannot be converted to a PauliTable. - """ - if qargs is None: - qargs = getattr(other, "qargs", None) - if not isinstance(other, PauliTable): - other = PauliTable(other) - if qargs is None and other.num_qubits != self.num_qubits: - raise QiskitError("other PauliTable must be on the same number of qubits.") - if qargs and other.num_qubits != len(qargs): - raise QiskitError("Number of qubits in the other PauliTable does not match qargs.") - - # Stack X and Z blocks for output size - x1, x2 = self._block_stack(self.X, other.X) - z1, z2 = self._block_stack(self.Z, other.Z) - - if qargs is not None: - ret_x, ret_z = x1.copy(), z1.copy() - x1 = x1[:, qargs] - z1 = z1[:, qargs] - ret_x[:, qargs] = x1 ^ x2 - ret_z[:, qargs] = z1 ^ z2 - pauli = np.hstack([ret_x, ret_z]) - else: - pauli = np.hstack((x1 ^ x2, z1 ^ z2)) - return PauliTable(pauli) - - def dot(self, other: PauliTable, qargs: None | list = None) -> PauliTable: - """Return the dot output product of two tables. - - This returns the combination of the dot product of all Paulis - in the current table with all Pauli's in the other table and - discards the complex phase from the product. Note that for - PauliTables this method is equivalent to :meth:`compose`. - - **Example** - - .. code-block:: - - from qiskit.quantum_info.operators import PauliTable - - current = PauliTable.from_labels(['I', 'X']) - other = PauliTable.from_labels(['Y', 'Z']) - print(current.dot(other)) - - .. parsed-literal:: - - PauliTable: ['Y', 'Z', 'Z', 'Y'] - - Args: - other (PauliTable): another PauliTable. - qargs (None or list): qubits to apply dot product on (Default: None). - - Returns: - PauliTable: the dot outer product table. - - Raises: - QiskitError: if other cannot be converted to a PauliTable. - """ - return self.compose(other, qargs=qargs, front=True) - - @classmethod - def _tensor(cls, a, b): - x1, x2 = a._block_stack(a.X, b.X) - z1, z2 = a._block_stack(a.Z, b.Z) - return PauliTable(np.hstack([x2, x1, z2, z1])) - - def _add(self, other, qargs=None): - """Append with another PauliTable. - - If ``qargs`` are specified the other operator will be added - assuming it is identity on all other subsystems. - - Args: - other (PauliTable): another table. - qargs (None or list): optional subsystems to add on - (Default: None) - - Returns: - PauliTable: the concatenated table self + other. - """ - if qargs is None: - qargs = getattr(other, "qargs", None) - - if not isinstance(other, PauliTable): - other = PauliTable(other) - - self._op_shape._validate_add(other._op_shape, qargs) - - if qargs is None or (sorted(qargs) == qargs and len(qargs) == self.num_qubits): - return PauliTable(np.vstack((self._array, other._array))) - - # Pad other with identity and then add - padded = PauliTable(np.zeros((1, 2 * self.num_qubits), dtype=bool)) - padded = padded.compose(other, qargs=qargs) - return PauliTable(np.vstack((self._array, padded._array))) - - def __add__(self, other): - qargs = getattr(other, "qargs", None) - return self._add(other, qargs=qargs) - - def conjugate(self): - """Not implemented.""" - raise NotImplementedError(f"{type(self)} does not support conjugatge") - - def transpose(self): - """Not implemented.""" - raise NotImplementedError(f"{type(self)} does not support transpose") - - # --------------------------------------------------------------------- - # Utility methods - # --------------------------------------------------------------------- - - def commutes(self, pauli: PauliTable) -> np.ndarray: - """Return list of commutation properties for each row with a Pauli. - - The returned vector is the same length as the size of the table and - contains `True` for rows that commute with the Pauli, and `False` - for the rows that anti-commute. - - Args: - pauli (PauliTable): a single Pauli row. - - Returns: - array: The boolean vector of which rows commute or anti-commute. - - Raises: - QiskitError: if input is not a single Pauli row. - """ - if not isinstance(pauli, PauliTable): - pauli = PauliTable(pauli) - if pauli.size != 1: - raise QiskitError("Input is not a single Pauli.") - return self._commutes(self, pauli) - - def commutes_with_all(self, other: PauliTable) -> np.ndarray: - """Return indexes of rows that commute other. - - If other is a multi-row Pauli table the returned vector indexes rows - of the current PauliTable that commute with *all* Pauli's in other. - If no rows satisfy the condition the returned array will be empty. - - Args: - other (PauliTable): a single Pauli or multi-row PauliTable. - - Returns: - array: index array of the commuting rows. - """ - return self._commutes_with_all(other) - - def anticommutes_with_all(self, other: PauliTable) -> np.ndarray: - """Return indexes of rows that commute other. - - If other is a multi-row Pauli table the returned vector indexes rows - of the current PauliTable that anti-commute with *all* Pauli's in other. - If no rows satisfy the condition the returned array will be empty. - - Args: - other (PauliTable): a single Pauli or multi-row - PauliTable. - - Returns: - array: index array of the anti-commuting rows. - """ - return self._commutes_with_all(other, anti=True) - - def _commutes_with_all(self, other, anti=False): - """Return row indexes that commute with all rows in another PauliTable. - - Args: - other (PauliTable): a PauliTable. - anti (bool): if True return rows that anti-commute, otherwise - return rows that commute (Default: False). - - Returns: - array: index array of commuting or anti-commuting row. - """ - if not isinstance(other, PauliTable): - other = PauliTable(other) - comms = PauliTable._commutes(self, other[0]) - (inds,) = np.where(comms == int(not anti)) - for pauli in other[1:]: - comms = PauliTable._commutes(self[inds], pauli) - (new_inds,) = np.where(comms == int(not anti)) - if new_inds.size == 0: - # No commuting rows - return new_inds - inds = inds[new_inds] - return inds - - @staticmethod - def _commutes(pauli_table, pauli): - """Return row indexes of pauli_table that commute with pauli - - Args: - pauli_table (PauliTable): a multi-row PauliTable. - pauli (PauliTable): a single-row PauliTable. - - Returns: - array: boolean vector of which rows commute (True) or - anti-commute (False). - """ - # Find positions where self and pauli are not identities - non_iden = (pauli_table.X | pauli_table.Z) & (pauli.X | pauli.Z) - # Multiply array by Pauli, and set entries where inputs - # where I to I - tmp = PauliTable(pauli_table.array ^ pauli.array) - tmp.X = tmp.X & non_iden - tmp.Z = tmp.Z & non_iden - # Find total number of non I Pauli's remaining in table - # if there are an even number the row commutes with the - # input Pauli, otherwise it anti-commutes - return np.logical_not(np.sum((tmp.X | tmp.Z), axis=1) % 2) - - @staticmethod - def _block_stack(array1, array2): - """Stack two arrays along their first axis.""" - sz1 = len(array1) - sz2 = len(array2) - out_shape1 = (sz1 * sz2,) + array1.shape[1:] - out_shape2 = (sz1 * sz2,) + array2.shape[1:] - if sz2 > 1: - # Stack blocks for output table - ret1 = np.reshape(np.stack(sz2 * [array1], axis=1), out_shape1) - else: - ret1 = array1 - if sz1 > 1: - # Stack blocks for output table - ret2 = np.reshape(np.vstack(sz1 * [array2]), out_shape2) - else: - ret2 = array2 - return ret1, ret2 - - # --------------------------------------------------------------------- - # Representation conversions - # --------------------------------------------------------------------- - - @classmethod - def from_labels(cls, labels): - """Construct a PauliTable from a list of Pauli strings. - - Args: - labels (list): Pauli string label(es). - - Returns: - PauliTable: the constructed PauliTable. - - Raises: - QiskitError: If the input list is empty or contains invalid - Pauli strings. - """ - n_paulis = len(labels) - if n_paulis == 0: - raise QiskitError("Input Pauli list is empty.") - # Get size from first Pauli - first = cls._from_label(labels[0]) - array = np.zeros((n_paulis, len(first)), dtype=bool) - array[0] = first - for i in range(1, n_paulis): - array[i] = cls._from_label(labels[i]) - return cls(array) - - def to_labels(self, array: bool = False): - r"""Convert a PauliTable to a list Pauli string labels. - - For large PauliTables converting using the ``array=True`` - kwarg will be more efficient since it allocates memory for - the full Numpy array of labels in advance. - - .. list-table:: Pauli Representations - :header-rows: 1 - - * - Label - - Symplectic - - Matrix - * - ``"I"`` - - :math:`[0, 0]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}` - * - ``"X"`` - - :math:`[1, 0]` - - :math:`\begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix}` - * - ``"Y"`` - - :math:`[1, 1]` - - :math:`\begin{bmatrix} 0 & -i \\ i & 0 \end{bmatrix}` - * - ``"Z"`` - - :math:`[0, 1]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}` - - Args: - array (bool): return a Numpy array if True, otherwise - return a list (Default: False). - - Returns: - list or array: The rows of the PauliTable in label form. - """ - ret = np.zeros(self.size, dtype=f" list: - r"""Convert to a list or array of Pauli matrices. - - For large PauliTables converting using the ``array=True`` - kwarg will be more efficient since it allocates memory a full - rank-3 Numpy array of matrices in advance. - - .. list-table:: Pauli Representations - :header-rows: 1 - - * - Label - - Symplectic - - Matrix - * - ``"I"`` - - :math:`[0, 0]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}` - * - ``"X"`` - - :math:`[1, 0]` - - :math:`\begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix}` - * - ``"Y"`` - - :math:`[1, 1]` - - :math:`\begin{bmatrix} 0 & -i \\ i & 0 \end{bmatrix}` - * - ``"Z"`` - - :math:`[0, 1]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}` - - Args: - sparse (bool): if True return sparse CSR matrices, otherwise - return dense Numpy arrays (Default: False). - array (bool): return as rank-3 numpy array if True, otherwise - return a list of Numpy arrays (Default: False). - - Returns: - list: A list of dense Pauli matrices if `array=False` and `sparse=False`. - list: A list of sparse Pauli matrices if `array=False` and `sparse=True`. - array: A dense rank-3 array of Pauli matrices if `array=True`. - """ - if not array: - # We return a list of Numpy array matrices - return [self._to_matrix(pauli, sparse=sparse) for pauli in self._array] - # For efficiency we also allow returning a single rank-3 - # array where first index is the Pauli row, and second two - # indices are the matrix indices - dim = 2**self.num_qubits - ret = np.zeros((self.size, dim, dim), dtype=complex) - for i in range(self.size): - ret[i] = self._to_matrix(self._array[i]) - return ret - - @staticmethod - def _from_label(label): - """Return the symplectic representation of a Pauli string""" - if label[0] == "+": - # We allow +1 phase sign so we can convert back from positive - # stabilizer strings - label = label[1:] - num_qubits = len(label) - symp = np.zeros(2 * num_qubits, dtype=bool) - xs = symp[0:num_qubits] - zs = symp[num_qubits : 2 * num_qubits] - for i, char in enumerate(label): - if char not in ["I", "X", "Y", "Z"]: - raise QiskitError( - "Pauli string contains invalid character:" - " {} not in ['I', 'X', 'Y', 'Z'].".format(char) - ) - if char in ["X", "Y"]: - xs[num_qubits - 1 - i] = True - if char in ["Z", "Y"]: - zs[num_qubits - 1 - i] = True - return symp - - @staticmethod - def _to_label(pauli): - """Return the Pauli string from symplectic representation.""" - # Cast in symplectic representation - # This should avoid a copy if the pauli is already a row - # in the symplectic table - symp = np.asarray(pauli, dtype=bool) - num_qubits = symp.size // 2 - x = symp[0:num_qubits] - z = symp[num_qubits : 2 * num_qubits] - paulis = np.zeros(num_qubits, dtype=" np.ndarray: - """Return the Pauli matrix from symplectic representation. - - Args: - pauli (array): symplectic Pauli vector. - sparse (bool): if True return a sparse CSR matrix, otherwise - return a dense Numpy array (Default: False). - real_valued (bool): if True return real Pauli matrices with - Y returned as iY (Default: False). - Returns: - array: if sparse=False. - csr_matrix: if sparse=True. - """ - - def count1(i): - """Count number of set bits in int or array""" - i = i - ((i >> 1) & 0x55555555) - i = (i & 0x33333333) + ((i >> 2) & 0x33333333) - return (((i + (i >> 4) & 0xF0F0F0F) * 0x1010101) & 0xFFFFFFFF) >> 24 - - symp = np.asarray(pauli, dtype=bool) - num_qubits = symp.size // 2 - x = symp[0:num_qubits] - z = symp[num_qubits : 2 * num_qubits] - - dim = 2**num_qubits - twos_array = 1 << np.arange(num_qubits, dtype=np.uint) - x_indices = np.array(x).dot(twos_array) - z_indices = np.array(z).dot(twos_array) - - indptr = np.arange(dim + 1, dtype=np.uint) - indices = indptr ^ x_indices - parity = np.mod(count1(z_indices & indptr), 2) - if real_valued: - dtype = np.float64 - data = np.where(parity, -1.0, 1.0) - else: - dtype = np.complex64 - data = (-1j) ** np.sum(x & z) * np.where(parity, (-1 + 0j), (1 + 0j)) - - if sparse: - # Return sparse matrix - from scipy.sparse import csr_matrix - - return csr_matrix((data, indices, indptr), shape=(dim, dim), dtype=dtype) - - # Build dense matrix using csr format - mat = np.zeros((dim, dim), dtype=dtype) - for i in range(dim): - mat[i][indices[indptr[i] : indptr[i + 1]]] = data[indptr[i] : indptr[i + 1]] - return mat - - # --------------------------------------------------------------------- - # Custom Iterators - # --------------------------------------------------------------------- - - def label_iter(self): - """Return a label representation iterator. - - This is a lazy iterator that converts each row into the string - label only as it is used. To convert the entire table to labels use - the :meth:`to_labels` method. - - Returns: - LabelIterator: label iterator object for the PauliTable. - """ - - class LabelIterator(CustomIterator): - """Label representation iteration and item access.""" - - def __repr__(self): - return f"" - - def __getitem__(self, key): - return self.obj._to_label(self.obj.array[key]) - - return LabelIterator(self) - - def matrix_iter(self, sparse: bool = False): - """Return a matrix representation iterator. - - This is a lazy iterator that converts each row into the Pauli matrix - representation only as it is used. To convert the entire table to - matrices use the :meth:`to_matrix` method. - - Args: - sparse (bool): optionally return sparse CSR matrices if True, - otherwise return Numpy array matrices - (Default: False) - - Returns: - MatrixIterator: matrix iterator object for the PauliTable. - """ - - class MatrixIterator(CustomIterator): - """Matrix representation iteration and item access.""" - - def __repr__(self): - return f"" - - def __getitem__(self, key): - return self.obj._to_matrix(self.obj.array[key], sparse=sparse) - - return MatrixIterator(self) - - -# Update docstrings for API docs -generate_apidocs(PauliTable) diff --git a/qiskit/quantum_info/operators/symplectic/pauli_utils.py b/qiskit/quantum_info/operators/symplectic/pauli_utils.py index e132499d54c0..4fe074cbe754 100644 --- a/qiskit/quantum_info/operators/symplectic/pauli_utils.py +++ b/qiskit/quantum_info/operators/symplectic/pauli_utils.py @@ -14,11 +14,12 @@ """ from __future__ import annotations + from qiskit.quantum_info.operators.symplectic.pauli_list import PauliList def pauli_basis(num_qubits: int, weight: bool = False) -> PauliList: - """Return the ordered PauliTable or PauliList for the n-qubit Pauli basis. + """Return the ordered PauliList for the n-qubit Pauli basis. Args: num_qubits (int): number of qubits diff --git a/qiskit/quantum_info/operators/symplectic/random.py b/qiskit/quantum_info/operators/symplectic/random.py index 2e4d4b89ad74..999c52e6959d 100644 --- a/qiskit/quantum_info/operators/symplectic/random.py +++ b/qiskit/quantum_info/operators/symplectic/random.py @@ -14,14 +14,13 @@ """ from __future__ import annotations + import numpy as np from numpy.random import default_rng - from .clifford import Clifford from .pauli import Pauli from .pauli_list import PauliList -from .pauli_table import PauliTable def random_pauli( @@ -86,31 +85,6 @@ def random_pauli_list( return PauliList.from_symplectic(z, x) -def random_pauli_table( - num_qubits: int, size: int = 1, seed: int | np.random.Generator | None = None -): - """Return a random PauliTable. - - Args: - num_qubits (int): the number of qubits. - size (int): Optional. The number of rows of the table (Default: 1). - seed (int or np.random.Generator): Optional. Set a fixed seed or - generator for RNG. - - Returns: - PauliTable: a random PauliTable. - """ - if seed is None: - rng = np.random.default_rng() - elif isinstance(seed, np.random.Generator): - rng = seed - else: - rng = default_rng(seed) - - table = rng.integers(2, size=(size, 2 * num_qubits)).astype(bool) - return PauliTable(table) - - def random_clifford(num_qubits: int, seed: int | np.random.Generator | None = None): """Return a random Clifford operator. diff --git a/qiskit/quantum_info/operators/symplectic/stabilizer_table.py b/qiskit/quantum_info/operators/symplectic/stabilizer_table.py deleted file mode 100644 index 6c2c0c9b9169..000000000000 --- a/qiskit/quantum_info/operators/symplectic/stabilizer_table.py +++ /dev/null @@ -1,1099 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017, 2023 -# -# 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. -""" -Symplectic Stabilizer Table Class -""" - -from __future__ import annotations -import numpy as np - -from qiskit.exceptions import QiskitError -from qiskit.quantum_info.operators.custom_iterator import CustomIterator -from qiskit.quantum_info.operators.mixins import AdjointMixin, generate_apidocs -from qiskit.quantum_info.operators.symplectic.pauli_table import PauliTable -from qiskit.utils.deprecation import deprecate_func - - -class StabilizerTable(PauliTable, AdjointMixin): - r"""DEPRECATED: Symplectic representation of a list Stabilizer matrices. - - **Symplectic Representation** - - The symplectic representation of a single-qubit Stabilizer matrix - is a pair of boolean values :math:`[x, z]` and a boolean phase `p` - such that the Stabilizer matrix is given by - :math:`S = (-1)^p \sigma_z^z.\sigma_x^x`. - The correspondence between labels, symplectic representation, - stabilizer matrices, and Pauli matrices for the single-qubit case is - shown in the following table. - - .. list-table:: Table 1: Stabilizer Representations - :header-rows: 1 - - * - Label - - Phase - - Symplectic - - Matrix - - Pauli - * - ``"+I"`` - - 0 - - :math:`[0, 0]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}` - - :math:`I` - * - ``"-I"`` - - 1 - - :math:`[0, 0]` - - :math:`\begin{bmatrix} -1 & 0 \\ 0 & -1 \end{bmatrix}` - - :math:`-I` - * - ``"X"`` - - 0 - - :math:`[1, 0]` - - :math:`\begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix}` - - :math:`X` - * - ``"-X"`` - - 1 - - :math:`[1, 0]` - - :math:`\begin{bmatrix} 0 & -1 \\ -1 & 0 \end{bmatrix}` - - :math:`-X` - * - ``"Y"`` - - 0 - - :math:`[1, 1]` - - :math:`\begin{bmatrix} 0 & 1 \\ -1 & 0 \end{bmatrix}` - - :math:`iY` - * - ``"-Y"`` - - 1 - - :math:`[1, 1]` - - :math:`\begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix}` - - :math:`-iY` - * - ``"Z"`` - - 0 - - :math:`[0, 1]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}` - - :math:`Z` - * - ``"-Z"`` - - 1 - - :math:`[0, 1]` - - :math:`\begin{bmatrix} -1 & 0 \\ 0 & 1 \end{bmatrix}` - - :math:`-Z` - - Internally this is stored as a length `N` boolean phase vector - :math:`[p_{N-1}, ..., p_{0}]` and a :class:`PauliTable` - :math:`M \times 2N` boolean matrix: - - .. math:: - - \left(\begin{array}{ccc|ccc} - x_{0,0} & ... & x_{0,N-1} & z_{0,0} & ... & z_{0,N-1} \\ - x_{1,0} & ... & x_{1,N-1} & z_{1,0} & ... & z_{1,N-1} \\ - \vdots & \ddots & \vdots & \vdots & \ddots & \vdots \\ - x_{M-1,0} & ... & x_{M-1,N-1} & z_{M-1,0} & ... & z_{M-1,N-1} - \end{array}\right) - - where each row is a block vector :math:`[X_i, Z_i]` with - :math:`X_i = [x_{i,0}, ..., x_{i,N-1}]`, :math:`Z_i = [z_{i,0}, ..., z_{i,N-1}]` - is the symplectic representation of an `N`-qubit Pauli. - This representation is based on reference [1]. - - StabilizerTable's can be created from a list of labels using :meth:`from_labels`, - and converted to a list of labels or a list of matrices using - :meth:`to_labels` and :meth:`to_matrix` respectively. - - **Group Product** - - The product of the stabilizer elements is defined with respect to the - matrix multiplication of the matrices in Table 1. In terms of - stabilizes labels the dot product group structure is - - +-------+----+----+----+----+ - | A.B | I | X | Y | Z | - +=======+====+====+====+====+ - | **I** | I | X | Y | Z | - +-------+----+----+----+----+ - | **X** | X | I | -Z | Y | - +-------+----+----+----+----+ - | **Y** | Y | Z | -I | -X | - +-------+----+----+----+----+ - | **Z** | Z | -Y | X | I | - +-------+----+----+----+----+ - - The :meth:`dot` method will return the output for - :code:`row.dot(col) = row.col`, while the :meth:`compose` will return - :code:`row.compose(col) = col.row` from the above table. - - Note that while this dot product is different to the matrix product - of the :class:`PauliTable`, it does not change the commutation structure - of elements. Hence :meth:`commutes:` will be the same for the same - labels. - - **Qubit Ordering** - - The qubits are ordered in the table such the least significant qubit - `[x_{i, 0}, z_{i, 0}]` is the first element of each of the :math:`X_i, Z_i` - vector blocks. This is the opposite order to position in string labels or - matrix tensor products where the least significant qubit is the right-most - string character. For example Pauli ``"ZX"`` has ``"X"`` on qubit-0 - and ``"Z"`` on qubit 1, and would have symplectic vectors :math:`x=[1, 0]`, - :math:`z=[0, 1]`. - - **Data Access** - - Subsets of rows can be accessed using the list access ``[]`` operator and - will return a table view of part of the StabilizerTable. The underlying - phase vector and Pauli array can be directly accessed using the :attr:`phase` - and :attr:`array` properties respectively. The sub-arrays for only the - `X` or `Z` blocks can be accessed using the :attr:`X` and :attr:`Z` - properties respectively. - - The Pauli part of the Stabilizer table can be viewed and accessed as a - :class:`PauliTable` object using the :attr:`pauli` property. Note that this - doesn't copy the underlying array so any changes made to the Pauli table - will also change the stabilizer table. - - **Iteration** - - Rows in the Stabilizer table can be iterated over like a list. Iteration can - also be done using the label or matrix representation of each row using the - :meth:`label_iter` and :meth:`matrix_iter` methods. - - References: - 1. S. Aaronson, D. Gottesman, *Improved Simulation of Stabilizer Circuits*, - Phys. Rev. A 70, 052328 (2004). - `arXiv:quant-ph/0406196 `_ - """ - - @deprecate_func(additional_msg="Instead, use the class PauliList", since="0.24.0") - def __init__(self, data: np.ndarray | str | PauliTable, phase: np.ndarray | bool | None = None): - """Initialize the StabilizerTable. - - Args: - data (array or str or PauliTable): input PauliTable data. - phase (array or bool or None): optional phase vector for input data - (Default: None). - - Raises: - QiskitError: if input array or phase vector has an invalid shape. - - Additional Information: - The input array is not copied so multiple Pauli and Stabilizer tables - can share the same underlying array. - """ - if isinstance(data, str) and phase is None: - pauli, phase = StabilizerTable._from_label(data) - elif isinstance(data, StabilizerTable): - pauli = data._array - if phase is None: - phase = data._phase - else: - pauli = data - # Initialize the Pauli table - super().__init__(pauli) - - # Initialize the phase vector - if phase is None or phase is False: - self._phase = np.zeros(self.size, dtype=bool) - elif phase is True: - self._phase = np.ones(self.size, dtype=bool) - else: - self._phase = np.asarray(phase, dtype=bool) - if self._phase.shape != (self.size,): - raise QiskitError("Phase vector is incorrect shape.") - - def __repr__(self): - return f"StabilizerTable(\n{repr(self._array)},\nphase={repr(self._phase)})" - - def __str__(self): - """String representation""" - return f"StabilizerTable: {self.to_labels()}" - - def __eq__(self, other): - """Test if two StabilizerTables are equal""" - if isinstance(other, StabilizerTable): - return np.all(self._phase == other._phase) and self.pauli == other.pauli - return False - - def copy(self): - """Return a copy of the StabilizerTable.""" - return StabilizerTable(self._array.copy(), self._phase.copy()) - - # --------------------------------------------------------------------- - # PauliTable and phase access - # --------------------------------------------------------------------- - - @property - def pauli(self): - """Return PauliTable""" - return PauliTable(self._array) - - @pauli.setter - def pauli(self, value): - if not isinstance(value, PauliTable): - value = PauliTable(value) - self._array[:, :] = value._array - - @property - def phase(self): - """Return phase vector""" - return self._phase - - @phase.setter - def phase(self, value): - self._phase[:] = value - - # --------------------------------------------------------------------- - # Array methods - # --------------------------------------------------------------------- - - def __getitem__(self, key): - """Return a view of StabilizerTable""" - if isinstance(key, (int, np.integer)): - key = [key] - return StabilizerTable(self._array[key], self._phase[key]) - - def __setitem__(self, key, value): - """Update StabilizerTable""" - if not isinstance(value, StabilizerTable): - value = StabilizerTable(value) - self._array[key] = value.array - self._phase[key] = value.phase - - def delete(self, ind: int | list, qubit: bool = False) -> StabilizerTable: - """Return a copy with Stabilizer rows deleted from table. - - When deleting qubit columns, qubit-0 is the right-most - (largest index) column, and qubit-(N-1) is the left-most - (0 index) column of the underlying :attr:`X` and :attr:`Z` - arrays. - - Args: - ind (int or list): index(es) to delete. - qubit (bool): if True delete qubit columns, otherwise delete - Stabilizer rows (Default: False). - - Returns: - StabilizerTable: the resulting table with the entries removed. - - Raises: - QiskitError: if ind is out of bounds for the array size or - number of qubits. - """ - if qubit: - # When deleting qubit columns we don't need to modify - # the phase vector - table = super().delete(ind, True) - return StabilizerTable(table, self._phase) - - if isinstance(ind, (int, np.integer)): - ind = [ind] - if max(ind) >= self.size: - raise QiskitError( - "Indices {} are not all less than the size of the StabilizerTable ({})".format( - ind, self.size - ) - ) - return StabilizerTable( - np.delete(self._array, ind, axis=0), np.delete(self._phase, ind, axis=0) - ) - - def insert(self, ind: int, value: StabilizerTable, qubit: bool = False) -> StabilizerTable: - """Insert stabilizers's into the table. - - When inserting qubit columns, qubit-0 is the right-most - (largest index) column, and qubit-(N-1) is the left-most - (0 index) column of the underlying :attr:`X` and :attr:`Z` - arrays. - - Args: - ind (int): index to insert at. - value (StabilizerTable): values to insert. - qubit (bool): if True delete qubit columns, otherwise delete - Pauli rows (Default: False). - - Returns: - StabilizerTable: the resulting table with the entries inserted. - - Raises: - QiskitError: if the insertion index is invalid. - """ - if not isinstance(ind, (int, np.integer)): - raise QiskitError("Insert index must be an integer.") - if not isinstance(value, StabilizerTable): - value = StabilizerTable(value) - - # Update PauliTable component - table = super().insert(ind, value, qubit=qubit) - - # Update phase vector - if not qubit: - phase = np.insert(self._phase, ind, value._phase, axis=0) - else: - phase = np.logical_xor(self._phase, value._phase) - return StabilizerTable(table, phase) - - def argsort(self, weight: bool = False) -> np.ndarray: - """Return indices for sorting the rows of the PauliTable. - - The default sort method is lexicographic sorting of Paulis by - qubit number. By using the `weight` kwarg the output can additionally - be sorted by the number of non-identity terms in the Stabilizer, - where the set of all Pauli's of a given weight are still ordered - lexicographically. - - This does not sort based on phase values. It will preserve the - original order of rows with the same Pauli's but different phases. - - Args: - weight (bool): optionally sort by weight if True (Default: False). - - Returns: - array: the indices for sorting the table. - """ - return super().argsort(weight=weight) - - def sort(self, weight: bool = False) -> StabilizerTable: - """Sort the rows of the table. - - The default sort method is lexicographic sorting by qubit number. - By using the `weight` kwarg the output can additionally be sorted - by the number of non-identity terms in the Pauli, where the set of - all Pauli's of a given weight are still ordered lexicographically. - - This does not sort based on phase values. It will preserve the - original order of rows with the same Pauli's but different phases. - - Consider sorting all a random ordering of all 2-qubit Paulis - - .. code-block:: - - from numpy.random import shuffle - from qiskit.quantum_info.operators import StabilizerTable - - # 2-qubit labels - labels = ['+II', '+IX', '+IY', '+IZ', '+XI', '+XX', '+XY', '+XZ', - '+YI', '+YX', '+YY', '+YZ', '+ZI', '+ZX', '+ZY', '+ZZ', - '-II', '-IX', '-IY', '-IZ', '-XI', '-XX', '-XY', '-XZ', - '-YI', '-YX', '-YY', '-YZ', '-ZI', '-ZX', '-ZY', '-ZZ'] - # Shuffle Labels - shuffle(labels) - st = StabilizerTable.from_labels(labels) - print('Initial Ordering') - print(st) - - # Lexicographic Ordering - srt = st.sort() - print('Lexicographically sorted') - print(srt) - - # Weight Ordering - srt = st.sort(weight=True) - print('Weight sorted') - print(srt) - - .. parsed-literal:: - - Initial Ordering - StabilizerTable: [ - '-YZ', '+IX', '-ZI', '+II', '-IY', '-II', '-XI', '-IX', '-ZX', '-ZZ', '+XY', '+XZ', - '-YX', '-YI', '+ZI', '+ZX', '+ZY', '+IZ', '-ZY', '+YZ', '-IZ', '-XX', '+XI', '+YI', - '+XX', '+IY', '+ZZ', '-XY', '-YY', '+YX', '+YY', '-XZ' - ] - Lexicographically sorted - StabilizerTable: [ - '+II', '-II', '+IX', '-IX', '-IY', '+IY', '+IZ', '-IZ', '-XI', '+XI', '-XX', '+XX', - '+XY', '-XY', '+XZ', '-XZ', '-YI', '+YI', '-YX', '+YX', '-YY', '+YY', '-YZ', '+YZ', - '-ZI', '+ZI', '-ZX', '+ZX', '+ZY', '-ZY', '-ZZ', '+ZZ' - ] - Weight sorted - StabilizerTable: [ - '+II', '-II', '+IX', '-IX', '-IY', '+IY', '+IZ', '-IZ', '-XI', '+XI', '-YI', '+YI', - '-ZI', '+ZI', '-XX', '+XX', '+XY', '-XY', '+XZ', '-XZ', '-YX', '+YX', '-YY', '+YY', - '-YZ', '+YZ', '-ZX', '+ZX', '+ZY', '-ZY', '-ZZ', '+ZZ' - ] - - Args: - weight (bool): optionally sort by weight if True (Default: False). - - Returns: - StabilizerTable: a sorted copy of the original table. - """ - return super().sort(weight=weight) - - def unique(self, return_index: bool = False, return_counts: bool = False) -> StabilizerTable: - """Return unique stabilizers from the table. - - **Example** - - .. code-block:: - - from qiskit.quantum_info.operators import StabilizerTable - - st = StabilizerTable.from_labels(['+X', '+I', '-I', '-X', '+X', '-X', '+I']) - unique = st.unique() - print(unique) - - .. parsed-literal:: - - StabilizerTable: ['+X', '+I', '-I', '-X'] - - Args: - return_index (bool): If True, also return the indices that - result in the unique array. - (Default: False) - return_counts (bool): If True, also return the number of times - each unique item appears in the table. - - Returns: - StabilizerTable: unique - the table of the unique rows. - - unique_indices: np.ndarray, optional - The indices of the first occurrences of the unique values in - the original array. Only provided if ``return_index`` is True.\ - - unique_counts: np.array, optional - The number of times each of the unique values comes up in the - original array. Only provided if ``return_counts`` is True. - """ - # Combine array and phases into single array for sorting - stack = np.hstack([self._array, self._phase.reshape((self.size, 1))]) - if return_counts: - _, index, counts = np.unique(stack, return_index=True, return_counts=True, axis=0) - else: - _, index = np.unique(stack, return_index=True, axis=0) - # Sort the index so we return unique rows in the original array order - sort_inds = index.argsort() - index = index[sort_inds] - unique = self[index] - # Concatenate return tuples - ret = (unique,) - if return_index: - ret += (index,) - if return_counts: - ret += (counts[sort_inds],) - if len(ret) == 1: - return ret[0] - return ret - - # --------------------------------------------------------------------- - # Utility methods - # --------------------------------------------------------------------- - - def tensor(self, other: StabilizerTable) -> StabilizerTable: - """Return the tensor output product of two tables. - - This returns the combination of the tensor product of all - stabilizers in the `current` table with all stabilizers in the - `other` table. The `other` tables qubits will be the - least-significant in the returned table. This is the opposite - tensor order to :meth:`tensor`. - - **Example** - - .. code-block:: - - from qiskit.quantum_info.operators import StabilizerTable - - current = StabilizerTable.from_labels(['+I', '-X']) - other = StabilizerTable.from_labels(['-Y', '+Z']) - print(current.tensor(other)) - - .. parsed-literal:: - - StabilizerTable: ['-IY', '+IZ', '+XY', '-XZ'] - - Args: - other (StabilizerTable): another StabilizerTable. - - Returns: - StabilizerTable: the tensor outer product table. - - Raises: - QiskitError: if other cannot be converted to a StabilizerTable. - """ - if not isinstance(other, StabilizerTable): - other = StabilizerTable(other) - return self._tensor(self, other) - - def expand(self, other: StabilizerTable) -> StabilizerTable: - """Return the expand output product of two tables. - - This returns the combination of the tensor product of all - stabilizers in the `other` table with all stabilizers in the - `current` table. The `current` tables qubits will be the - least-significant in the returned table. This is the opposite - tensor order to :meth:`tensor`. - - **Example** - - .. code-block:: - - from qiskit.quantum_info.operators import StabilizerTable - - current = StabilizerTable.from_labels(['+I', '-X']) - other = StabilizerTable.from_labels(['-Y', '+Z']) - print(current.expand(other)) - - .. parsed-literal:: - - StabilizerTable: ['-YI', '+YX', '+ZI', '-ZX'] - - Args: - other (StabilizerTable): another StabilizerTable. - - Returns: - StabilizerTable: the expand outer product table. - - Raises: - QiskitError: if other cannot be converted to a StabilizerTable. - """ - if not isinstance(other, StabilizerTable): - other = StabilizerTable(other) - return self._tensor(other, self) - - def compose( - self, other: StabilizerTable, qargs: None | list = None, front: bool = False - ) -> StabilizerTable: - """Return the compose output product of two tables. - - This returns the combination of the compose product of all - stabilizers in the current table with all stabilizers in the - other table. - - The individual stabilizer compose product is given by - - +----------------------+----+----+----+----+ - | :code:`A.compose(B)` | I | X | Y | Z | - +======================+====+====+====+====+ - | **I** | I | X | Y | Z | - +----------------------+----+----+----+----+ - | **X** | X | I | Z | -Y | - +----------------------+----+----+----+----+ - | **Y** | Y | -Z | -I | X | - +----------------------+----+----+----+----+ - | **Z** | Z | Y | -X | I | - +----------------------+----+----+----+----+ - - If `front=True` the composition will be given by the - :meth:`dot` method. - - **Example** - - .. code-block:: - - from qiskit.quantum_info.operators import StabilizerTable - - current = StabilizerTable.from_labels(['+I', '-X']) - other = StabilizerTable.from_labels(['+X', '-Z']) - print(current.compose(other)) - - .. parsed-literal:: - - StabilizerTable: ['+X', '-Z', '-I', '-Y'] - - Args: - other (StabilizerTable): another StabilizerTable. - qargs (None or list): qubits to apply compose product on - (Default: None). - front (bool): If True use `dot` composition method - (default: False). - - Returns: - StabilizerTable: the compose outer product table. - - Raises: - QiskitError: if other cannot be converted to a StabilizerTable. - """ - if qargs is None: - qargs = getattr(other, "qargs", None) - if not isinstance(other, StabilizerTable): - other = StabilizerTable(other) - if qargs is None and other.num_qubits != self.num_qubits: - raise QiskitError("other StabilizerTable must be on the same number of qubits.") - if qargs and other.num_qubits != len(qargs): - raise QiskitError("Number of qubits in the other StabilizerTable does not match qargs.") - - # Stack X and Z blocks for output size - x1, x2 = self._block_stack(self.X, other.X) - z1, z2 = self._block_stack(self.Z, other.Z) - phase1, phase2 = self._block_stack(self.phase, other.phase) - - if qargs is not None: - ret_x, ret_z = x1.copy(), z1.copy() - x1 = x1[:, qargs] - z1 = z1[:, qargs] - ret_x[:, qargs] = x1 ^ x2 - ret_z[:, qargs] = z1 ^ z2 - pauli = np.hstack([ret_x, ret_z]) - else: - pauli = np.hstack((x1 ^ x2, z1 ^ z2)) - - # We pick up a minus sign for products: - # Y.Y = -I, X.Y = -Z, Y.Z = -X, Z.X = -Y - if front: - minus = (x1 & z2 & (x2 | z1)) | (~x1 & x2 & z1 & ~z2) - else: - minus = (x2 & z1 & (x1 | z2)) | (~x2 & x1 & z2 & ~z1) - phase_shift = np.array(np.sum(minus, axis=1) % 2, dtype=bool) - phase = phase_shift ^ phase1 ^ phase2 - return StabilizerTable(pauli, phase) - - def dot(self, other: StabilizerTable, qargs: None | list = None) -> StabilizerTable: - """Return the dot output product of two tables. - - This returns the combination of the compose product of all - stabilizers in the current table with all stabilizers in the - other table. - - The individual stabilizer dot product is given by - - +------------------+----+----+----+----+ - | :code:`A.dot(B)` | I | X | Y | Z | - +==================+====+====+====+====+ - | **I** | I | X | Y | Z | - +------------------+----+----+----+----+ - | **X** | X | I | -Z | Y | - +------------------+----+----+----+----+ - | **Y** | Y | Z | -I | -X | - +------------------+----+----+----+----+ - | **Z** | Z | -Y | X | I | - +------------------+----+----+----+----+ - - **Example** - - .. code-block:: - - from qiskit.quantum_info.operators import StabilizerTable - - current = StabilizerTable.from_labels(['+I', '-X']) - other = StabilizerTable.from_labels(['+X', '-Z']) - print(current.dot(other)) - - .. parsed-literal:: - - StabilizerTable: ['+X', '-Z', '-I', '+Y'] - - Args: - other (StabilizerTable): another StabilizerTable. - qargs (None or list): qubits to apply dot product on - (Default: None). - - Returns: - StabilizerTable: the dot outer product table. - - Raises: - QiskitError: if other cannot be converted to a StabilizerTable. - """ - return self.compose(other, qargs=qargs, front=True) - - @classmethod - def _tensor(cls, a, b): - pauli = super()._tensor(a, b) - phase1, phase2 = a._block_stack(a.phase, b.phase) - phase = np.logical_xor(phase1, phase2) - return StabilizerTable(pauli, phase) - - def _add(self, other, qargs=None): - """Append with another StabilizerTable. - - If ``qargs`` are specified the other operator will be added - assuming it is identity on all other subsystems. - - Args: - other (StabilizerTable): another table. - qargs (None or list): optional subsystems to add on - (Default: None) - - Returns: - StabilizerTable: the concatenated table self + other. - """ - if qargs is None: - qargs = getattr(other, "qargs", None) - - if not isinstance(other, StabilizerTable): - other = StabilizerTable(other) - - self._op_shape._validate_add(other._op_shape, qargs) - - if qargs is None or (sorted(qargs) == qargs and len(qargs) == self.num_qubits): - return StabilizerTable( - np.vstack((self._array, other._array)), np.hstack((self._phase, other._phase)) - ) - - # Pad other with identity and then add - padded = StabilizerTable(np.zeros((1, 2 * self.num_qubits), dtype=bool)) - padded = padded.compose(other, qargs=qargs) - - return StabilizerTable( - np.vstack((self._array, padded._array)), np.hstack((self._phase, padded._phase)) - ) - - def _multiply(self, other): - """Multiply (XOR) phase vector of the StabilizerTable. - - This updates the phase vector of the table. Allowed values for - multiplication are ``False``, ``True``, 1 or -1. Multiplying by - -1 or ``False`` is equivalent. As is multiplying by 1 or ``True``. - - Args: - other (bool or int): a Boolean value. - - Returns: - StabilizerTable: the updated stabilizer table. - - Raises: - QiskitError: if other is not in (False, True, 1, -1). - """ - # Numeric (integer) value case - if not isinstance(other, bool) and other not in [1, -1]: - raise QiskitError("Can only multiply a Stabilizer value by +1 or -1 phase.") - - # We have to be careful we don't cast True <-> +1 when - # we store -1 phase as boolen True value - if (isinstance(other, bool) and other) or other == -1: - ret = self.copy() - ret._phase ^= True - return ret - return self - - # --------------------------------------------------------------------- - # Representation conversions - # --------------------------------------------------------------------- - - @classmethod - def from_labels(cls, labels: list) -> StabilizerTable: - r"""Construct a StabilizerTable from a list of Pauli stabilizer strings. - - Pauli Stabilizer string labels are Pauli strings with an optional - ``"+"`` or ``"-"`` character. If there is no +/-sign a + phase is - used by default. - - .. list-table:: Stabilizer Representations - :header-rows: 1 - - * - Label - - Phase - - Symplectic - - Matrix - - Pauli - * - ``"+I"`` - - 0 - - :math:`[0, 0]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}` - - :math:`I` - * - ``"-I"`` - - 1 - - :math:`[0, 0]` - - :math:`\begin{bmatrix} -1 & 0 \\ 0 & -1 \end{bmatrix}` - - :math:`-I` - * - ``"X"`` - - 0 - - :math:`[1, 0]` - - :math:`\begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix}` - - :math:`X` - * - ``"-X"`` - - 1 - - :math:`[1, 0]` - - :math:`\begin{bmatrix} 0 & -1 \\ -1 & 0 \end{bmatrix}` - - :math:`-X` - * - ``"Y"`` - - 0 - - :math:`[1, 1]` - - :math:`\begin{bmatrix} 0 & 1 \\ -1 & 0 \end{bmatrix}` - - :math:`iY` - * - ``"-Y"`` - - 1 - - :math:`[1, 1]` - - :math:`\begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix}` - - :math:`-iY` - * - ``"Z"`` - - 0 - - :math:`[0, 1]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}` - - :math:`Z` - * - ``"-Z"`` - - 1 - - :math:`[0, 1]` - - :math:`\begin{bmatrix} -1 & 0 \\ 0 & 1 \end{bmatrix}` - - :math:`-Z` - - Args: - labels (list): Pauli stabilizer string label(es). - - Returns: - StabilizerTable: the constructed StabilizerTable. - - Raises: - QiskitError: If the input list is empty or contains invalid - Pauli stabilizer strings. - """ - if isinstance(labels, str): - labels = [labels] - n_paulis = len(labels) - if n_paulis == 0: - raise QiskitError("Input Pauli list is empty.") - # Get size from first Pauli - pauli, phase = cls._from_label(labels[0]) - table = np.zeros((n_paulis, len(pauli)), dtype=bool) - phases = np.zeros(n_paulis, dtype=bool) - table[0], phases[0] = pauli, phase - for i in range(1, n_paulis): - table[i], phases[i] = cls._from_label(labels[i]) - return cls(table, phases) - - def to_labels(self, array: bool = False): - r"""Convert a StabilizerTable to a list Pauli stabilizer string labels. - - For large StabilizerTables converting using the ``array=True`` - kwarg will be more efficient since it allocates memory for - the full Numpy array of labels in advance. - - .. list-table:: Stabilizer Representations - :header-rows: 1 - - * - Label - - Phase - - Symplectic - - Matrix - - Pauli - * - ``"+I"`` - - 0 - - :math:`[0, 0]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}` - - :math:`I` - * - ``"-I"`` - - 1 - - :math:`[0, 0]` - - :math:`\begin{bmatrix} -1 & 0 \\ 0 & -1 \end{bmatrix}` - - :math:`-I` - * - ``"X"`` - - 0 - - :math:`[1, 0]` - - :math:`\begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix}` - - :math:`X` - * - ``"-X"`` - - 1 - - :math:`[1, 0]` - - :math:`\begin{bmatrix} 0 & -1 \\ -1 & 0 \end{bmatrix}` - - :math:`-X` - * - ``"Y"`` - - 0 - - :math:`[1, 1]` - - :math:`\begin{bmatrix} 0 & 1 \\ -1 & 0 \end{bmatrix}` - - :math:`iY` - * - ``"-Y"`` - - 1 - - :math:`[1, 1]` - - :math:`\begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix}` - - :math:`-iY` - * - ``"Z"`` - - 0 - - :math:`[0, 1]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}` - - :math:`Z` - * - ``"-Z"`` - - 1 - - :math:`[0, 1]` - - :math:`\begin{bmatrix} -1 & 0 \\ 0 & 1 \end{bmatrix}` - - :math:`-Z` - - Args: - array (bool): return a Numpy array if True, otherwise - return a list (Default: False). - - Returns: - list or array: The rows of the StabilizerTable in label form. - """ - ret = np.zeros(self.size, dtype=f" list: - r"""Convert to a list or array of Stabilizer matrices. - - For large StabilizerTables converting using the ``array=True`` - kwarg will be more efficient since it allocates memory for the full - rank-3 Numpy array of matrices in advance. - - .. list-table:: Stabilizer Representations - :header-rows: 1 - - * - Label - - Phase - - Symplectic - - Matrix - - Pauli - * - ``"+I"`` - - 0 - - :math:`[0, 0]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}` - - :math:`I` - * - ``"-I"`` - - 1 - - :math:`[0, 0]` - - :math:`\begin{bmatrix} -1 & 0 \\ 0 & -1 \end{bmatrix}` - - :math:`-I` - * - ``"X"`` - - 0 - - :math:`[1, 0]` - - :math:`\begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix}` - - :math:`X` - * - ``"-X"`` - - 1 - - :math:`[1, 0]` - - :math:`\begin{bmatrix} 0 & -1 \\ -1 & 0 \end{bmatrix}` - - :math:`-X` - * - ``"Y"`` - - 0 - - :math:`[1, 1]` - - :math:`\begin{bmatrix} 0 & 1 \\ -1 & 0 \end{bmatrix}` - - :math:`iY` - * - ``"-Y"`` - - 1 - - :math:`[1, 1]` - - :math:`\begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix}` - - :math:`-iY` - * - ``"Z"`` - - 0 - - :math:`[0, 1]` - - :math:`\begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}` - - :math:`Z` - * - ``"-Z"`` - - 1 - - :math:`[0, 1]` - - :math:`\begin{bmatrix} -1 & 0 \\ 0 & 1 \end{bmatrix}` - - :math:`-Z` - - Args: - sparse (bool): if True return sparse CSR matrices, otherwise - return dense Numpy arrays (Default: False). - array (bool): return as rank-3 numpy array if True, otherwise - return a list of Numpy arrays (Default: False). - - Returns: - list: A list of dense Pauli matrices if `array=False` and `sparse=False`. - list: A list of sparse Pauli matrices if `array=False` and `sparse=True`. - array: A dense rank-3 array of Pauli matrices if `array=True`. - """ - if not array: - # We return a list of Numpy array matrices - return [ - self._to_matrix(pauli, phase, sparse=sparse) - for pauli, phase in zip(self._array, self._phase) - ] - # For efficiency we also allow returning a single rank-3 - # array where first index is the Pauli row, and second two - # indices are the matrix indices - dim = 2**self.num_qubits - ret = np.zeros((self.size, dim, dim), dtype=float) - for i in range(self.size): - ret[i] = self._to_matrix(self._array[i], self._phase[i]) - return ret - - @staticmethod - def _from_label(label): - """Return the symplectic representation of a Pauli stabilizer string""" - # Check if first character is '+' or '-' - phase = False - if label[0] in ["-", "+"]: - phase = label[0] == "-" - label = label[1:] - return PauliTable._from_label(label), phase - - @staticmethod - def _to_label(pauli, phase): - """Return the Pauli stabilizer string from symplectic representation.""" - # pylint: disable=arguments-differ - # Cast in symplectic representation - # This should avoid a copy if the pauli is already a row - # in the symplectic table - label = PauliTable._to_label(pauli) - if phase: - return "-" + label - return "+" + label - - @staticmethod - def _to_matrix(pauli, phase, sparse=False): - """Return the Pauli stabilizer matrix from symplectic representation. - - Args: - pauli (array): symplectic Pauli vector. - phase (bool): the phase value for the Pauli. - sparse (bool): if True return a sparse CSR matrix, otherwise - return a dense Numpy array (Default: False). - - Returns: - array: if sparse=False. - csr_matrix: if sparse=True. - """ - mat = PauliTable._to_matrix(pauli, sparse=sparse, real_valued=True) - if phase: - mat *= -1 - return mat - - # --------------------------------------------------------------------- - # Custom Iterators - # --------------------------------------------------------------------- - - def label_iter(self): - """Return a label representation iterator. - - This is a lazy iterator that converts each row into the string - label only as it is used. To convert the entire table to labels use - the :meth:`to_labels` method. - - Returns: - LabelIterator: label iterator object for the StabilizerTable. - """ - - class LabelIterator(CustomIterator): - """Label representation iteration and item access.""" - - def __repr__(self): - return f"" - - def __getitem__(self, key): - return self.obj._to_label(self.obj.array[key], self.obj.phase[key]) - - return LabelIterator(self) - - def matrix_iter(self, sparse: bool = False): - """Return a matrix representation iterator. - - This is a lazy iterator that converts each row into the Pauli matrix - representation only as it is used. To convert the entire table to - matrices use the :meth:`to_matrix` method. - - Args: - sparse (bool): optionally return sparse CSR matrices if True, - otherwise return Numpy array matrices - (Default: False) - - Returns: - MatrixIterator: matrix iterator object for the StabilizerTable. - """ - - class MatrixIterator(CustomIterator): - """Matrix representation iteration and item access.""" - - def __repr__(self): - return f"" - - def __getitem__(self, key): - return self.obj._to_matrix(self.obj.array[key], self.obj.phase[key], sparse=sparse) - - return MatrixIterator(self) - - -# Update docstrings for API docs -generate_apidocs(StabilizerTable) diff --git a/qiskit/quantum_info/random.py b/qiskit/quantum_info/random.py index ef648446899c..eb4ae9271226 100644 --- a/qiskit/quantum_info/random.py +++ b/qiskit/quantum_info/random.py @@ -20,7 +20,6 @@ random_hermitian, random_pauli, random_pauli_list, - random_pauli_table, random_quantum_channel, random_unitary, ) diff --git a/qiskit/test/base.py b/qiskit/test/base.py index 04cd0f1fafe0..588ca89434a0 100644 --- a/qiskit/test/base.py +++ b/qiskit/test/base.py @@ -229,7 +229,6 @@ def setUpClass(cls): r"The DerivativeBase.parameter_expression_grad method.*", r"The property ``qiskit\.circuit\.bit\.Bit\.(register|index)`` is deprecated.*", r"The CXDirection pass has been deprecated", - r"The pauli_basis function with PauliTable.*", # Caused by internal scikit-learn scipy usage r"The 'sym_pos' keyword is deprecated and should be replaced by using", # jupyter_client 7.4.8 uses deprecated shims in pyzmq that raise warnings with pyzmq 25. diff --git a/releasenotes/notes/remove-deprecated-in-quantum-info-0f9bd2b0c093307d.yaml b/releasenotes/notes/remove-deprecated-in-quantum-info-0f9bd2b0c093307d.yaml new file mode 100644 index 000000000000..a49cf58be8fb --- /dev/null +++ b/releasenotes/notes/remove-deprecated-in-quantum-info-0f9bd2b0c093307d.yaml @@ -0,0 +1,7 @@ +--- +upgrade: + - | + The classes ``qiskit.quantum_info.PauliTable`` and `qiskit.quantum_info.StabilizerTable` + are removed. The function ``random_pauli_table`` is also removed. + They were deprecated in Qiskit 0.43 (with Terra 0.24), released in May 2023. + Instead, you should use :class:`.PauliList` and :func:`.random_pauli_list`. diff --git a/test/python/opflow/test_pauli_sum_op.py b/test/python/opflow/test_pauli_sum_op.py index 4889b9ca9437..7b97756ae3a6 100644 --- a/test/python/opflow/test_pauli_sum_op.py +++ b/test/python/opflow/test_pauli_sum_op.py @@ -15,9 +15,9 @@ import unittest from itertools import product from test.python.opflow import QiskitOpflowTestCase -from ddt import ddt, data, unpack import numpy as np +from ddt import data, ddt, unpack from scipy.sparse import csr_matrix from sympy import Symbol @@ -31,15 +31,15 @@ I, One, OperatorStateFn, + OpflowError, PauliSumOp, SummedOp, X, Y, Z, Zero, - OpflowError, ) -from qiskit.quantum_info import Pauli, PauliTable, SparsePauliOp +from qiskit.quantum_info import Pauli, PauliList, SparsePauliOp @ddt @@ -316,9 +316,9 @@ def test_matrix_iter(self): """Test PauliSumOp dense matrix_iter method.""" labels = ["III", "IXI", "IYY", "YIZ", "XYZ", "III"] coeffs = np.array([1, 2, 3, 4, 5, 6]) - table = PauliTable.from_labels(labels) + paulis = PauliList(labels) coeff = 10 - op = PauliSumOp(SparsePauliOp(table, coeffs), coeff) + op = PauliSumOp(SparsePauliOp(paulis, coeffs), coeff) for idx, i in enumerate(op.matrix_iter()): self.assertTrue(np.array_equal(i, coeff * coeffs[idx] * Pauli(labels[idx]).to_matrix())) @@ -327,8 +327,8 @@ def test_matrix_iter_sparse(self): labels = ["III", "IXI", "IYY", "YIZ", "XYZ", "III"] coeffs = np.array([1, 2, 3, 4, 5, 6]) coeff = 10 - table = PauliTable.from_labels(labels) - op = PauliSumOp(SparsePauliOp(table, coeffs), coeff) + paulis = PauliList(labels) + op = PauliSumOp(SparsePauliOp(paulis, coeffs), coeff) for idx, i in enumerate(op.matrix_iter(sparse=True)): self.assertTrue( np.array_equal(i.toarray(), coeff * coeffs[idx] * Pauli(labels[idx]).to_matrix()) diff --git a/test/python/quantum_info/operators/symplectic/test_clifford.py b/test/python/quantum_info/operators/symplectic/test_clifford.py index 4dbde8a36e34..76cd9463f00e 100644 --- a/test/python/quantum_info/operators/symplectic/test_clifford.py +++ b/test/python/quantum_info/operators/symplectic/test_clifford.py @@ -244,20 +244,6 @@ def test_append_1_qubit_gate(self): with self.subTest(msg="append gate %s" % gate_name): cliff = Clifford([[1, 0], [0, 1]]) cliff = _append_operation(cliff, gate_name, [0]) - with self.assertWarns(DeprecationWarning): - value_table = cliff.table._array - value_phase = cliff.table._phase - value_stabilizer = cliff.stabilizer.to_labels() - value_destabilizer = cliff.destabilizer.to_labels() - self.assertTrue(np.all(np.array(value_table == target_table[gate_name]))) - self.assertTrue(np.all(np.array(value_phase == target_phase[gate_name]))) - self.assertTrue( - np.all(np.array(value_stabilizer == [target_stabilizer[gate_name]])) - ) - self.assertTrue( - np.all(np.array(value_destabilizer == [target_destabilizer[gate_name]])) - ) - # New methods value_table = cliff.tableau[:, :-1] value_phase = cliff.phase value_stabilizer = cliff.to_labels(mode="S") diff --git a/test/python/quantum_info/operators/symplectic/test_pauli_list.py b/test/python/quantum_info/operators/symplectic/test_pauli_list.py index 63e079e55e80..c856112a196f 100644 --- a/test/python/quantum_info/operators/symplectic/test_pauli_list.py +++ b/test/python/quantum_info/operators/symplectic/test_pauli_list.py @@ -39,8 +39,6 @@ Operator, Pauli, PauliList, - PauliTable, - StabilizerTable, ) from qiskit.quantum_info.random import random_clifford, random_pauli_list from qiskit.test import QiskitTestCase @@ -215,34 +213,6 @@ def test_list_init(self): value[0] = "-iII" self.assertEqual(value, target) - def test_pauli_table_init(self): - """Test table initialization.""" - with self.subTest(msg="PauliTable"): - target = PauliTable.from_labels(["XI", "IX", "IZ"]) - value = PauliList(target) - self.assertEqual(value, target) - - with self.subTest(msg="PauliTable no copy"): - target = PauliTable.from_labels(["XI", "IX", "IZ"]) - value = PauliList(target) - value[0] = "II" - self.assertEqual(value, target) - - def test_stabilizer_table_init(self): - """Test table initialization.""" - with self.subTest(msg="PauliTable"): - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["+II", "-XZ"]) - value = PauliList(target) - self.assertEqual(value, target) - - with self.subTest(msg="PauliTable no copy"): - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["+YY", "-XZ", "XI"]) - value = PauliList(target) - value[0] = "II" - self.assertEqual(value, target) - def test_init_from_settings(self): """Test initializing from the settings dictionary.""" pauli_list = PauliList(["IX", "-iYZ", "YY"]) diff --git a/test/python/quantum_info/operators/symplectic/test_pauli_table.py b/test/python/quantum_info/operators/symplectic/test_pauli_table.py deleted file mode 100644 index 69fb9d96f4c5..000000000000 --- a/test/python/quantum_info/operators/symplectic/test_pauli_table.py +++ /dev/null @@ -1,1570 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017, 2023. -# -# 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. - -"""Tests for PauliTable class.""" - -import unittest -from test import combine - -import numpy as np -from ddt import ddt -from scipy.sparse import csr_matrix - -from qiskit import QiskitError -from qiskit.quantum_info.operators.symplectic import PauliTable -from qiskit.test import QiskitTestCase - - -def pauli_mat(label): - """Return Pauli matrix from a Pauli label""" - mat = np.eye(1, dtype=complex) - for i in label: - if i == "I": - mat = np.kron(mat, np.eye(2, dtype=complex)) - elif i == "X": - mat = np.kron(mat, np.array([[0, 1], [1, 0]], dtype=complex)) - elif i == "Y": - mat = np.kron(mat, np.array([[0, -1j], [1j, 0]], dtype=complex)) - elif i == "Z": - mat = np.kron(mat, np.array([[1, 0], [0, -1]], dtype=complex)) - else: - raise QiskitError(f"Invalid Pauli string {i}") - return mat - - -class TestPauliTableInit(QiskitTestCase): - """Tests for PauliTable initialization.""" - - def test_array_init(self): - """Test array initialization.""" - # Matrix array initialization - with self.subTest(msg="bool array"): - target = np.array([[False, False], [True, True]]) - with self.assertWarns(DeprecationWarning): - value = PauliTable(target)._array - self.assertTrue(np.all(value == target)) - - with self.subTest(msg="bool array no copy"): - target = np.array([[False, True], [True, True]]) - with self.assertWarns(DeprecationWarning): - value = PauliTable(target)._array - value[0, 0] = not value[0, 0] - self.assertTrue(np.all(value == target)) - - with self.subTest(msg="bool array raises"): - array = np.array([[False, False, False], [True, True, True]]) - with self.assertWarns(DeprecationWarning): - self.assertRaises(QiskitError, PauliTable, array) - - def test_vector_init(self): - """Test vector initialization.""" - # Vector array initialization - with self.subTest(msg="bool vector"): - target = np.array([False, False, False, False]) - with self.assertWarns(DeprecationWarning): - value = PauliTable(target)._array - self.assertTrue(np.all(value == target)) - - with self.subTest(msg="bool vector no copy"): - target = np.array([False, True, True, False]) - with self.assertWarns(DeprecationWarning): - value = PauliTable(target)._array - value[0, 0] = not value[0, 0] - self.assertTrue(np.all(value == target)) - - def test_string_init(self): - """Test string initialization.""" - # String initialization - with self.subTest(msg='str init "I"'): - with self.assertWarns(DeprecationWarning): - value = PauliTable("I")._array - target = np.array([[False, False]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "X"'): - with self.assertWarns(DeprecationWarning): - value = PauliTable("X")._array - target = np.array([[True, False]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "Y"'): - with self.assertWarns(DeprecationWarning): - value = PauliTable("Y")._array - target = np.array([[True, True]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "Z"'): - with self.assertWarns(DeprecationWarning): - value = PauliTable("Z")._array - target = np.array([[False, True]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "IX"'): - with self.assertWarns(DeprecationWarning): - value = PauliTable("IX")._array - target = np.array([[True, False, False, False]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "XI"'): - with self.assertWarns(DeprecationWarning): - value = PauliTable("XI")._array - target = np.array([[False, True, False, False]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "YZ"'): - with self.assertWarns(DeprecationWarning): - value = PauliTable("YZ")._array - target = np.array([[False, True, True, True]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "XIZ"'): - with self.assertWarns(DeprecationWarning): - value = PauliTable("XIZ")._array - target = np.array([[False, False, True, True, False, False]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - def test_table_init(self): - """Test table initialization.""" - # Pauli Table initialization - with self.subTest(msg="PauliTable"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["XI", "IX", "IZ"]) - value = PauliTable(target) - self.assertEqual(value, target) - - with self.subTest(msg="PauliTable no copy"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["XI", "IX", "IZ"]) - value = PauliTable(target) - value[0] = "II" - self.assertEqual(value, target) - - -class TestPauliTableProperties(QiskitTestCase): - """Tests for PauliTable properties.""" - - def test_array_propertiy(self): - """Test array property""" - - with self.subTest(msg="array"): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable("II") - array = np.zeros([2, 4], dtype=bool) - self.assertTrue(np.all(pauli.array == array)) - - with self.subTest(msg="set array"): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable("XX") - array = np.zeros([1, 4], dtype=bool) - pauli.array = array - self.assertTrue(np.all(pauli.array == array)) - - with self.subTest(msg="set array raises"): - - def set_array_raise(): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable("XXX") - pauli.array = np.eye(4) - return pauli - - self.assertRaises(ValueError, set_array_raise) - - def test_x_propertiy(self): - """Test X property""" - with self.subTest(msg="X"): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["XI", "IZ", "YY"]) - array = np.array([[False, True], [False, False], [True, True]], dtype=bool) - self.assertTrue(np.all(pauli.X == array)) - - with self.subTest(msg="set X"): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["XI", "IZ"]) - val = np.array([[False, False], [True, True]], dtype=bool) - pauli.X = val - with self.assertWarns(DeprecationWarning): - self.assertEqual(pauli, PauliTable.from_labels(["II", "XY"])) - - with self.subTest(msg="set X raises"): - - def set_x(): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["XI", "IZ"]) - val = np.array([[False, False, False], [True, True, True]], dtype=bool) - pauli.X = val - return pauli - - self.assertRaises(Exception, set_x) - - def test_z_propertiy(self): - """Test Z property""" - with self.subTest(msg="Z"): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["XI", "IZ", "YY"]) - array = np.array([[False, False], [True, False], [True, True]], dtype=bool) - self.assertTrue(np.all(pauli.Z == array)) - - with self.subTest(msg="set Z"): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["XI", "IZ"]) - val = np.array([[False, False], [True, True]], dtype=bool) - pauli.Z = val - with self.assertWarns(DeprecationWarning): - self.assertEqual(pauli, PauliTable.from_labels(["XI", "ZZ"])) - - with self.subTest(msg="set Z raises"): - - def set_z(): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["XI", "IZ"]) - val = np.array([[False, False, False], [True, True, True]], dtype=bool) - pauli.Z = val - return pauli - - self.assertRaises(Exception, set_z) - - def test_shape_propertiy(self): - """Test shape property""" - shape = (3, 8) - with self.assertWarns(DeprecationWarning): - pauli = PauliTable(np.zeros(shape)) - self.assertEqual(pauli.shape, shape) - - def test_size_propertiy(self): - """Test size property""" - with self.subTest(msg="size"): - for j in range(1, 10): - shape = (j, 8) - with self.assertWarns(DeprecationWarning): - pauli = PauliTable(np.zeros(shape)) - self.assertEqual(pauli.size, j) - - def test_n_qubit_propertiy(self): - """Test n_qubit property""" - with self.subTest(msg="num_qubits"): - for j in range(1, 10): - shape = (5, 2 * j) - with self.assertWarns(DeprecationWarning): - pauli = PauliTable(np.zeros(shape)) - self.assertEqual(pauli.num_qubits, j) - - def test_eq(self): - """Test __eq__ method.""" - with self.assertWarns(DeprecationWarning): - pauli1 = PauliTable.from_labels(["II", "XI"]) - pauli2 = PauliTable.from_labels(["XI", "II"]) - self.assertEqual(pauli1, pauli1) - self.assertNotEqual(pauli1, pauli2) - - def test_len_methods(self): - """Test __len__ method.""" - for j in range(1, 10): - labels = j * ["XX"] - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(labels) - self.assertEqual(len(pauli), j) - - def test_add_methods(self): - """Test __add__ method.""" - labels1 = ["XXI", "IXX"] - labels2 = ["XXI", "ZZI", "ZYZ"] - with self.assertWarns(DeprecationWarning): - pauli1 = PauliTable.from_labels(labels1) - pauli2 = PauliTable.from_labels(labels2) - target = PauliTable.from_labels(labels1 + labels2) - self.assertEqual(target, pauli1 + pauli2) - - def test_add_qargs(self): - """Test add method with qargs.""" - with self.assertWarns(DeprecationWarning): - pauli1 = PauliTable.from_labels(["IIII", "YYYY"]) - pauli2 = PauliTable.from_labels(["XY", "YZ"]) - - with self.subTest(msg="qargs=[0, 1]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IIII", "YYYY", "IIXY", "IIYZ"]) - self.assertEqual(pauli1 + pauli2([0, 1]), target) - - with self.subTest(msg="qargs=[0, 3]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IIII", "YYYY", "XIIY", "YIIZ"]) - self.assertEqual(pauli1 + pauli2([0, 3]), target) - - with self.subTest(msg="qargs=[2, 1]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IIII", "YYYY", "IYXI", "IZYI"]) - self.assertEqual(pauli1 + pauli2([2, 1]), target) - - with self.subTest(msg="qargs=[3, 1]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IIII", "YYYY", "YIXI", "ZIYI"]) - self.assertEqual(pauli1 + pauli2([3, 1]), target) - - def test_getitem_methods(self): - """Test __getitem__ method.""" - with self.subTest(msg="__getitem__ single"): - labels = ["XI", "IY"] - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(labels) - self.assertEqual(pauli[0], PauliTable(labels[0])) - self.assertEqual(pauli[1], PauliTable(labels[1])) - - with self.subTest(msg="__getitem__ array"): - labels = np.array(["XI", "IY", "IZ", "XY", "ZX"]) - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(labels) - inds = [0, 3] - with self.assertWarns(DeprecationWarning): - self.assertEqual(pauli[inds], PauliTable.from_labels(labels[inds])) - inds = np.array([4, 1]) - with self.assertWarns(DeprecationWarning): - self.assertEqual(pauli[inds], PauliTable.from_labels(labels[inds])) - - with self.subTest(msg="__getitem__ slice"): - labels = np.array(["XI", "IY", "IZ", "XY", "ZX"]) - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(labels) - self.assertEqual(pauli[:], pauli) - with self.assertWarns(DeprecationWarning): - self.assertEqual(pauli[1:3], PauliTable.from_labels(labels[1:3])) - - def test_setitem_methods(self): - """Test __setitem__ method.""" - with self.subTest(msg="__setitem__ single"): - labels = ["XI", "IY"] - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["XI", "IY"]) - pauli[0] = "II" - with self.assertWarns(DeprecationWarning): - self.assertEqual(pauli[0], PauliTable("II")) - pauli[1] = "XX" - with self.assertWarns(DeprecationWarning): - self.assertEqual(pauli[1], PauliTable("XX")) - - def raises_single(): - # Wrong size Pauli - pauli[0] = "XXX" - - self.assertRaises(Exception, raises_single) - - with self.subTest(msg="__setitem__ array"): - labels = np.array(["XI", "IY", "IZ"]) - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(labels) - target = PauliTable.from_labels(["II", "ZZ"]) - inds = [2, 0] - pauli[inds] = target - self.assertEqual(pauli[inds], target) - - def raises_array(): - with self.assertWarns(DeprecationWarning): - pauli[inds] = PauliTable.from_labels(["YY", "ZZ", "XX"]) - - self.assertRaises(Exception, raises_array) - - with self.subTest(msg="__setitem__ slice"): - labels = np.array(5 * ["III"]) - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(labels) - target = PauliTable.from_labels(5 * ["XXX"]) - pauli[:] = target - self.assertEqual(pauli[:], target) - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(2 * ["ZZZ"]) - pauli[1:3] = target - self.assertEqual(pauli[1:3], target) - - -class TestPauliTableLabels(QiskitTestCase): - """Tests PauliTable label representation conversions.""" - - def test_from_labels_1q(self): - """Test 1-qubit from_labels method.""" - labels = ["I", "Z", "Z", "X", "Y"] - array = np.array( - [[False, False], [False, True], [False, True], [True, False], [True, True]], dtype=bool - ) - with self.assertWarns(DeprecationWarning): - target = PauliTable(array) - value = PauliTable.from_labels(labels) - self.assertEqual(target, value) - - def test_from_labels_2q(self): - """Test 2-qubit from_labels method.""" - labels = ["II", "YY", "XZ"] - array = np.array( - [[False, False, False, False], [True, True, True, True], [False, True, True, False]], - dtype=bool, - ) - with self.assertWarns(DeprecationWarning): - target = PauliTable(array) - value = PauliTable.from_labels(labels) - self.assertEqual(target, value) - - def test_from_labels_5q(self): - """Test 5-qubit from_labels method.""" - labels = [5 * "I", 5 * "X", 5 * "Y", 5 * "Z"] - array = np.array( - [10 * [False], 5 * [True] + 5 * [False], 10 * [True], 5 * [False] + 5 * [True]], - dtype=bool, - ) - with self.assertWarns(DeprecationWarning): - target = PauliTable(array) - value = PauliTable.from_labels(labels) - self.assertEqual(target, value) - - def test_to_labels_1q(self): - """Test 1-qubit to_labels method.""" - with self.assertWarns(DeprecationWarning): - pauli = PauliTable( - np.array( - [[False, False], [False, True], [False, True], [True, False], [True, True]], - dtype=bool, - ) - ) - target = ["I", "Z", "Z", "X", "Y"] - value = pauli.to_labels() - self.assertEqual(value, target) - - def test_to_labels_1q_array(self): - """Test 1-qubit to_labels method w/ array=True.""" - with self.assertWarns(DeprecationWarning): - pauli = PauliTable( - np.array( - [[False, False], [False, True], [False, True], [True, False], [True, True]], - dtype=bool, - ) - ) - target = np.array(["I", "Z", "Z", "X", "Y"]) - value = pauli.to_labels(array=True) - self.assertTrue(np.all(value == target)) - - def test_labels_round_trip(self): - """Test from_labels and to_labels round trip.""" - target = ["III", "IXZ", "XYI", "ZZZ"] - with self.assertWarns(DeprecationWarning): - value = PauliTable.from_labels(target).to_labels() - self.assertEqual(value, target) - - def test_labels_round_trip_array(self): - """Test from_labels and to_labels round trip w/ array=True.""" - labels = ["III", "IXZ", "XYI", "ZZZ"] - target = np.array(labels) - with self.assertWarns(DeprecationWarning): - value = PauliTable.from_labels(labels).to_labels(array=True) - self.assertTrue(np.all(value == target)) - - -class TestPauliTableMatrix(QiskitTestCase): - """Tests PauliTable matrix representation conversions.""" - - def test_to_matrix_1q(self): - """Test 1-qubit to_matrix method.""" - labels = ["X", "I", "Z", "Y"] - targets = [pauli_mat(i) for i in labels] - with self.assertWarns(DeprecationWarning): - values = PauliTable.from_labels(labels).to_matrix() - self.assertTrue(isinstance(values, list)) - for target, value in zip(targets, values): - self.assertTrue(np.all(value == target)) - - def test_to_matrix_1q_array(self): - """Test 1-qubit to_matrix method w/ array=True.""" - labels = ["Z", "I", "Y", "X"] - target = np.array([pauli_mat(i) for i in labels]) - with self.assertWarns(DeprecationWarning): - value = PauliTable.from_labels(labels).to_matrix(array=True) - self.assertTrue(isinstance(value, np.ndarray)) - self.assertTrue(np.all(value == target)) - - def test_to_matrix_1q_sparse(self): - """Test 1-qubit to_matrix method w/ sparse=True.""" - labels = ["X", "I", "Z", "Y"] - targets = [pauli_mat(i) for i in labels] - with self.assertWarns(DeprecationWarning): - values = PauliTable.from_labels(labels).to_matrix(sparse=True) - for mat, targ in zip(values, targets): - self.assertTrue(isinstance(mat, csr_matrix)) - self.assertTrue(np.all(targ == mat.toarray())) - - def test_to_matrix_2q(self): - """Test 2-qubit to_matrix method.""" - labels = ["IX", "YI", "II", "ZZ"] - targets = [pauli_mat(i) for i in labels] - with self.assertWarns(DeprecationWarning): - values = PauliTable.from_labels(labels).to_matrix() - self.assertTrue(isinstance(values, list)) - for target, value in zip(targets, values): - self.assertTrue(np.all(value == target)) - - def test_to_matrix_2q_array(self): - """Test 2-qubit to_matrix method w/ array=True.""" - labels = ["ZZ", "XY", "YX", "IZ"] - target = np.array([pauli_mat(i) for i in labels]) - with self.assertWarns(DeprecationWarning): - value = PauliTable.from_labels(labels).to_matrix(array=True) - self.assertTrue(isinstance(value, np.ndarray)) - self.assertTrue(np.all(value == target)) - - def test_to_matrix_2q_sparse(self): - """Test 2-qubit to_matrix method w/ sparse=True.""" - labels = ["IX", "II", "ZY", "YZ"] - targets = [pauli_mat(i) for i in labels] - with self.assertWarns(DeprecationWarning): - values = PauliTable.from_labels(labels).to_matrix(sparse=True) - for mat, targ in zip(values, targets): - self.assertTrue(isinstance(mat, csr_matrix)) - self.assertTrue(np.all(targ == mat.toarray())) - - def test_to_matrix_5q(self): - """Test 5-qubit to_matrix method.""" - labels = ["IXIXI", "YZIXI", "IIXYZ"] - targets = [pauli_mat(i) for i in labels] - with self.assertWarns(DeprecationWarning): - values = PauliTable.from_labels(labels).to_matrix() - self.assertTrue(isinstance(values, list)) - for target, value in zip(targets, values): - self.assertTrue(np.all(value == target)) - - def test_to_matrix_5q_sparse(self): - """Test 5-qubit to_matrix method w/ sparse=True.""" - labels = ["XXXYY", "IXIZY", "ZYXIX"] - targets = [pauli_mat(i) for i in labels] - with self.assertWarns(DeprecationWarning): - values = PauliTable.from_labels(labels).to_matrix(sparse=True) - for mat, targ in zip(values, targets): - self.assertTrue(isinstance(mat, csr_matrix)) - self.assertTrue(np.all(targ == mat.toarray())) - - -class TestPauliTableIteration(QiskitTestCase): - """Tests for PauliTable iterators class.""" - - def test_enumerate(self): - """Test enumerate with PauliTable.""" - labels = ["III", "IXI", "IYY", "YIZ", "XYZ", "III"] - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(labels) - for idx, i in enumerate(pauli): - with self.assertWarns(DeprecationWarning): - self.assertEqual(i, PauliTable(labels[idx])) - - def test_iter(self): - """Test iter with PauliTable.""" - labels = ["III", "IXI", "IYY", "YIZ", "XYZ", "III"] - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(labels) - for idx, i in enumerate(iter(pauli)): - with self.assertWarns(DeprecationWarning): - self.assertEqual(i, PauliTable(labels[idx])) - - def test_zip(self): - """Test zip with PauliTable.""" - labels = ["III", "IXI", "IYY", "YIZ", "XYZ", "III"] - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(labels) - for label, i in zip(labels, pauli): - with self.assertWarns(DeprecationWarning): - self.assertEqual(i, PauliTable(label)) - - def test_label_iter(self): - """Test PauliTable label_iter method.""" - labels = ["III", "IXI", "IYY", "YIZ", "XYZ", "III"] - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(labels) - for idx, i in enumerate(pauli.label_iter()): - self.assertEqual(i, labels[idx]) - - def test_matrix_iter(self): - """Test PauliTable dense matrix_iter method.""" - labels = ["III", "IXI", "IYY", "YIZ", "XYZ", "III"] - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(labels) - for idx, i in enumerate(pauli.matrix_iter()): - self.assertTrue(np.all(i == pauli_mat(labels[idx]))) - - def test_matrix_iter_sparse(self): - """Test PauliTable sparse matrix_iter method.""" - labels = ["III", "IXI", "IYY", "YIZ", "XYZ", "III"] - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(labels) - for idx, i in enumerate(pauli.matrix_iter(sparse=True)): - self.assertTrue(isinstance(i, csr_matrix)) - self.assertTrue(np.all(i.toarray() == pauli_mat(labels[idx]))) - - -@ddt -class TestPauliTableOperator(QiskitTestCase): - """Tests for PauliTable base operator methods.""" - - @combine(j=range(1, 10)) - def test_tensor(self, j): - """Test tensor method j={j}.""" - labels1 = ["XX", "YY"] - labels2 = [j * "I", j * "Z"] - with self.assertWarns(DeprecationWarning): - pauli1 = PauliTable.from_labels(labels1) - pauli2 = PauliTable.from_labels(labels2) - - value = pauli1.tensor(pauli2) - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels([i + j for i in labels1 for j in labels2]) - self.assertEqual(value, target) - - @combine(j=range(1, 10)) - def test_expand(self, j): - """Test expand method j={j}.""" - labels1 = ["XX", "YY"] - labels2 = [j * "I", j * "Z"] - with self.assertWarns(DeprecationWarning): - pauli1 = PauliTable.from_labels(labels1) - pauli2 = PauliTable.from_labels(labels2) - - value = pauli1.expand(pauli2) - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels([j + i for j in labels2 for i in labels1]) - self.assertEqual(value, target) - - def test_compose_1q(self): - """Test 1-qubit compose methods.""" - # Test single qubit Pauli dot products - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["I", "X", "Y", "Z"]) - - with self.subTest(msg="compose single I"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["I", "X", "Y", "Z"]) - value = pauli.compose("I") - self.assertEqual(target, value) - - with self.subTest(msg="compose single X"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["X", "I", "Z", "Y"]) - value = pauli.compose("X") - self.assertEqual(target, value) - - with self.subTest(msg="compose single Y"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["Y", "Z", "I", "X"]) - value = pauli.compose("Y") - self.assertEqual(target, value) - - with self.subTest(msg="compose single Z"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["Z", "Y", "X", "I"]) - value = pauli.compose("Z") - self.assertEqual(target, value) - - def test_dot_1q(self): - """Test 1-qubit dot method.""" - # Test single qubit Pauli dot products - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["I", "X", "Y", "Z"]) - - with self.subTest(msg="dot single I"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["I", "X", "Y", "Z"]) - value = pauli.dot("I") - self.assertEqual(target, value) - - with self.subTest(msg="dot single X"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["X", "I", "Z", "Y"]) - value = pauli.dot("X") - self.assertEqual(target, value) - - with self.subTest(msg="dot single Y"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["Y", "Z", "I", "X"]) - value = pauli.dot("Y") - self.assertEqual(target, value) - - with self.subTest(msg="dot single Z"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["Z", "Y", "X", "I"]) - value = pauli.dot("Z") - self.assertEqual(target, value) - - def test_qargs_compose_1q(self): - """Test 1-qubit compose method with qargs.""" - - with self.assertWarns(DeprecationWarning): - pauli1 = PauliTable.from_labels(["III", "XXX"]) - pauli2 = PauliTable("Z") - - with self.subTest(msg="compose 1-qubit qargs=[0]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IIZ", "XXY"]) - value = pauli1.compose(pauli2, qargs=[0]) - self.assertEqual(value, target) - - with self.subTest(msg="compose 1-qubit qargs=[1]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IZI", "XYX"]) - value = pauli1.compose(pauli2, qargs=[1]) - self.assertEqual(value, target) - - with self.subTest(msg="compose 1-qubit qargs=[2]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["ZII", "YXX"]) - value = pauli1.compose(pauli2, qargs=[2]) - self.assertEqual(value, target) - - def test_qargs_dot_1q(self): - """Test 1-qubit dot method with qargs.""" - - with self.assertWarns(DeprecationWarning): - pauli1 = PauliTable.from_labels(["III", "XXX"]) - pauli2 = PauliTable("Z") - - with self.subTest(msg="dot 1-qubit qargs=[0]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IIZ", "XXY"]) - value = pauli1.dot(pauli2, qargs=[0]) - self.assertEqual(value, target) - - with self.subTest(msg="dot 1-qubit qargs=[1]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IZI", "XYX"]) - value = pauli1.dot(pauli2, qargs=[1]) - self.assertEqual(value, target) - - with self.subTest(msg="dot 1-qubit qargs=[2]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["ZII", "YXX"]) - value = pauli1.dot(pauli2, qargs=[2]) - self.assertEqual(value, target) - - def test_qargs_compose_2q(self): - """Test 2-qubit compose method with qargs.""" - - with self.assertWarns(DeprecationWarning): - pauli1 = PauliTable.from_labels(["III", "XXX"]) - pauli2 = PauliTable("ZY") - - with self.subTest(msg="compose 2-qubit qargs=[0, 1]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IZY", "XYZ"]) - value = pauli1.compose(pauli2, qargs=[0, 1]) - self.assertEqual(value, target) - - with self.subTest(msg="compose 2-qubit qargs=[1, 0]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IYZ", "XZY"]) - value = pauli1.compose(pauli2, qargs=[1, 0]) - self.assertEqual(value, target) - - with self.subTest(msg="compose 2-qubit qargs=[0, 2]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["ZIY", "YXZ"]) - value = pauli1.compose(pauli2, qargs=[0, 2]) - self.assertEqual(value, target) - - with self.subTest(msg="compose 2-qubit qargs=[2, 0]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["YIZ", "ZXY"]) - value = pauli1.compose(pauli2, qargs=[2, 0]) - self.assertEqual(value, target) - - def test_qargs_dot_2q(self): - """Test 2-qubit dot method with qargs.""" - - with self.assertWarns(DeprecationWarning): - pauli1 = PauliTable.from_labels(["III", "XXX"]) - pauli2 = PauliTable("ZY") - - with self.subTest(msg="dot 2-qubit qargs=[0, 1]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IZY", "XYZ"]) - value = pauli1.dot(pauli2, qargs=[0, 1]) - self.assertEqual(value, target) - - with self.subTest(msg="dot 2-qubit qargs=[1, 0]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IYZ", "XZY"]) - value = pauli1.dot(pauli2, qargs=[1, 0]) - self.assertEqual(value, target) - - with self.subTest(msg="dot 2-qubit qargs=[0, 2]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["ZIY", "YXZ"]) - value = pauli1.dot(pauli2, qargs=[0, 2]) - self.assertEqual(value, target) - - with self.subTest(msg="dot 2-qubit qargs=[2, 0]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["YIZ", "ZXY"]) - value = pauli1.dot(pauli2, qargs=[2, 0]) - self.assertEqual(value, target) - - def test_qargs_compose_3q(self): - """Test 3-qubit compose method with qargs.""" - - with self.assertWarns(DeprecationWarning): - pauli1 = PauliTable.from_labels(["III", "XXX"]) - pauli2 = PauliTable("XYZ") - - with self.subTest(msg="compose 3-qubit qargs=None"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["XYZ", "IZY"]) - value = pauli1.compose(pauli2) - self.assertEqual(value, target) - - with self.subTest(msg="compose 3-qubit qargs=[0, 1, 2]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["XYZ", "IZY"]) - value = pauli1.compose(pauli2, qargs=[0, 1, 2]) - self.assertEqual(value, target) - - with self.subTest(msg="compose 3-qubit qargs=[2, 1, 0]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["ZYX", "YZI"]) - value = pauli1.compose(pauli2, qargs=[2, 1, 0]) - self.assertEqual(value, target) - - with self.subTest(msg="compose 3-qubit qargs=[1, 0, 2]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["XZY", "IYZ"]) - value = pauli1.compose(pauli2, qargs=[1, 0, 2]) - self.assertEqual(value, target) - - def test_qargs_dot_3q(self): - """Test 3-qubit dot method with qargs.""" - - with self.assertWarns(DeprecationWarning): - pauli1 = PauliTable.from_labels(["III", "XXX"]) - pauli2 = PauliTable("XYZ") - - with self.subTest(msg="dot 3-qubit qargs=None"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["XYZ", "IZY"]) - value = pauli1.dot(pauli2, qargs=[0, 1, 2]) - self.assertEqual(value, target) - - with self.subTest(msg="dot 3-qubit qargs=[0, 1, 2]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["XYZ", "IZY"]) - value = pauli1.dot(pauli2, qargs=[0, 1, 2]) - self.assertEqual(value, target) - - with self.subTest(msg="dot 3-qubit qargs=[2, 1, 0]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["ZYX", "YZI"]) - value = pauli1.dot(pauli2, qargs=[2, 1, 0]) - self.assertEqual(value, target) - - with self.subTest(msg="dot 3-qubit qargs=[1, 0, 2]"): - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["XZY", "IYZ"]) - value = pauli1.dot(pauli2, qargs=[1, 0, 2]) - self.assertEqual(value, target) - - -class TestPauliTableMethods(QiskitTestCase): - """Tests for PauliTable utility methods class.""" - - def test_sort(self): - """Test sort method.""" - with self.subTest(msg="1 qubit standard order"): - unsrt = ["X", "Z", "I", "Y", "X", "Z"] - srt = ["I", "X", "X", "Y", "Z", "Z"] - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(srt) - value = PauliTable.from_labels(unsrt).sort() - self.assertEqual(target, value) - - with self.subTest(msg="1 qubit weight order"): - unsrt = ["X", "Z", "I", "Y", "X", "Z"] - srt = ["I", "X", "X", "Y", "Z", "Z"] - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(srt) - value = PauliTable.from_labels(unsrt).sort(weight=True) - self.assertEqual(target, value) - - with self.subTest(msg="2 qubit standard order"): - srt = [ - "II", - "IX", - "IY", - "IY", - "XI", - "XX", - "XY", - "XZ", - "YI", - "YX", - "YY", - "YZ", - "ZI", - "ZI", - "ZX", - "ZY", - "ZZ", - "ZZ", - ] - unsrt = srt.copy() - np.random.shuffle(unsrt) - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(srt) - value = PauliTable.from_labels(unsrt).sort() - self.assertEqual(target, value) - - with self.subTest(msg="2 qubit weight order"): - srt = [ - "II", - "IX", - "IX", - "IY", - "IZ", - "XI", - "YI", - "YI", - "ZI", - "XX", - "XX", - "XY", - "XZ", - "YX", - "YY", - "YY", - "YZ", - "ZX", - "ZX", - "ZY", - "ZZ", - ] - unsrt = srt.copy() - np.random.shuffle(unsrt) - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(srt) - value = PauliTable.from_labels(unsrt).sort(weight=True) - self.assertEqual(target, value) - - with self.subTest(msg="3 qubit standard order"): - srt = [ - "III", - "III", - "IIX", - "IIY", - "IIZ", - "IXI", - "IXX", - "IXY", - "IXZ", - "IYI", - "IYX", - "IYY", - "IYZ", - "IZI", - "IZX", - "IZY", - "IZY", - "IZZ", - "XII", - "XII", - "XIX", - "XIY", - "XIZ", - "XXI", - "XXX", - "XXY", - "XXZ", - "XYI", - "XYX", - "XYY", - "XYZ", - "XYZ", - "XZI", - "XZX", - "XZY", - "XZZ", - "YII", - "YIX", - "YIY", - "YIZ", - "YXI", - "YXX", - "YXY", - "YXZ", - "YXZ", - "YYI", - "YYX", - "YYX", - "YYY", - "YYZ", - "YZI", - "YZX", - "YZY", - "YZZ", - "ZII", - "ZIX", - "ZIY", - "ZIZ", - "ZXI", - "ZXX", - "ZXX", - "ZXY", - "ZXZ", - "ZYI", - "ZYI", - "ZYX", - "ZYY", - "ZYZ", - "ZZI", - "ZZX", - "ZZY", - "ZZZ", - ] - unsrt = srt.copy() - np.random.shuffle(unsrt) - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(srt) - value = PauliTable.from_labels(unsrt).sort() - self.assertEqual(target, value) - - with self.subTest(msg="3 qubit weight order"): - srt = [ - "III", - "IIX", - "IIY", - "IIZ", - "IXI", - "IYI", - "IZI", - "XII", - "YII", - "ZII", - "IXX", - "IXY", - "IXZ", - "IYX", - "IYY", - "IYZ", - "IZX", - "IZY", - "IZZ", - "XIX", - "XIY", - "XIZ", - "XXI", - "XYI", - "XZI", - "XZI", - "YIX", - "YIY", - "YIZ", - "YXI", - "YYI", - "YZI", - "YZI", - "ZIX", - "ZIY", - "ZIZ", - "ZXI", - "ZYI", - "ZZI", - "ZZI", - "XXX", - "XXY", - "XXZ", - "XYX", - "XYY", - "XYZ", - "XZX", - "XZY", - "XZZ", - "YXX", - "YXY", - "YXZ", - "YYX", - "YYY", - "YYZ", - "YZX", - "YZY", - "YZZ", - "ZXX", - "ZXY", - "ZXZ", - "ZYX", - "ZYY", - "ZYZ", - "ZZX", - "ZZY", - "ZZZ", - ] - unsrt = srt.copy() - np.random.shuffle(unsrt) - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(srt) - value = PauliTable.from_labels(unsrt).sort(weight=True) - self.assertEqual(target, value) - - def test_unique(self): - """Test unique method.""" - with self.subTest(msg="1 qubit"): - labels = ["X", "Z", "X", "X", "I", "Y", "I", "X", "Z", "Z", "X", "I"] - unique = ["X", "Z", "I", "Y"] - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(unique) - value = PauliTable.from_labels(labels).unique() - self.assertEqual(target, value) - - with self.subTest(msg="2 qubit"): - labels = ["XX", "IX", "XX", "II", "IZ", "ZI", "YX", "YX", "ZZ", "IX", "XI"] - unique = ["XX", "IX", "II", "IZ", "ZI", "YX", "ZZ", "XI"] - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(unique) - value = PauliTable.from_labels(labels).unique() - self.assertEqual(target, value) - - with self.subTest(msg="10 qubit"): - labels = [10 * "X", 10 * "I", 10 * "X"] - unique = [10 * "X", 10 * "I"] - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(unique) - value = PauliTable.from_labels(labels).unique() - self.assertEqual(target, value) - - def test_delete(self): - """Test delete method.""" - with self.subTest(msg="no rows"): - pauli = PauliTable.from_labels(["XX", "YY"]) - self.assertEqual(pauli.delete([]), pauli) - - with self.subTest(msg="single row"): - for j in range(1, 6): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels([j * "X", j * "Y"]) - self.assertEqual(pauli.delete(0), PauliTable(j * "Y")) - self.assertEqual(pauli.delete(1), PauliTable(j * "X")) - - with self.subTest(msg="multiple rows"): - for j in range(1, 6): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels([j * "X", j * "Y", j * "Z"]) - self.assertEqual(pauli.delete([0, 2]), PauliTable(j * "Y")) - self.assertEqual(pauli.delete([1, 2]), PauliTable(j * "X")) - self.assertEqual(pauli.delete([0, 1]), PauliTable(j * "Z")) - - with self.subTest(msg="no rows"): - pauli = PauliTable.from_labels(["XX", "YY"]) - self.assertEqual(pauli.delete([], qubit=True), pauli) - - with self.subTest(msg="single qubit"): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["IIX", "IYI", "ZII"]) - value = pauli.delete(0, qubit=True) - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["II", "IY", "ZI"]) - self.assertEqual(value, target) - value = pauli.delete(1, qubit=True) - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IX", "II", "ZI"]) - self.assertEqual(value, target) - value = pauli.delete(2, qubit=True) - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["IX", "YI", "II"]) - self.assertEqual(value, target) - - with self.subTest(msg="multiple qubits"): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["IIX", "IYI", "ZII"]) - value = pauli.delete([0, 1], qubit=True) - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["I", "I", "Z"]) - self.assertEqual(value, target) - value = pauli.delete([1, 2], qubit=True) - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["X", "I", "I"]) - self.assertEqual(value, target) - value = pauli.delete([0, 2], qubit=True) - with self.assertWarns(DeprecationWarning): - target = PauliTable.from_labels(["I", "Y", "I"]) - self.assertEqual(value, target) - - def test_insert(self): - """Test insert method.""" - # Insert single row - for j in range(1, 10): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable(j * "X") - target0 = PauliTable.from_labels([j * "I", j * "X"]) - target1 = PauliTable.from_labels([j * "X", j * "I"]) - - with self.subTest(msg=f"single row from str ({j})"): - value0 = pauli.insert(0, j * "I") - self.assertEqual(value0, target0) - value1 = pauli.insert(1, j * "I") - self.assertEqual(value1, target1) - - with self.subTest(msg=f"single row from PauliTable ({j})"): - with self.assertWarns(DeprecationWarning): - value0 = pauli.insert(0, PauliTable(j * "I")) - self.assertEqual(value0, target0) - with self.assertWarns(DeprecationWarning): - value1 = pauli.insert(1, PauliTable(j * "I")) - self.assertEqual(value1, target1) - - with self.subTest(msg=f"single row from array ({j})"): - with self.assertWarns(DeprecationWarning): - value0 = pauli.insert(0, PauliTable(j * "I").array) - self.assertEqual(value0, target0) - with self.assertWarns(DeprecationWarning): - value1 = pauli.insert(1, PauliTable(j * "I").array) - self.assertEqual(value1, target1) - - # Insert multiple rows - for j in range(1, 10): - with self.assertWarns(DeprecationWarning): - pauli = PauliTable(j * "X") - insert = PauliTable.from_labels([j * "I", j * "Y", j * "Z"]) - target0 = insert + pauli - target1 = pauli + insert - - with self.subTest(msg=f"multiple-rows from PauliTable ({j})"): - value0 = pauli.insert(0, insert) - self.assertEqual(value0, target0) - value1 = pauli.insert(1, insert) - self.assertEqual(value1, target1) - - with self.subTest(msg=f"multiple-rows from array ({j})"): - value0 = pauli.insert(0, insert.array) - self.assertEqual(value0, target0) - value1 = pauli.insert(1, insert.array) - self.assertEqual(value1, target1) - - # Insert single column - pauli = PauliTable.from_labels(["X", "Y", "Z"]) - for i in ["I", "X", "Y", "Z"]: - with self.assertWarns(DeprecationWarning): - target0 = PauliTable.from_labels(["X" + i, "Y" + i, "Z" + i]) - target1 = PauliTable.from_labels([i + "X", i + "Y", i + "Z"]) - - with self.subTest(msg="single-column single-val from str"): - value = pauli.insert(0, i, qubit=True) - self.assertEqual(value, target0) - value = pauli.insert(1, i, qubit=True) - self.assertEqual(value, target1) - - with self.subTest(msg="single-column single-val from PauliTable"): - with self.assertWarns(DeprecationWarning): - value = pauli.insert(0, PauliTable(i), qubit=True) - self.assertEqual(value, target0) - with self.assertWarns(DeprecationWarning): - value = pauli.insert(1, PauliTable(i), qubit=True) - self.assertEqual(value, target1) - - with self.subTest(msg="single-column single-val from array"): - with self.assertWarns(DeprecationWarning): - value = pauli.insert(0, PauliTable(i).array, qubit=True) - self.assertEqual(value, target0) - with self.assertWarns(DeprecationWarning): - value = pauli.insert(1, PauliTable(i).array, qubit=True) - self.assertEqual(value, target1) - - # Insert single column with multiple values - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["X", "Y", "Z"]) - for i in [("I", "X", "Y"), ("X", "Y", "Z"), ("Y", "Z", "I")]: - with self.assertWarns(DeprecationWarning): - target0 = PauliTable.from_labels(["X" + i[0], "Y" + i[1], "Z" + i[2]]) - target1 = PauliTable.from_labels([i[0] + "X", i[1] + "Y", i[2] + "Z"]) - - with self.subTest(msg="single-column multiple-vals from PauliTable"): - with self.assertWarns(DeprecationWarning): - value = pauli.insert(0, PauliTable.from_labels(i), qubit=True) - self.assertEqual(value, target0) - with self.assertWarns(DeprecationWarning): - value = pauli.insert(1, PauliTable.from_labels(i), qubit=True) - self.assertEqual(value, target1) - - with self.subTest(msg="single-column multiple-vals from array"): - with self.assertWarns(DeprecationWarning): - value = pauli.insert(0, PauliTable.from_labels(i).array, qubit=True) - self.assertEqual(value, target0) - with self.assertWarns(DeprecationWarning): - value = pauli.insert(1, PauliTable.from_labels(i).array, qubit=True) - self.assertEqual(value, target1) - - # Insert multiple columns from single - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["X", "Y", "Z"]) - for j in range(1, 5): - for i in [j * "I", j * "X", j * "Y", j * "Z"]: - with self.assertWarns(DeprecationWarning): - target0 = PauliTable.from_labels(["X" + i, "Y" + i, "Z" + i]) - target1 = PauliTable.from_labels([i + "X", i + "Y", i + "Z"]) - - with self.subTest(msg="multiple-columns single-val from str"): - value = pauli.insert(0, i, qubit=True) - self.assertEqual(value, target0) - value = pauli.insert(1, i, qubit=True) - self.assertEqual(value, target1) - - with self.subTest(msg="multiple-columns single-val from PauliTable"): - with self.assertWarns(DeprecationWarning): - value = pauli.insert(0, PauliTable(i), qubit=True) - self.assertEqual(value, target0) - with self.assertWarns(DeprecationWarning): - value = pauli.insert(1, PauliTable(i), qubit=True) - self.assertEqual(value, target1) - - with self.subTest(msg="multiple-columns single-val from array"): - with self.assertWarns(DeprecationWarning): - value = pauli.insert(0, PauliTable(i).array, qubit=True) - self.assertEqual(value, target0) - with self.assertWarns(DeprecationWarning): - value = pauli.insert(1, PauliTable(i).array, qubit=True) - self.assertEqual(value, target1) - - # Insert multiple columns multiple row values - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["X", "Y", "Z"]) - for j in range(1, 5): - for i in [ - (j * "I", j * "X", j * "Y"), - (j * "X", j * "Z", j * "Y"), - (j * "Y", j * "Z", j * "I"), - ]: - with self.assertWarns(DeprecationWarning): - target0 = PauliTable.from_labels(["X" + i[0], "Y" + i[1], "Z" + i[2]]) - target1 = PauliTable.from_labels([i[0] + "X", i[1] + "Y", i[2] + "Z"]) - - with self.subTest(msg="multiple-column multiple-vals from PauliTable"): - with self.assertWarns(DeprecationWarning): - value = pauli.insert(0, PauliTable.from_labels(i), qubit=True) - self.assertEqual(value, target0) - with self.assertWarns(DeprecationWarning): - value = pauli.insert(1, PauliTable.from_labels(i), qubit=True) - self.assertEqual(value, target1) - - with self.subTest(msg="multiple-column multiple-vals from array"): - with self.assertWarns(DeprecationWarning): - value = pauli.insert(0, PauliTable.from_labels(i).array, qubit=True) - self.assertEqual(value, target0) - with self.assertWarns(DeprecationWarning): - value = pauli.insert(1, PauliTable.from_labels(i).array, qubit=True) - self.assertEqual(value, target1) - - def test_commutes(self): - """Test commutes method.""" - # Single qubit Pauli - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["I", "X", "Y", "Z"]) - with self.subTest(msg="commutes single-Pauli I"): - value = list(pauli.commutes("I")) - target = [True, True, True, True] - self.assertEqual(value, target) - - with self.subTest(msg="commutes single-Pauli X"): - value = list(pauli.commutes("X")) - target = [True, True, False, False] - self.assertEqual(value, target) - - with self.subTest(msg="commutes single-Pauli Y"): - value = list(pauli.commutes("Y")) - target = [True, False, True, False] - self.assertEqual(value, target) - - with self.subTest(msg="commutes single-Pauli Z"): - value = list(pauli.commutes("Z")) - target = [True, False, False, True] - self.assertEqual(value, target) - - # 2-qubit Pauli - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["II", "IX", "YI", "XY", "ZZ"]) - with self.subTest(msg="commutes single-Pauli II"): - value = list(pauli.commutes("II")) - target = [True, True, True, True, True] - self.assertEqual(value, target) - - with self.subTest(msg="commutes single-Pauli IX"): - value = list(pauli.commutes("IX")) - target = [True, True, True, False, False] - self.assertEqual(value, target) - - with self.subTest(msg="commutes single-Pauli XI"): - value = list(pauli.commutes("XI")) - target = [True, True, False, True, False] - self.assertEqual(value, target) - - with self.subTest(msg="commutes single-Pauli YI"): - value = list(pauli.commutes("YI")) - target = [True, True, True, False, False] - self.assertEqual(value, target) - - with self.subTest(msg="commutes single-Pauli IY"): - value = list(pauli.commutes("IY")) - target = [True, False, True, True, False] - self.assertEqual(value, target) - - with self.subTest(msg="commutes single-Pauli XY"): - value = list(pauli.commutes("XY")) - target = [True, False, False, True, True] - self.assertEqual(value, target) - - with self.subTest(msg="commutes single-Pauli YX"): - value = list(pauli.commutes("YX")) - target = [True, True, True, True, True] - self.assertEqual(value, target) - - with self.subTest(msg="commutes single-Pauli ZZ"): - value = list(pauli.commutes("ZZ")) - target = [True, False, False, True, True] - self.assertEqual(value, target) - - def test_commutes_with_all(self): - """Test commutes_with_all method.""" - # 1-qubit - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["I", "X", "Y", "Z"]) - with self.subTest(msg="commutes_with_all [I]"): - value = list(pauli.commutes_with_all("I")) - target = [0, 1, 2, 3] - self.assertEqual(value, target) - - with self.subTest(msg="commutes_with_all [X]"): - value = list(pauli.commutes_with_all("X")) - target = [0, 1] - self.assertEqual(value, target) - - with self.subTest(msg="commutes_with_all [Y]"): - value = list(pauli.commutes_with_all("Y")) - target = [0, 2] - self.assertEqual(value, target) - - with self.subTest(msg="commutes_with_all [Z]"): - value = list(pauli.commutes_with_all("Z")) - target = [0, 3] - self.assertEqual(value, target) - - # 2-qubit Pauli - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["II", "IX", "YI", "XY", "ZZ"]) - - with self.subTest(msg="commutes_with_all [IX, YI]"): - with self.assertWarns(DeprecationWarning): - other = PauliTable.from_labels(["IX", "YI"]) - value = list(pauli.commutes_with_all(other)) - target = [0, 1, 2] - self.assertEqual(value, target) - - with self.subTest(msg="commutes_with_all [XY, ZZ]"): - with self.assertWarns(DeprecationWarning): - other = PauliTable.from_labels(["XY", "ZZ"]) - value = list(pauli.commutes_with_all(other)) - target = [0, 3, 4] - self.assertEqual(value, target) - - with self.subTest(msg="commutes_with_all [YX, ZZ]"): - with self.assertWarns(DeprecationWarning): - other = PauliTable.from_labels(["YX", "ZZ"]) - value = list(pauli.commutes_with_all(other)) - target = [0, 3, 4] - self.assertEqual(value, target) - - with self.subTest(msg="commutes_with_all [XY, YX]"): - with self.assertWarns(DeprecationWarning): - other = PauliTable.from_labels(["XY", "YX"]) - value = list(pauli.commutes_with_all(other)) - target = [0, 3, 4] - self.assertEqual(value, target) - - with self.subTest(msg="commutes_with_all [XY, IX]"): - with self.assertWarns(DeprecationWarning): - other = PauliTable.from_labels(["XY", "IX"]) - value = list(pauli.commutes_with_all(other)) - target = [0] - self.assertEqual(value, target) - - with self.subTest(msg="commutes_with_all [YX, IX]"): - with self.assertWarns(DeprecationWarning): - other = PauliTable.from_labels(["YX", "IX"]) - value = list(pauli.commutes_with_all(other)) - target = [0, 1, 2] - self.assertEqual(value, target) - - def test_anticommutes_with_all(self): - """Test anticommutes_with_all method.""" - # 1-qubit - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["I", "X", "Y", "Z"]) - with self.subTest(msg="anticommutes_with_all [I]"): - value = list(pauli.anticommutes_with_all("I")) - target = [] - self.assertEqual(value, target) - - with self.subTest(msg="antianticommutes_with_all [X]"): - value = list(pauli.anticommutes_with_all("X")) - target = [2, 3] - self.assertEqual(value, target) - - with self.subTest(msg="anticommutes_with_all [Y]"): - value = list(pauli.anticommutes_with_all("Y")) - target = [1, 3] - self.assertEqual(value, target) - - with self.subTest(msg="anticommutes_with_all [Z]"): - value = list(pauli.anticommutes_with_all("Z")) - target = [1, 2] - self.assertEqual(value, target) - - # 2-qubit Pauli - with self.assertWarns(DeprecationWarning): - pauli = PauliTable.from_labels(["II", "IX", "YI", "XY", "ZZ"]) - - with self.subTest(msg="anticommutes_with_all [IX, YI]"): - with self.assertWarns(DeprecationWarning): - other = PauliTable.from_labels(["IX", "YI"]) - value = list(pauli.anticommutes_with_all(other)) - target = [3, 4] - self.assertEqual(value, target) - - with self.subTest(msg="anticommutes_with_all [XY, ZZ]"): - with self.assertWarns(DeprecationWarning): - other = PauliTable.from_labels(["XY", "ZZ"]) - value = list(pauli.anticommutes_with_all(other)) - target = [1, 2] - self.assertEqual(value, target) - - with self.subTest(msg="anticommutes_with_all [YX, ZZ]"): - with self.assertWarns(DeprecationWarning): - other = PauliTable.from_labels(["YX", "ZZ"]) - value = list(pauli.anticommutes_with_all(other)) - target = [] - self.assertEqual(value, target) - - with self.subTest(msg="anticommutes_with_all [XY, YX]"): - with self.assertWarns(DeprecationWarning): - other = PauliTable.from_labels(["XY", "YX"]) - value = list(pauli.anticommutes_with_all(other)) - target = [] - self.assertEqual(value, target) - - with self.subTest(msg="anticommutes_with_all [XY, IX]"): - with self.assertWarns(DeprecationWarning): - other = PauliTable.from_labels(["XY", "IX"]) - value = list(pauli.anticommutes_with_all(other)) - target = [] - self.assertEqual(value, target) - - with self.subTest(msg="anticommutes_with_all [YX, IX]"): - with self.assertWarns(DeprecationWarning): - other = PauliTable.from_labels(["YX", "IX"]) - value = list(pauli.anticommutes_with_all(other)) - target = [] - self.assertEqual(value, target) - - -if __name__ == "__main__": - unittest.main() diff --git a/test/python/quantum_info/operators/symplectic/test_pauli_utils.py b/test/python/quantum_info/operators/symplectic/test_pauli_utils.py index 7ba8e2634d52..070d204ac727 100644 --- a/test/python/quantum_info/operators/symplectic/test_pauli_utils.py +++ b/test/python/quantum_info/operators/symplectic/test_pauli_utils.py @@ -11,12 +11,12 @@ # that they have been altered from the originals. -"""Tests for PauliTable utility functions.""" +"""Tests for PauliList utility functions.""" import unittest from qiskit.test import QiskitTestCase -from qiskit.quantum_info.operators.symplectic import PauliTable, pauli_basis +from qiskit.quantum_info import PauliList, pauli_basis class TestPauliBasis(QiskitTestCase): @@ -25,13 +25,13 @@ class TestPauliBasis(QiskitTestCase): def test_standard_order_1q(self): """Test 1-qubit pauli_basis function.""" labels = ["I", "X", "Y", "Z"] - target = PauliTable.from_labels(labels) + target = PauliList(labels) self.assertEqual(pauli_basis(1), target) def test_weight_order_1q(self): """Test 1-qubit pauli_basis function with weight=True.""" labels = ["I", "X", "Y", "Z"] - target = PauliTable.from_labels(labels) + target = PauliList(labels) self.assertEqual(pauli_basis(1, weight=True), target) def test_standard_order_2q(self): @@ -54,7 +54,7 @@ def test_standard_order_2q(self): "ZY", "ZZ", ] - target = PauliTable.from_labels(labels) + target = PauliList(labels) self.assertEqual(pauli_basis(2), target) def test_weight_order_2q(self): @@ -77,7 +77,7 @@ def test_weight_order_2q(self): "ZY", "ZZ", ] - target = PauliTable.from_labels(labels) + target = PauliList(labels) self.assertEqual(pauli_basis(2, weight=True), target) def test_standard_order_3q(self): @@ -148,7 +148,7 @@ def test_standard_order_3q(self): "ZZY", "ZZZ", ] - target = PauliTable.from_labels(labels) + target = PauliList(labels) self.assertEqual(pauli_basis(3), target) def test_weight_order_3q(self): @@ -219,7 +219,7 @@ def test_weight_order_3q(self): "ZZY", "ZZZ", ] - target = PauliTable.from_labels(labels) + target = PauliList(labels) self.assertEqual(pauli_basis(3, weight=True), target) diff --git a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py index df0eb0d20f79..929534d26e8f 100644 --- a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py +++ b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py @@ -22,7 +22,7 @@ from qiskit import QiskitError from qiskit.circuit import ParameterExpression, Parameter, ParameterVector from qiskit.circuit.parametertable import ParameterView -from qiskit.quantum_info.operators import Operator, Pauli, PauliList, PauliTable, SparsePauliOp +from qiskit.quantum_info.operators import Operator, Pauli, PauliList, SparsePauliOp from qiskit.test import QiskitTestCase from qiskit.circuit.library import EfficientSU2 from qiskit.primitives import BackendEstimator @@ -50,21 +50,6 @@ def pauli_mat(label): class TestSparsePauliOpInit(QiskitTestCase): """Tests for SparsePauliOp initialization.""" - def test_pauli_table_init(self): - """Test PauliTable initialization.""" - labels = ["I", "X", "Y", "Z"] - table = PauliTable.from_labels(labels) - paulis = PauliList(labels) - with self.subTest(msg="no coeffs"): - spp_op = SparsePauliOp(table) - np.testing.assert_array_equal(spp_op.coeffs, np.ones(len(labels))) - self.assertEqual(spp_op.paulis, paulis) - with self.subTest(msg="no coeffs"): - coeffs = [1, 2, 3, 4] - spp_op = SparsePauliOp(table, coeffs) - np.testing.assert_array_equal(spp_op.coeffs, coeffs) - self.assertEqual(spp_op.paulis, paulis) - def test_str_init(self): """Test str initialization.""" for label in ["IZ", "XI", "YX", "ZZ"]: diff --git a/test/python/quantum_info/operators/symplectic/test_stabilizer_table.py b/test/python/quantum_info/operators/symplectic/test_stabilizer_table.py deleted file mode 100644 index a77ff14276d7..000000000000 --- a/test/python/quantum_info/operators/symplectic/test_stabilizer_table.py +++ /dev/null @@ -1,1213 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017, 2023. -# -# 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. - -"""Tests for StabilizerTable class.""" - -import unittest - -import numpy as np -from scipy.sparse import csr_matrix - -from qiskit import QiskitError -from qiskit.quantum_info.operators.symplectic import PauliTable, StabilizerTable -from qiskit.test import QiskitTestCase - - -def stab_mat(label): - """Return stabilizer matrix from a stabilizer label""" - mat = np.eye(1, dtype=complex) - if label[0] == "-": - mat *= -1 - if label[0] in ["-", "+"]: - label = label[1:] - for i in label: - if i == "I": - mat = np.kron(mat, np.eye(2)) - elif i == "X": - mat = np.kron(mat, np.array([[0, 1], [1, 0]])) - elif i == "Y": - mat = np.kron(mat, np.array([[0, 1], [-1, 0]])) - elif i == "Z": - mat = np.kron(mat, np.array([[1, 0], [0, -1]])) - else: - raise QiskitError(f"Invalid stabilizer string {i}") - return mat - - -class TestStabilizerTableInit(QiskitTestCase): - """Tests for StabilizerTable initialization.""" - - def test_array_init(self): - """Test array initialization.""" - - with self.subTest(msg="bool array"): - target = np.array([[False, False], [True, True]]) - with self.assertWarns(DeprecationWarning): - value = StabilizerTable(target)._array - self.assertTrue(np.all(value == target)) - - with self.subTest(msg="bool array no copy"): - target = np.array([[False, True], [True, True]]) - with self.assertWarns(DeprecationWarning): - value = StabilizerTable(target)._array - value[0, 0] = not value[0, 0] - self.assertTrue(np.all(value == target)) - - with self.subTest(msg="bool array raises"): - array = np.array([[False, False, False], [True, True, True]]) - with self.assertWarns(DeprecationWarning): - self.assertRaises(QiskitError, StabilizerTable, array) - - def test_vector_init(self): - """Test vector initialization.""" - - with self.subTest(msg="bool vector"): - target = np.array([False, False, False, False]) - with self.assertWarns(DeprecationWarning): - value = StabilizerTable(target)._array - self.assertTrue(np.all(value == target)) - - with self.subTest(msg="bool vector no copy"): - target = np.array([False, True, True, False]) - with self.assertWarns(DeprecationWarning): - value = StabilizerTable(target)._array - value[0, 0] = not value[0, 0] - self.assertTrue(np.all(value == target)) - - def test_string_init(self): - """Test string initialization.""" - - with self.subTest(msg='str init "I"'): - with self.assertWarns(DeprecationWarning): - value = StabilizerTable("I")._array - target = np.array([[False, False]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "X"'): - with self.assertWarns(DeprecationWarning): - value = StabilizerTable("X")._array - target = np.array([[True, False]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "Y"'): - with self.assertWarns(DeprecationWarning): - value = StabilizerTable("Y")._array - target = np.array([[True, True]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "Z"'): - with self.assertWarns(DeprecationWarning): - value = StabilizerTable("Z")._array - target = np.array([[False, True]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "IX"'): - with self.assertWarns(DeprecationWarning): - value = StabilizerTable("IX")._array - target = np.array([[True, False, False, False]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "XI"'): - with self.assertWarns(DeprecationWarning): - value = StabilizerTable("XI")._array - target = np.array([[False, True, False, False]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "YZ"'): - with self.assertWarns(DeprecationWarning): - value = StabilizerTable("YZ")._array - target = np.array([[False, True, True, True]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - with self.subTest(msg='str init "XIZ"'): - with self.assertWarns(DeprecationWarning): - value = StabilizerTable("XIZ")._array - target = np.array([[False, False, True, True, False, False]], dtype=bool) - self.assertTrue(np.all(np.array(value == target))) - - def test_table_init(self): - """Test StabilizerTable initialization.""" - - with self.subTest(msg="StabilizerTable"): - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["XI", "IX", "IZ"]) - value = StabilizerTable(target) - self.assertEqual(value, target) - - with self.subTest(msg="StabilizerTable no copy"): - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["XI", "IX", "IZ"]) - value = StabilizerTable(target) - value[0] = "II" - self.assertEqual(value, target) - - -class TestStabilizerTableProperties(QiskitTestCase): - """Tests for StabilizerTable properties.""" - - def test_array_property(self): - """Test array property""" - - with self.subTest(msg="array"): - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable("II") - array = np.zeros([2, 4], dtype=bool) - self.assertTrue(np.all(stab.array == array)) - - with self.subTest(msg="set array"): - - def set_array(): - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable("XXX") - stab.array = np.eye(4) - return stab - - self.assertRaises(Exception, set_array) - - def test_x_property(self): - """Test X property""" - - with self.subTest(msg="X"): - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["XI", "IZ", "YY"]) - array = np.array([[False, True], [False, False], [True, True]], dtype=bool) - self.assertTrue(np.all(stab.X == array)) - - with self.subTest(msg="set X"): - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["XI", "IZ"]) - val = np.array([[False, False], [True, True]], dtype=bool) - stab.X = val - with self.assertWarns(DeprecationWarning): - self.assertEqual(stab, StabilizerTable.from_labels(["II", "XY"])) - - with self.subTest(msg="set X raises"): - - def set_x(): - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["XI", "IZ"]) - val = np.array([[False, False, False], [True, True, True]], dtype=bool) - stab.X = val - return stab - - self.assertRaises(Exception, set_x) - - def test_z_property(self): - """Test Z property""" - with self.subTest(msg="Z"): - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["XI", "IZ", "YY"]) - array = np.array([[False, False], [True, False], [True, True]], dtype=bool) - self.assertTrue(np.all(stab.Z == array)) - - with self.subTest(msg="set Z"): - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["XI", "IZ"]) - val = np.array([[False, False], [True, True]], dtype=bool) - stab.Z = val - with self.assertWarns(DeprecationWarning): - self.assertEqual(stab, StabilizerTable.from_labels(["XI", "ZZ"])) - - with self.subTest(msg="set Z raises"): - - def set_z(): - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["XI", "IZ"]) - val = np.array([[False, False, False], [True, True, True]], dtype=bool) - stab.Z = val - return stab - - self.assertRaises(Exception, set_z) - - def test_shape_property(self): - """Test shape property""" - shape = (3, 8) - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable(np.zeros(shape)) - self.assertEqual(stab.shape, shape) - - def test_size_property(self): - """Test size property""" - with self.subTest(msg="size"): - for j in range(1, 10): - shape = (j, 8) - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable(np.zeros(shape)) - self.assertEqual(stab.size, j) - - def test_num_qubits_property(self): - """Test num_qubits property""" - with self.subTest(msg="num_qubits"): - for j in range(1, 10): - shape = (5, 2 * j) - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable(np.zeros(shape)) - self.assertEqual(stab.num_qubits, j) - - def test_phase_property(self): - """Test phase property""" - with self.subTest(msg="phase"): - phase = np.array([False, True, True, False]) - array = np.eye(4, dtype=bool) - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable(array, phase) - self.assertTrue(np.all(stab.phase == phase)) - - with self.subTest(msg="set phase"): - phase = np.array([False, True, True, False]) - array = np.eye(4, dtype=bool) - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable(array) - stab.phase = phase - self.assertTrue(np.all(stab.phase == phase)) - - with self.subTest(msg="set phase raises"): - phase = np.array([False, True, False]) - array = np.eye(4, dtype=bool) - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable(array) - - def set_phase_raise(): - """Raise exception""" - stab.phase = phase - - self.assertRaises(ValueError, set_phase_raise) - - def test_pauli_property(self): - """Test pauli property""" - with self.subTest(msg="pauli"): - phase = np.array([False, True, True, False]) - array = np.eye(4, dtype=bool) - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable(array, phase) - pauli = PauliTable(array) - self.assertEqual(stab.pauli, pauli) - - with self.subTest(msg="set pauli"): - phase = np.array([False, True, True, False]) - array = np.zeros((4, 4), dtype=bool) - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable(array, phase) - pauli = PauliTable(np.eye(4, dtype=bool)) - stab.pauli = pauli - self.assertTrue(np.all(stab.array == pauli.array)) - self.assertTrue(np.all(stab.phase == phase)) - - with self.subTest(msg="set pauli"): - phase = np.array([False, True, True, False]) - array = np.zeros((4, 4), dtype=bool) - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable(array, phase) - pauli = PauliTable(np.eye(4, dtype=bool)[1:]) - - def set_pauli_raise(): - """Raise exception""" - stab.pauli = pauli - - self.assertRaises(ValueError, set_pauli_raise) - - def test_eq(self): - """Test __eq__ method.""" - with self.assertWarns(DeprecationWarning): - stab1 = StabilizerTable.from_labels(["II", "XI"]) - stab2 = StabilizerTable.from_labels(["XI", "II"]) - self.assertEqual(stab1, stab1) - self.assertNotEqual(stab1, stab2) - - def test_len_methods(self): - """Test __len__ method.""" - for j in range(1, 10): - labels = j * ["XX"] - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(labels) - self.assertEqual(len(stab), j) - - def test_add_methods(self): - """Test __add__ method.""" - labels1 = ["+XXI", "-IXX"] - labels2 = ["+XXI", "-ZZI", "+ZYZ"] - with self.assertWarns(DeprecationWarning): - stab1 = StabilizerTable.from_labels(labels1) - stab2 = StabilizerTable.from_labels(labels2) - target = StabilizerTable.from_labels(labels1 + labels2) - self.assertEqual(target, stab1 + stab2) - - def test_add_qargs(self): - """Test add method with qargs.""" - with self.assertWarns(DeprecationWarning): - stab1 = StabilizerTable.from_labels(["+IIII", "-YYYY"]) - stab2 = StabilizerTable.from_labels(["-XY", "+YZ"]) - - with self.subTest(msg="qargs=[0, 1]"): - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["+IIII", "-YYYY", "-IIXY", "+IIYZ"]) - self.assertEqual(stab1 + stab2([0, 1]), target) - - with self.subTest(msg="qargs=[0, 3]"): - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["+IIII", "-YYYY", "-XIIY", "+YIIZ"]) - self.assertEqual(stab1 + stab2([0, 3]), target) - - with self.subTest(msg="qargs=[2, 1]"): - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["+IIII", "-YYYY", "-IYXI", "+IZYI"]) - self.assertEqual(stab1 + stab2([2, 1]), target) - - with self.subTest(msg="qargs=[3, 1]"): - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["+IIII", "-YYYY", "-YIXI", "+ZIYI"]) - self.assertEqual(stab1 + stab2([3, 1]), target) - - def test_getitem_methods(self): - """Test __getitem__ method.""" - with self.subTest(msg="__getitem__ single"): - labels = ["+XI", "-IY"] - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(labels) - self.assertEqual(stab[0], StabilizerTable(labels[0])) - self.assertEqual(stab[1], StabilizerTable(labels[1])) - - with self.subTest(msg="__getitem__ array"): - labels = np.array(["+XI", "-IY", "+IZ", "-XY", "+ZX"]) - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(labels) - inds = [0, 3] - with self.assertWarns(DeprecationWarning): - self.assertEqual(stab[inds], StabilizerTable.from_labels(labels[inds])) - inds = np.array([4, 1]) - with self.assertWarns(DeprecationWarning): - self.assertEqual(stab[inds], StabilizerTable.from_labels(labels[inds])) - - with self.subTest(msg="__getitem__ slice"): - labels = np.array(["+XI", "-IY", "+IZ", "-XY", "+ZX"]) - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(labels) - self.assertEqual(stab[:], stab) - self.assertEqual(stab[1:3], StabilizerTable.from_labels(labels[1:3])) - - def test_setitem_methods(self): - """Test __setitem__ method.""" - with self.subTest(msg="__setitem__ single"): - labels = ["+XI", "IY"] - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["+XI", "IY"]) - stab[0] = "+II" - self.assertEqual(stab[0], StabilizerTable("+II")) - stab[1] = "-XX" - self.assertEqual(stab[1], StabilizerTable("-XX")) - - def raises_single(): - # Wrong size Pauli - stab[0] = "+XXX" - - self.assertRaises(Exception, raises_single) - - with self.subTest(msg="__setitem__ array"): - labels = np.array(["+XI", "-IY", "+IZ"]) - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(labels) - target = StabilizerTable.from_labels(["+II", "-ZZ"]) - inds = [2, 0] - stab[inds] = target - with self.assertWarns(DeprecationWarning): - self.assertEqual(stab[inds], target) - - def raises_array(): - with self.assertWarns(DeprecationWarning): - stab[inds] = StabilizerTable.from_labels(["+YY", "-ZZ", "+XX"]) - - self.assertRaises(Exception, raises_array) - - with self.subTest(msg="__setitem__ slice"): - labels = np.array(5 * ["+III"]) - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(labels) - target = StabilizerTable.from_labels(5 * ["-XXX"]) - stab[:] = target - with self.assertWarns(DeprecationWarning): - self.assertEqual(stab[:], target) - target = StabilizerTable.from_labels(2 * ["+ZZZ"]) - stab[1:3] = target - self.assertEqual(stab[1:3], target) - - -class TestStabilizerTableLabels(QiskitTestCase): - """Tests for StabilizerTable label converions.""" - - def test_from_labels_1q(self): - """Test 1-qubit from_labels method.""" - labels = ["I", "X", "Y", "Z", "+I", "+X", "+Y", "+Z", "-I", "-X", "-Y", "-Z"] - array = np.vstack( - 3 * [np.array([[False, False], [True, False], [True, True], [False, True]], dtype=bool)] - ) - phase = np.array(8 * [False] + 4 * [True], dtype=bool) - with self.assertWarns(DeprecationWarning): - target = StabilizerTable(array, phase) - value = StabilizerTable.from_labels(labels) - self.assertEqual(target, value) - - def test_from_labels_2q(self): - """Test 2-qubit from_labels method.""" - labels = ["II", "-YY", "+XZ"] - array = np.array( - [[False, False, False, False], [True, True, True, True], [False, True, True, False]], - dtype=bool, - ) - phase = np.array([False, True, False]) - with self.assertWarns(DeprecationWarning): - target = StabilizerTable(array, phase) - value = StabilizerTable.from_labels(labels) - self.assertEqual(target, value) - - def test_from_labels_5q(self): - """Test 5-qubit from_labels method.""" - labels = ["IIIII", "-XXXXX", "YYYYY", "ZZZZZ"] - array = np.array( - [10 * [False], 5 * [True] + 5 * [False], 10 * [True], 5 * [False] + 5 * [True]], - dtype=bool, - ) - phase = np.array([False, True, False, False]) - with self.assertWarns(DeprecationWarning): - target = StabilizerTable(array, phase) - value = StabilizerTable.from_labels(labels) - self.assertEqual(target, value) - - def test_to_labels_1q(self): - """Test 1-qubit to_labels method.""" - array = np.vstack( - 2 * [np.array([[False, False], [True, False], [True, True], [False, True]], dtype=bool)] - ) - phase = np.array(4 * [False] + 4 * [True], dtype=bool) - with self.assertWarns(DeprecationWarning): - value = StabilizerTable(array, phase).to_labels() - target = ["+I", "+X", "+Y", "+Z", "-I", "-X", "-Y", "-Z"] - self.assertEqual(value, target) - - def test_to_labels_1q_array(self): - """Test 1-qubit to_labels method w/ array=True.""" - array = np.vstack( - 2 * [np.array([[False, False], [True, False], [True, True], [False, True]], dtype=bool)] - ) - phase = np.array(4 * [False] + 4 * [True], dtype=bool) - with self.assertWarns(DeprecationWarning): - value = StabilizerTable(array, phase).to_labels(array=True) - target = np.array(["+I", "+X", "+Y", "+Z", "-I", "-X", "-Y", "-Z"]) - self.assertTrue(np.all(value == target)) - - def test_labels_round_trip(self): - """Test from_labels and to_labels round trip.""" - target = ["+III", "-IXZ", "-XYI", "+ZZZ"] - with self.assertWarns(DeprecationWarning): - value = StabilizerTable.from_labels(target).to_labels() - self.assertEqual(value, target) - - def test_labels_round_trip_array(self): - """Test from_labels and to_labels round trip w/ array=True.""" - labels = ["+III", "-IXZ", "-XYI", "+ZZZ"] - target = np.array(labels) - with self.assertWarns(DeprecationWarning): - value = StabilizerTable.from_labels(labels).to_labels(array=True) - self.assertTrue(np.all(value == target)) - - -class TestStabilizerTableMatrix(QiskitTestCase): - """Tests for StabilizerTable matrix converions.""" - - def test_to_matrix_1q(self): - """Test 1-qubit to_matrix method.""" - labels = ["+I", "+X", "+Y", "+Z", "-I", "-X", "-Y", "-Z"] - targets = [stab_mat(i) for i in labels] - with self.assertWarns(DeprecationWarning): - values = StabilizerTable.from_labels(labels).to_matrix() - self.assertTrue(isinstance(values, list)) - for target, value in zip(targets, values): - self.assertTrue(np.all(value == target)) - - def test_to_matrix_1q_array(self): - """Test 1-qubit to_matrix method w/ array=True.""" - labels = ["+I", "+X", "+Y", "+Z", "-I", "-X", "-Y", "-Z"] - target = np.array([stab_mat(i) for i in labels]) - with self.assertWarns(DeprecationWarning): - value = StabilizerTable.from_labels(labels).to_matrix(array=True) - self.assertTrue(isinstance(value, np.ndarray)) - self.assertTrue(np.all(value == target)) - - def test_to_matrix_1q_sparse(self): - """Test 1-qubit to_matrix method w/ sparse=True.""" - labels = ["+I", "+X", "+Y", "+Z", "-I", "-X", "-Y", "-Z"] - targets = [stab_mat(i) for i in labels] - with self.assertWarns(DeprecationWarning): - values = StabilizerTable.from_labels(labels).to_matrix(sparse=True) - for mat, targ in zip(values, targets): - self.assertTrue(isinstance(mat, csr_matrix)) - self.assertTrue(np.all(targ == mat.toarray())) - - def test_to_matrix_2q(self): - """Test 2-qubit to_matrix method.""" - labels = ["+IX", "-YI", "-II", "+ZZ"] - targets = [stab_mat(i) for i in labels] - with self.assertWarns(DeprecationWarning): - values = StabilizerTable.from_labels(labels).to_matrix() - self.assertTrue(isinstance(values, list)) - for target, value in zip(targets, values): - self.assertTrue(np.all(value == target)) - - def test_to_matrix_2q_array(self): - """Test 2-qubit to_matrix method w/ array=True.""" - labels = ["-ZZ", "-XY", "+YX", "-IZ"] - target = np.array([stab_mat(i) for i in labels]) - with self.assertWarns(DeprecationWarning): - value = StabilizerTable.from_labels(labels).to_matrix(array=True) - self.assertTrue(isinstance(value, np.ndarray)) - self.assertTrue(np.all(value == target)) - - def test_to_matrix_2q_sparse(self): - """Test 2-qubit to_matrix method w/ sparse=True.""" - labels = ["+IX", "+II", "-ZY", "-YZ"] - targets = [stab_mat(i) for i in labels] - with self.assertWarns(DeprecationWarning): - values = StabilizerTable.from_labels(labels).to_matrix(sparse=True) - for mat, targ in zip(values, targets): - self.assertTrue(isinstance(mat, csr_matrix)) - self.assertTrue(np.all(targ == mat.toarray())) - - def test_to_matrix_5q(self): - """Test 5-qubit to_matrix method.""" - labels = ["IXIXI", "YZIXI", "IIXYZ"] - targets = [stab_mat(i) for i in labels] - with self.assertWarns(DeprecationWarning): - values = StabilizerTable.from_labels(labels).to_matrix() - self.assertTrue(isinstance(values, list)) - for target, value in zip(targets, values): - self.assertTrue(np.all(value == target)) - - def test_to_matrix_5q_sparse(self): - """Test 5-qubit to_matrix method w/ sparse=True.""" - labels = ["-XXXYY", "IXIZY", "-ZYXIX", "+ZXIYZ"] - targets = [stab_mat(i) for i in labels] - with self.assertWarns(DeprecationWarning): - values = StabilizerTable.from_labels(labels).to_matrix(sparse=True) - for mat, targ in zip(values, targets): - self.assertTrue(isinstance(mat, csr_matrix)) - self.assertTrue(np.all(targ == mat.toarray())) - - -class TestStabilizerTableMethods(QiskitTestCase): - """Tests for StabilizerTable methods.""" - - def test_sort(self): - """Test sort method.""" - with self.subTest(msg="1 qubit"): - unsrt = ["X", "-Z", "I", "Y", "-X", "Z"] - srt = ["I", "X", "-X", "Y", "-Z", "Z"] - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(srt) - value = StabilizerTable.from_labels(unsrt).sort() - self.assertEqual(target, value) - - with self.subTest(msg="1 qubit weight order"): - unsrt = ["X", "-Z", "I", "Y", "-X", "Z"] - srt = ["I", "X", "-X", "Y", "-Z", "Z"] - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(srt) - value = StabilizerTable.from_labels(unsrt).sort(weight=True) - self.assertEqual(target, value) - - with self.subTest(msg="2 qubit standard order"): - srt_p = [ - "II", - "IX", - "IY", - "XI", - "XX", - "XY", - "XZ", - "YI", - "YX", - "YY", - "YZ", - "ZI", - "ZX", - "ZY", - "ZZ", - ] - srt_m = ["-" + i for i in srt_p] - - unsrt_p = srt_p.copy() - np.random.shuffle(unsrt_p) - unsrt_m = srt_m.copy() - np.random.shuffle(unsrt_m) - - # Sort with + cases all first in shuffled list - srt = [val for pair in zip(srt_p, srt_m) for val in pair] - unsrt = unsrt_p + unsrt_m - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(srt) - value = StabilizerTable.from_labels(unsrt).sort() - self.assertEqual(target, value) - - # Sort with - cases all first in shuffled list - srt = [val for pair in zip(srt_m, srt_p) for val in pair] - unsrt = unsrt_m + unsrt_p - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(srt) - value = StabilizerTable.from_labels(unsrt).sort() - self.assertEqual(target, value) - - with self.subTest(msg="2 qubit weight order"): - srt_p = [ - "II", - "IX", - "IY", - "IZ", - "XI", - "YI", - "ZI", - "XX", - "XY", - "XZ", - "YX", - "YY", - "YZ", - "ZX", - "ZY", - "ZZ", - ] - srt_m = ["-" + i for i in srt_p] - - unsrt_p = srt_p.copy() - np.random.shuffle(unsrt_p) - unsrt_m = srt_m.copy() - np.random.shuffle(unsrt_m) - - # Sort with + cases all first in shuffled list - srt = [val for pair in zip(srt_p, srt_m) for val in pair] - unsrt = unsrt_p + unsrt_m - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(srt) - value = StabilizerTable.from_labels(unsrt).sort(weight=True) - self.assertEqual(target, value) - - # Sort with - cases all first in shuffled list - srt = [val for pair in zip(srt_m, srt_p) for val in pair] - unsrt = unsrt_m + unsrt_p - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(srt) - value = StabilizerTable.from_labels(unsrt).sort(weight=True) - self.assertEqual(target, value) - - def test_unique(self): - """Test unique method.""" - with self.subTest(msg="1 qubit"): - labels = ["X", "Z", "-I", "-X", "X", "I", "Y", "-I", "-X", "-Z", "Z", "X", "I"] - unique = ["X", "Z", "-I", "-X", "I", "Y", "-Z"] - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(unique) - value = StabilizerTable.from_labels(labels).unique() - self.assertEqual(target, value) - - with self.subTest(msg="2 qubit"): - labels = [ - "XX", - "IX", - "-XX", - "XX", - "-IZ", - "II", - "IZ", - "ZI", - "YX", - "YX", - "ZZ", - "IX", - "XI", - ] - unique = ["XX", "IX", "-XX", "-IZ", "II", "IZ", "ZI", "YX", "ZZ", "XI"] - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(unique) - value = StabilizerTable.from_labels(labels).unique() - self.assertEqual(target, value) - - with self.subTest(msg="10 qubit"): - labels = [10 * "X", "-" + 10 * "X", "-" + 10 * "X", 10 * "I", 10 * "X"] - unique = [10 * "X", "-" + 10 * "X", 10 * "I"] - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(unique) - value = StabilizerTable.from_labels(labels).unique() - self.assertEqual(target, value) - - def test_delete(self): - """Test delete method.""" - with self.subTest(msg="single row"): - for j in range(1, 6): - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels([j * "X", "-" + j * "Y"]) - self.assertEqual(stab.delete(0), StabilizerTable("-" + j * "Y")) - self.assertEqual(stab.delete(1), StabilizerTable(j * "X")) - - with self.subTest(msg="multiple rows"): - for j in range(1, 6): - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels([j * "X", "-" + j * "Y", j * "Z"]) - self.assertEqual(stab.delete([0, 2]), StabilizerTable("-" + j * "Y")) - self.assertEqual(stab.delete([1, 2]), StabilizerTable(j * "X")) - self.assertEqual(stab.delete([0, 1]), StabilizerTable(j * "Z")) - - with self.subTest(msg="single qubit"): - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["IIX", "IYI", "ZII"]) - value = stab.delete(0, qubit=True) - target = StabilizerTable.from_labels(["II", "IY", "ZI"]) - self.assertEqual(value, target) - value = stab.delete(1, qubit=True) - target = StabilizerTable.from_labels(["IX", "II", "ZI"]) - self.assertEqual(value, target) - value = stab.delete(2, qubit=True) - target = StabilizerTable.from_labels(["IX", "YI", "II"]) - self.assertEqual(value, target) - - with self.subTest(msg="multiple qubits"): - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["IIX", "IYI", "ZII"]) - value = stab.delete([0, 1], qubit=True) - target = StabilizerTable.from_labels(["I", "I", "Z"]) - self.assertEqual(value, target) - value = stab.delete([1, 2], qubit=True) - target = StabilizerTable.from_labels(["X", "I", "I"]) - self.assertEqual(value, target) - value = stab.delete([0, 2], qubit=True) - target = StabilizerTable.from_labels(["I", "Y", "I"]) - self.assertEqual(value, target) - - def test_insert(self): - """Test insert method.""" - # Insert single row - for j in range(1, 10): - l_px = j * "X" - l_mi = "-" + j * "I" - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable(l_px) - target0 = StabilizerTable.from_labels([l_mi, l_px]) - target1 = StabilizerTable.from_labels([l_px, l_mi]) - - with self.subTest(msg=f"single row from str ({j})"): - with self.assertWarns(DeprecationWarning): - value0 = stab.insert(0, l_mi) - self.assertEqual(value0, target0) - value1 = stab.insert(1, l_mi) - self.assertEqual(value1, target1) - - with self.subTest(msg=f"single row from StabilizerTable ({j})"): - with self.assertWarns(DeprecationWarning): - value0 = stab.insert(0, StabilizerTable(l_mi)) - self.assertEqual(value0, target0) - value1 = stab.insert(1, StabilizerTable(l_mi)) - self.assertEqual(value1, target1) - - # Insert multiple rows - for j in range(1, 10): - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable(j * "X") - insert = StabilizerTable.from_labels(["-" + j * "I", j * "Y", "-" + j * "Z"]) - target0 = insert + stab - target1 = stab + insert - - with self.subTest(msg=f"multiple-rows from StabilizerTable ({j})"): - with self.assertWarns(DeprecationWarning): - value0 = stab.insert(0, insert) - self.assertEqual(value0, target0) - value1 = stab.insert(1, insert) - self.assertEqual(value1, target1) - - # Insert single column - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["X", "Y", "Z"]) - for sgn in ["+", "-"]: - for i in ["I", "X", "Y", "Z"]: - with self.assertWarns(DeprecationWarning): - target0 = StabilizerTable.from_labels( - [sgn + "X" + i, sgn + "Y" + i, sgn + "Z" + i] - ) - target1 = StabilizerTable.from_labels( - [sgn + i + "X", sgn + i + "Y", sgn + i + "Z"] - ) - - with self.subTest(msg=f"single-column single-val from str {sgn + i}"): - with self.assertWarns(DeprecationWarning): - value = stab.insert(0, sgn + i, qubit=True) - self.assertEqual(value, target0) - value = stab.insert(1, sgn + i, qubit=True) - self.assertEqual(value, target1) - - with self.subTest(msg=f"single-column single-val from StabilizerTable {sgn + i}"): - with self.assertWarns(DeprecationWarning): - value = stab.insert(0, StabilizerTable(sgn + i), qubit=True) - self.assertEqual(value, target0) - value = stab.insert(1, StabilizerTable(sgn + i), qubit=True) - self.assertEqual(value, target1) - - # Insert single column with multiple values - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["X", "Y", "Z"]) - for i in [("I", "X", "Y"), ("X", "Y", "Z"), ("Y", "Z", "I")]: - with self.assertWarns(DeprecationWarning): - target0 = StabilizerTable.from_labels(["X" + i[0], "Y" + i[1], "Z" + i[2]]) - target1 = StabilizerTable.from_labels([i[0] + "X", i[1] + "Y", i[2] + "Z"]) - - with self.subTest(msg="single-column multiple-vals from StabilizerTable"): - with self.assertWarns(DeprecationWarning): - value = stab.insert(0, StabilizerTable.from_labels(i), qubit=True) - self.assertEqual(value, target0) - value = stab.insert(1, StabilizerTable.from_labels(i), qubit=True) - self.assertEqual(value, target1) - - with self.subTest(msg="single-column multiple-vals from array"): - with self.assertWarns(DeprecationWarning): - value = stab.insert(0, StabilizerTable.from_labels(i).array, qubit=True) - self.assertEqual(value, target0) - value = stab.insert(1, StabilizerTable.from_labels(i).array, qubit=True) - self.assertEqual(value, target1) - - # Insert multiple columns from single - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["X", "Y", "Z"]) - for j in range(1, 5): - for i in [j * "I", j * "X", j * "Y", j * "Z"]: - with self.assertWarns(DeprecationWarning): - target0 = StabilizerTable.from_labels(["X" + i, "Y" + i, "Z" + i]) - target1 = StabilizerTable.from_labels([i + "X", i + "Y", i + "Z"]) - - with self.subTest(msg="multiple-columns single-val from str"): - with self.assertWarns(DeprecationWarning): - value = stab.insert(0, i, qubit=True) - self.assertEqual(value, target0) - value = stab.insert(1, i, qubit=True) - self.assertEqual(value, target1) - - with self.subTest(msg="multiple-columns single-val from StabilizerTable"): - with self.assertWarns(DeprecationWarning): - value = stab.insert(0, StabilizerTable(i), qubit=True) - self.assertEqual(value, target0) - value = stab.insert(1, StabilizerTable(i), qubit=True) - self.assertEqual(value, target1) - - with self.subTest(msg="multiple-columns single-val from array"): - with self.assertWarns(DeprecationWarning): - value = stab.insert(0, StabilizerTable(i).array, qubit=True) - self.assertEqual(value, target0) - value = stab.insert(1, StabilizerTable(i).array, qubit=True) - self.assertEqual(value, target1) - - # Insert multiple columns multiple row values - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["X", "Y", "Z"]) - for j in range(1, 5): - for i in [ - (j * "I", j * "X", j * "Y"), - (j * "X", j * "Z", j * "Y"), - (j * "Y", j * "Z", j * "I"), - ]: - with self.assertWarns(DeprecationWarning): - target0 = StabilizerTable.from_labels(["X" + i[0], "Y" + i[1], "Z" + i[2]]) - target1 = StabilizerTable.from_labels([i[0] + "X", i[1] + "Y", i[2] + "Z"]) - - with self.subTest(msg="multiple-column multiple-vals from StabilizerTable"): - with self.assertWarns(DeprecationWarning): - value = stab.insert(0, StabilizerTable.from_labels(i), qubit=True) - self.assertEqual(value, target0) - value = stab.insert(1, StabilizerTable.from_labels(i), qubit=True) - self.assertEqual(value, target1) - - with self.subTest(msg="multiple-column multiple-vals from array"): - with self.assertWarns(DeprecationWarning): - value = stab.insert(0, StabilizerTable.from_labels(i).array, qubit=True) - self.assertEqual(value, target0) - value = stab.insert(1, StabilizerTable.from_labels(i).array, qubit=True) - self.assertEqual(value, target1) - - def test_iteration(self): - """Test iteration methods.""" - - labels = ["+III", "+IXI", "-IYY", "+YIZ", "-ZIZ", "+XYZ", "-III"] - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(labels) - - with self.subTest(msg="enumerate"): - with self.assertWarns(DeprecationWarning): - for idx, i in enumerate(stab): - self.assertEqual(i, StabilizerTable(labels[idx])) - - with self.subTest(msg="iter"): - with self.assertWarns(DeprecationWarning): - for idx, i in enumerate(iter(stab)): - self.assertEqual(i, StabilizerTable(labels[idx])) - - with self.subTest(msg="zip"): - with self.assertWarns(DeprecationWarning): - for label, i in zip(labels, stab): - self.assertEqual(i, StabilizerTable(label)) - - with self.subTest(msg="label_iter"): - for idx, i in enumerate(stab.label_iter()): - self.assertEqual(i, labels[idx]) - - with self.subTest(msg="matrix_iter (dense)"): - for idx, i in enumerate(stab.matrix_iter()): - self.assertTrue(np.all(i == stab_mat(labels[idx]))) - - with self.subTest(msg="matrix_iter (sparse)"): - for idx, i in enumerate(stab.matrix_iter(sparse=True)): - self.assertTrue(isinstance(i, csr_matrix)) - self.assertTrue(np.all(i.toarray() == stab_mat(labels[idx]))) - - def test_tensor(self): - """Test tensor method.""" - labels1 = ["-XX", "YY"] - labels2 = ["III", "-ZZZ"] - with self.assertWarns(DeprecationWarning): - stab1 = StabilizerTable.from_labels(labels1) - stab2 = StabilizerTable.from_labels(labels2) - - target = StabilizerTable.from_labels(["-XXIII", "XXZZZ", "YYIII", "-YYZZZ"]) - value = stab1.tensor(stab2) - self.assertEqual(value, target) - - def test_expand(self): - """Test expand method.""" - labels1 = ["-XX", "YY"] - labels2 = ["III", "-ZZZ"] - with self.assertWarns(DeprecationWarning): - stab1 = StabilizerTable.from_labels(labels1) - stab2 = StabilizerTable.from_labels(labels2) - - target = StabilizerTable.from_labels(["-IIIXX", "IIIYY", "ZZZXX", "-ZZZYY"]) - value = stab1.expand(stab2) - self.assertEqual(value, target) - - def test_compose(self): - """Test compose and dot methods.""" - - # Test single qubit Pauli dot products - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["I", "X", "Y", "Z"]) - - # Test single qubit Pauli dot products - with self.assertWarns(DeprecationWarning): - stab = StabilizerTable.from_labels(["I", "X", "Y", "Z", "-I", "-X", "-Y", "-Z"]) - - with self.subTest(msg="dot single I"): - with self.assertWarns(DeprecationWarning): - value = stab.compose("I") - target = StabilizerTable.from_labels(["I", "X", "Y", "Z", "-I", "-X", "-Y", "-Z"]) - self.assertEqual(target, value) - - with self.subTest(msg="dot single -I"): - with self.assertWarns(DeprecationWarning): - value = stab.compose("-I") - target = StabilizerTable.from_labels(["-I", "-X", "-Y", "-Z", "I", "X", "Y", "Z"]) - self.assertEqual(target, value) - - with self.subTest(msg="dot single I"): - with self.assertWarns(DeprecationWarning): - value = stab.dot("I") - target = StabilizerTable.from_labels(["I", "X", "Y", "Z", "-I", "-X", "-Y", "-Z"]) - self.assertEqual(target, value) - - with self.subTest(msg="dot single -I"): - with self.assertWarns(DeprecationWarning): - value = stab.dot("-I") - target = StabilizerTable.from_labels(["-I", "-X", "-Y", "-Z", "I", "X", "Y", "Z"]) - self.assertEqual(target, value) - - with self.subTest(msg="compose single X"): - with self.assertWarns(DeprecationWarning): - value = stab.compose("X") - target = StabilizerTable.from_labels(["X", "I", "-Z", "Y", "-X", "-I", "Z", "-Y"]) - self.assertEqual(target, value) - - with self.subTest(msg="compose single -X"): - with self.assertWarns(DeprecationWarning): - value = stab.compose("-X") - target = StabilizerTable.from_labels(["-X", "-I", "Z", "-Y", "X", "I", "-Z", "Y"]) - self.assertEqual(target, value) - - with self.subTest(msg="dot single X"): - with self.assertWarns(DeprecationWarning): - value = stab.dot("X") - target = StabilizerTable.from_labels(["X", "I", "Z", "-Y", "-X", "-I", "-Z", "Y"]) - self.assertEqual(target, value) - - with self.subTest(msg="dot single -X"): - with self.assertWarns(DeprecationWarning): - value = stab.dot("-X") - target = StabilizerTable.from_labels(["-X", "-I", "-Z", "Y", "X", "I", "Z", "-Y"]) - self.assertEqual(target, value) - - with self.subTest(msg="compose single Y"): - with self.assertWarns(DeprecationWarning): - value = stab.compose("Y") - target = StabilizerTable.from_labels(["Y", "Z", "-I", "-X", "-Y", "-Z", "I", "X"]) - self.assertEqual(target, value) - - with self.subTest(msg="compose single -Y"): - with self.assertWarns(DeprecationWarning): - value = stab.compose("-Y") - target = StabilizerTable.from_labels(["-Y", "-Z", "I", "X", "Y", "Z", "-I", "-X"]) - self.assertEqual(target, value) - - with self.subTest(msg="dot single Y"): - with self.assertWarns(DeprecationWarning): - value = stab.dot("Y") - target = StabilizerTable.from_labels(["Y", "-Z", "-I", "X", "-Y", "Z", "I", "-X"]) - self.assertEqual(target, value) - - with self.subTest(msg="dot single -Y"): - with self.assertWarns(DeprecationWarning): - value = stab.dot("-Y") - target = StabilizerTable.from_labels(["-Y", "Z", "I", "-X", "Y", "-Z", "-I", "X"]) - self.assertEqual(target, value) - - with self.subTest(msg="compose single Z"): - with self.assertWarns(DeprecationWarning): - value = stab.compose("Z") - target = StabilizerTable.from_labels(["Z", "-Y", "X", "I", "-Z", "Y", "-X", "-I"]) - self.assertEqual(target, value) - - with self.subTest(msg="compose single -Z"): - with self.assertWarns(DeprecationWarning): - value = stab.compose("-Z") - target = StabilizerTable.from_labels(["-Z", "Y", "-X", "-I", "Z", "-Y", "X", "I"]) - self.assertEqual(target, value) - - with self.subTest(msg="dot single Z"): - with self.assertWarns(DeprecationWarning): - value = stab.dot("Z") - target = StabilizerTable.from_labels(["Z", "Y", "-X", "I", "-Z", "-Y", "X", "-I"]) - self.assertEqual(target, value) - - with self.subTest(msg="dot single -Z"): - with self.assertWarns(DeprecationWarning): - value = stab.dot("-Z") - target = StabilizerTable.from_labels(["-Z", "-Y", "X", "-I", "Z", "Y", "-X", "I"]) - self.assertEqual(target, value) - - def test_compose_qargs(self): - """Test compose and dot methods with qargs.""" - - # Dot product with qargs - with self.assertWarns(DeprecationWarning): - stab1 = StabilizerTable.from_labels(["III", "-XXX", "YYY", "-ZZZ"]) - - # 1-qubit qargs - with self.assertWarns(DeprecationWarning): - stab2 = StabilizerTable("-Z") - - with self.subTest(msg="dot 1-qubit qargs=[0]"): - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["-IIZ", "XXY", "YYX", "ZZI"]) - value = stab1.dot(stab2, qargs=[0]) - self.assertEqual(value, target) - - with self.subTest(msg="compose 1-qubit qargs=[0]"): - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["-IIZ", "-XXY", "-YYX", "ZZI"]) - value = stab1.compose(stab2, qargs=[0]) - self.assertEqual(value, target) - - with self.subTest(msg="dot 1-qubit qargs=[1]"): - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["-IZI", "XYX", "YXY", "ZIZ"]) - value = stab1.dot(stab2, qargs=[1]) - self.assertEqual(value, target) - - with self.subTest(msg="compose 1-qubit qargs=[1]"): - with self.assertWarns(DeprecationWarning): - value = stab1.compose(stab2, qargs=[1]) - target = StabilizerTable.from_labels(["-IZI", "-XYX", "-YXY", "ZIZ"]) - self.assertEqual(value, target) - - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["ZII", "YXX"]) - with self.subTest(msg="dot 1-qubit qargs=[2]"): - with self.assertWarns(DeprecationWarning): - value = stab1.dot(stab2, qargs=[2]) - target = StabilizerTable.from_labels(["-ZII", "YXX", "XYY", "IZZ"]) - self.assertEqual(value, target) - - with self.subTest(msg="compose 1-qubit qargs=[2]"): - with self.assertWarns(DeprecationWarning): - value = stab1.compose(stab2, qargs=[2]) - target = StabilizerTable.from_labels(["-ZII", "-YXX", "-XYY", "IZZ"]) - self.assertEqual(value, target) - - # 2-qubit qargs - with self.assertWarns(DeprecationWarning): - stab2 = StabilizerTable("-ZY") - with self.subTest(msg="dot 2-qubit qargs=[0, 1]"): - with self.assertWarns(DeprecationWarning): - value = stab1.dot(stab2, qargs=[0, 1]) - target = StabilizerTable.from_labels(["-IZY", "-XYZ", "-YXI", "ZIX"]) - self.assertEqual(value, target) - - with self.subTest(msg="compose 2-qubit qargs=[0, 1]"): - with self.assertWarns(DeprecationWarning): - value = stab1.compose(stab2, qargs=[0, 1]) - target = StabilizerTable.from_labels(["-IZY", "-XYZ", "YXI", "-ZIX"]) - self.assertEqual(value, target) - - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["YIZ", "ZXY"]) - with self.subTest(msg="dot 2-qubit qargs=[2, 0]"): - with self.assertWarns(DeprecationWarning): - value = stab1.dot(stab2, qargs=[2, 0]) - target = StabilizerTable.from_labels(["-YIZ", "-ZXY", "-IYX", "XZI"]) - self.assertEqual(value, target) - - with self.subTest(msg="compose 2-qubit qargs=[2, 0]"): - with self.assertWarns(DeprecationWarning): - value = stab1.compose(stab2, qargs=[2, 0]) - target = StabilizerTable.from_labels(["-YIZ", "-ZXY", "IYX", "-XZI"]) - self.assertEqual(value, target) - - # 3-qubit qargs - with self.assertWarns(DeprecationWarning): - stab2 = StabilizerTable("-XYZ") - - with self.assertWarns(DeprecationWarning): - target = StabilizerTable.from_labels(["XYZ", "IZY"]) - with self.subTest(msg="dot 3-qubit qargs=None"): - with self.assertWarns(DeprecationWarning): - value = stab1.dot(stab2, qargs=[0, 1, 2]) - target = StabilizerTable.from_labels(["-XYZ", "-IZY", "-ZIX", "-YXI"]) - self.assertEqual(value, target) - - with self.subTest(msg="dot 3-qubit qargs=[0, 1, 2]"): - with self.assertWarns(DeprecationWarning): - value = stab1.dot(stab2, qargs=[0, 1, 2]) - target = StabilizerTable.from_labels(["-XYZ", "-IZY", "-ZIX", "-YXI"]) - self.assertEqual(value, target) - - with self.subTest(msg="dot 3-qubit qargs=[2, 1, 0]"): - with self.assertWarns(DeprecationWarning): - value = stab1.dot(stab2, qargs=[2, 1, 0]) - target = StabilizerTable.from_labels(["-ZYX", "-YZI", "-XIZ", "-IXY"]) - self.assertEqual(value, target) - - with self.subTest(msg="compose 3-qubit qargs=[2, 1, 0]"): - with self.assertWarns(DeprecationWarning): - value = stab1.compose(stab2, qargs=[2, 1, 0]) - target = StabilizerTable.from_labels(["-ZYX", "-YZI", "-XIZ", "-IXY"]) - self.assertEqual(value, target) - - -if __name__ == "__main__": - unittest.main() diff --git a/test/python/quantum_info/operators/test_random.py b/test/python/quantum_info/operators/test_random.py index 0ade4e016d02..20e8fdf96a29 100644 --- a/test/python/quantum_info/operators/test_random.py +++ b/test/python/quantum_info/operators/test_random.py @@ -18,20 +18,12 @@ import numpy as np from ddt import ddt -from qiskit.quantum_info import ( - Choi, - Clifford, - Operator, - PauliList, - PauliTable, - Stinespring, -) +from qiskit.quantum_info import Choi, Clifford, Operator, PauliList, Stinespring from qiskit.quantum_info.operators.predicates import is_hermitian_matrix from qiskit.quantum_info.random import ( random_clifford, random_hermitian, random_pauli_list, - random_pauli_table, random_quantum_channel, random_unitary, ) @@ -199,46 +191,9 @@ def test_not_global_seed(self): self.assertFalse(np.all(rng_before == rng_after)) -@ddt -class TestPauliTwoDesignTable(QiskitTestCase): - """DEPRECATED: Testing random_pauli_table function.""" - - @combine(num_qubits=[1, 2, 3, 4, 5, 10, 50, 100, 200, 250], size=[1, 10, 100]) - def test_valid(self, num_qubits, size): - """Test random_pauli_table {num_qubits}-qubits, size {size}.""" - with self.assertWarns(DeprecationWarning): - value = random_pauli_table(num_qubits, size=size) - with self.subTest(msg="Test type"): - self.assertIsInstance(value, PauliTable) - with self.subTest(msg="Test num_qubits"): - self.assertEqual(value.num_qubits, num_qubits) - with self.subTest(msg="Test type"): - self.assertEqual(len(value), size) - - def test_fixed_seed(self): - """Test fixing seed fixes output""" - seed = 1532 - with self.assertWarns(DeprecationWarning): - value1 = random_pauli_table(10, size=10, seed=seed) - value2 = random_pauli_table(10, size=10, seed=seed) - self.assertEqual(value1, value2) - - def test_not_global_seed(self): - """Test fixing random_hermitian seed is locally scoped.""" - seed = 314159 - test_cases = 100 - with self.assertWarns(DeprecationWarning): - random_pauli_table(10, size=10, seed=seed) - rng_before = np.random.randint(1000, size=test_cases) - with self.assertWarns(DeprecationWarning): - random_pauli_table(10, seed=seed) - rng_after = np.random.randint(1000, size=test_cases) - self.assertFalse(np.all(rng_before == rng_after)) - - @ddt class TestRandomPauliList(QiskitTestCase): - """Testing random_pauli_table function.""" + """Testing random_pauli_list function.""" @combine(num_qubits=[1, 2, 3, 4, 5, 10, 50, 100, 200, 250], size=[1, 10, 100]) def test_valid(self, num_qubits, size):