Esempio n. 1
0
    def __init__(self, data, coeffs=None):
        """Initialize an operator object.

        Args:
            data (Paulilist, SparsePauliOp, PauliTable): Pauli list of terms.
            coeffs (np.ndarray): complex coefficients for Pauli terms.

        Raises:
            QiskitError: If the input data or coeffs are invalid.
        """
        if isinstance(data, SparsePauliOp):
            pauli_list = data._pauli_list
            coeffs = data._coeffs
        else:
            pauli_list = PauliList(data)
            if coeffs is None:
                coeffs = np.ones(pauli_list.size, dtype=complex)
        # Initialize PauliList
        self._pauli_list = PauliList.from_symplectic(pauli_list.z, pauli_list.x)

        # Initialize Coeffs
        self._coeffs = np.asarray((-1j) ** pauli_list.phase * coeffs, dtype=complex)
        if self._coeffs.shape != (self._pauli_list.size,):
            raise QiskitError(
                "coeff vector is incorrect shape for number"
                " of Paulis {} != {}".format(self._coeffs.shape, self._pauli_list.size)
            )
        # Initialize LinearOp
        super().__init__(num_qubits=self._pauli_list.num_qubits)
def pauli_basis(num_qubits, weight=False, pauli_list=False):
    """Return the ordered PauliTable or PauliList for the n-qubit Pauli basis.

    Args:
        num_qubits (int): number of qubits
        weight (bool): if True optionally return the basis sorted by Pauli weight
                       rather than lexicographic order (Default: False)
        pauli_list (bool): if True, the return type becomes PauliList, otherwise PauliTable.

    Returns:
        PauliTable, PauliList: the Paulis for the basis
    """
    if pauli_list:
        pauli_1q = PauliList(["I", "X", "Y", "Z"])
    else:
        warnings.warn(
            "The pauli_basis function with PauliTable output is deprecated as of Qiskit Terra "
            "0.19.0 and will be removed no sooner than 3 months after the releasedate. "
            "Use PauliList by pauli_list=True instead.",
            DeprecationWarning,
            stacklevel=2,
        )
        pauli_1q = PauliTable(
            np.array(
                [[False, False], [True, False], [True, True], [False, True]],
                dtype=bool))
    if num_qubits == 1:
        return pauli_1q
    pauli = pauli_1q
    for _ in range(num_qubits - 1):
        pauli = pauli_1q.tensor(pauli)
    if weight:
        return pauli.sort(weight=True)
    return pauli
Esempio n. 3
0
def pauli_basis(num_qubits, weight=False, pauli_list=False):
    """Return the ordered PauliTable or PauliList for the n-qubit Pauli basis.

    Args:
        num_qubits (int): number of qubits
        weight (bool): if True optionally return the basis sorted by Pauli weight
                       rather than lexicographic order (Default: False)
        pauli_list (bool): if True, the return type becomes PauliList, otherwise PauliTable.

    Returns:
        PauliTable, PauliList: the Paulis for the basis
    """
    if pauli_list:
        pauli_1q = PauliList(["I", "X", "Y", "Z"])
    else:
        warnings.warn(
            "The return type of 'pauli_basis' will change from PauliTable to PauliList in a "
            "future release of Qiskit Terra.  Returning PauliTable is deprecated as of "
            "Qiskit Terra 0.19, and will be removed in a future release.  To immediately switch "
            "to the new behaviour, pass the keyword argument 'pauli_list=True'.",
            FutureWarning,
            stacklevel=2,
        )
        pauli_1q = PauliTable(
            np.array(
                [[False, False], [True, False], [True, True], [False, True]],
                dtype=bool))
    if num_qubits == 1:
        return pauli_1q
    pauli = pauli_1q
    for _ in range(num_qubits - 1):
        pauli = pauli_1q.tensor(pauli)
    if weight:
        return pauli.sort(weight=True)
    return pauli
Esempio n. 4
0
    def compose(self, other, qargs=None, front=False):
        if qargs is None:
            qargs = getattr(other, "qargs", None)

        if not isinstance(other, SparsePauliOp):
            other = SparsePauliOp(other)

        # Validate composition dimensions and qargs match
        self._op_shape.compose(other._op_shape, qargs, front)

        if qargs is not None:
            x1, z1 = self.paulis.x[:, qargs], self.paulis.z[:, qargs]
        else:
            x1, z1 = self.paulis.x, self.paulis.z
        x2, z2 = other.paulis.x, other.paulis.z
        num_qubits = other.num_qubits

        # This method is the outer version of `BasePauli.compose`.
        # `x1` and `z1` have shape `(self.size, num_qubits)`.
        # `x2` and `z2` have shape `(other.size, num_qubits)`.
        # `x1[:, no.newaxis]` results in shape `(self.size, 1, num_qubits)`.
        # `ar = ufunc(x1[:, np.newaxis], x2)` will be in shape `(self.size, other.size, num_qubits)`.
        # So, `ar.reshape((-1, num_qubits))` will be in shape `(self.size * other.size, num_qubits)`.
        # Ref: https://numpy.org/doc/stable/user/theory.broadcasting.html

        phase = np.add.outer(self.paulis._phase,
                             other.paulis._phase).reshape(-1)
        if front:
            q = np.logical_and(x1[:, np.newaxis], z2).reshape((-1, num_qubits))
        else:
            q = np.logical_and(z1[:, np.newaxis], x2).reshape((-1, num_qubits))
        # `np.mod` will be applied to `phase` in `SparsePauliOp.__init__`
        phase = phase + 2 * q.sum(axis=1, dtype=np.uint8)

        x3 = np.logical_xor(x1[:, np.newaxis], x2).reshape((-1, num_qubits))
        z3 = np.logical_xor(z1[:, np.newaxis], z2).reshape((-1, num_qubits))

        if qargs is None:
            pauli_list = PauliList(BasePauli(z3, x3, phase))
        else:
            x4 = np.repeat(self.paulis.x, other.size, axis=0)
            z4 = np.repeat(self.paulis.z, other.size, axis=0)
            x4[:, qargs] = x3
            z4[:, qargs] = z3
            pauli_list = PauliList(BasePauli(z4, x4, phase))

        # note: the following is a faster code equivalent to
        # `coeffs = np.kron(self.coeffs, other.coeffs)`
        # since `self.coeffs` and `other.coeffs` are both 1d arrays.
        coeffs = np.multiply.outer(self.coeffs, other.coeffs).ravel()
        return SparsePauliOp(pauli_list, coeffs, copy=False)
Esempio n. 5
0
    def sum(ops):
        """Sum of SparsePauliOps.

        This is a specialized version of the builtin ``sum`` function for SparsePauliOp
        with smaller overhead.

        Args:
            ops (list[SparsePauliOp]): a list of SparsePauliOps.

        Returns:
            SparsePauliOp: the SparsePauliOp representing the sum of the input list.

        Raises:
            QiskitError: if the input list is empty.
            QiskitError: if the input list includes an object that is not SparsePauliOp.
            QiskitError: if the numbers of qubits of the objects in the input list do not match.
        """
        if len(ops) == 0:
            raise QiskitError("Input list is empty")
        if not all(isinstance(op, SparsePauliOp) for op in ops):
            raise QiskitError(
                "Input list includes an object that is not SparsePauliOp")
        for other in ops[1:]:
            ops[0]._op_shape._validate_add(other._op_shape)

        z = np.vstack([op.paulis.z for op in ops])
        x = np.vstack([op.paulis.x for op in ops])
        phase = np.hstack([op.paulis._phase for op in ops])
        pauli_list = PauliList(BasePauli(z, x, phase))
        coeffs = np.hstack([op.coeffs for op in ops])
        return SparsePauliOp(pauli_list,
                             coeffs,
                             ignore_pauli_phase=True,
                             copy=False)
Esempio n. 6
0
    def compose(self, other, qargs=None, front=False):
        if qargs is None:
            qargs = getattr(other, "qargs", None)

        if not isinstance(other, SparsePauliOp):
            other = SparsePauliOp(other)

        # Validate composition dimensions and qargs match
        self._op_shape.compose(other._op_shape, qargs, front)

        if qargs is not None:
            x1, z1 = self.paulis.x[:, qargs], self.paulis.z[:, qargs]
        else:
            x1, z1 = self.paulis.x, self.paulis.z
        x2, z2 = other.paulis.x, other.paulis.z
        num_qubits = other.num_qubits

        # This method is the outer version of `BasePauli.compose`.
        # `x1` and `z1` have shape `(self.size, num_qubits)`.
        # `x2` and `z2` have shape `(other.size, num_qubits)`.
        # `x1[:, no.newaxis]` results in shape `(self.size, 1, num_qubits)`.
        # `ar = ufunc(x1[:, np.newaxis], x2)` will be in shape `(self.size, other.size, num_qubits)`.
        # So, `ar.reshape((-1, num_qubits))` will be in shape `(self.size * other.size, num_qubits)`.
        # Ref: https://numpy.org/doc/stable/user/theory.broadcasting.html

        phase = np.add.outer(self.paulis._phase,
                             other.paulis._phase).reshape(-1)
        if front:
            q = np.logical_and(x1[:, np.newaxis], z2).reshape((-1, num_qubits))
        else:
            q = np.logical_and(z1[:, np.newaxis], x2).reshape((-1, num_qubits))
        phase = np.mod(phase + 2 * np.sum(q, axis=1), 4)

        x3 = np.logical_xor(x1[:, np.newaxis], x2).reshape((-1, num_qubits))
        z3 = np.logical_xor(z1[:, np.newaxis], z2).reshape((-1, num_qubits))

        if qargs is None:
            pauli_list = PauliList(BasePauli(z3, x3, phase))
        else:
            x4 = np.repeat(self.paulis.x, other.size, axis=0)
            z4 = np.repeat(self.paulis.z, other.size, axis=0)
            x4[:, qargs] = x3
            z4[:, qargs] = z3
            pauli_list = PauliList(BasePauli(z4, x4, phase))

        coeffs = np.kron(self.coeffs, other.coeffs)
        return SparsePauliOp(pauli_list, coeffs)
Esempio n. 7
0
    def from_sparse_list(obj, num_qubits):
        """Construct from a list of local Pauli strings and coefficients.

        Each list element is a 3-tuple of a local Pauli string, indices where to apply it,
        and a coefficient.

        For example, the 5-qubit Hamiltonian

        .. math::

            H = Z_1 X_4 + 2 Y_0 Y_3

        can be constructed as

        .. code-block:: python

            # via triples and local Paulis with indices
            op = SparsePauliOp.from_sparse_list([("ZX", [1, 4], 1), ("YY", [0, 3], 2)], num_qubits=5)

            # equals the following construction from "dense" Paulis
            op = SparsePauliOp.from_list([("XIIZI", 1), ("IYIIY", 2)])

        Args:
            obj (Iterable[Tuple[str, List[int], complex]]): The list 3-tuples specifying the Paulis.
            num_qubits (int): The number of qubits of the operator.

        Returns:
            SparsePauliOp: The SparsePauliOp representation of the Pauli terms.

        Raises:
            QiskitError: If the list of Paulis is empty.
            QiskitError: If the number of qubits is incompatible with the indices of the Pauli terms.
        """
        obj = list(obj)  # To convert zip or other iterable

        size = len(obj)  # number of Pauli terms
        if size == 0:
            raise QiskitError("Input Pauli list is empty.")

        coeffs = np.zeros(size, dtype=complex)
        labels = np.zeros(size, dtype=f"<U{num_qubits}")

        for i, (paulis, indices, coeff) in enumerate(obj):
            # construct the full label based off the non-trivial Paulis and indices
            label = ["I"] * num_qubits
            for pauli, index in zip(paulis, indices):
                if index >= num_qubits:
                    raise QiskitError(
                        f"The number of qubits ({num_qubits}) is smaller than a required index {index}."
                    )
                label[~index] = pauli

            labels[i] = "".join(label)
            coeffs[i] = coeff

        paulis = PauliList(labels)
        return SparsePauliOp(paulis, coeffs, copy=False)
Esempio n. 8
0
    def simplify(self, atol=None, rtol=None):
        """Simplify PauliList by combining duplicates and removing zeros.

        Args:
            atol (float): Optional. Absolute tolerance for checking if
                          coefficients are zero (Default: 1e-8).
            rtol (float): Optional. relative tolerance for checking if
                          coefficients are zero (Default: 1e-5).

        Returns:
            SparsePauliOp: the simplified SparsePauliOp operator.
        """
        # Get default atol and rtol
        if atol is None:
            atol = self.atol
        if rtol is None:
            rtol = self.rtol

        # Filter non-zero coefficients
        non_zero = np.logical_not(
            np.isclose(self.coeffs, 0, atol=atol, rtol=rtol))
        paulis_x = self.paulis.x[non_zero]
        paulis_z = self.paulis.z[non_zero]
        nz_coeffs = self.coeffs[non_zero]

        # Pack bool vectors into np.uint8 vectors by np.packbits
        array = np.packbits(paulis_x, axis=1) * 256 + np.packbits(paulis_z,
                                                                  axis=1)
        indexes, inverses = unordered_unique(array)

        if np.all(non_zero) and indexes.shape[0] == array.shape[0]:
            # No zero operator or duplicate operator
            return self.copy()

        coeffs = np.zeros(indexes.shape[0], dtype=complex)
        np.add.at(coeffs, inverses, nz_coeffs)
        # Delete zero coefficient rows
        is_zero = np.isclose(coeffs, 0, atol=atol, rtol=rtol)
        # Check edge case that we deleted all Paulis
        # In this case we return an identity Pauli with a zero coefficient
        if np.all(is_zero):
            x = np.zeros((1, self.num_qubits), dtype=bool)
            z = np.zeros((1, self.num_qubits), dtype=bool)
            coeffs = np.array([0j], dtype=complex)
        else:
            non_zero = np.logical_not(is_zero)
            non_zero_indexes = indexes[non_zero]
            x = paulis_x[non_zero_indexes]
            z = paulis_z[non_zero_indexes]
            coeffs = coeffs[non_zero]

        return SparsePauliOp(PauliList.from_symplectic(z, x),
                             coeffs,
                             ignore_pauli_phase=True,
                             copy=False)
Esempio n. 9
0
    def _evolve_clifford(self, other, qargs=None, frame="h"):
        """Heisenberg picture evolution of a Pauli by a Clifford."""
        if qargs is None:
            idx = slice(None)
            num_act = self.num_qubits
        else:
            idx = list(qargs)
            num_act = len(idx)

        # Set return to I on qargs
        ret = self.copy()
        ret._x[:, idx] = False
        ret._z[:, idx] = False

        # pylint: disable=cyclic-import
        from qiskit.quantum_info.operators.symplectic.pauli import Pauli
        from qiskit.quantum_info.operators.symplectic.pauli_list import PauliList

        # Get action of Pauli's from Clifford
        if frame == "s":
            adj = other.copy()
        else:
            adj = other.adjoint()
        pauli_list = []
        for z in self._z[:, idx]:
            pauli = Pauli("I" * num_act)
            for row in adj.stabilizer[z]:
                pauli.compose(Pauli((row.Z[0], row.X[0], 2 * row.phase[0])),
                              inplace=True)
            pauli_list.append(pauli)
        ret.dot(PauliList(pauli_list), qargs=qargs, inplace=True)

        pauli_list = []
        for x in self._x[:, idx]:
            pauli = Pauli("I" * num_act)
            for row in adj.destabilizer[x]:
                pauli.compose(Pauli((row.Z[0], row.X[0], 2 * row.phase[0])),
                              inplace=True)
            pauli_list.append(pauli)
        ret.dot(PauliList(pauli_list), qargs=qargs, inplace=True)
        return ret
Esempio n. 10
0
 def from_list(obj):
     """Construct from a list [(pauli_str, coeffs)]"""
     obj = list(obj)  # To convert zip or other iterable
     num_qubits = len(obj[0][0])
     size = len(obj)
     coeffs = np.zeros(size, dtype=complex)
     labels = np.zeros(size, dtype=f"<U{num_qubits}")
     for i, item in enumerate(obj):
         labels[i] = item[0]
         coeffs[i] = item[1]
     paulis = PauliList(labels)
     return SparsePauliOp(paulis, coeffs)
Esempio n. 11
0
    def compose(self, other, qargs=None, front=False):
        if qargs is None:
            qargs = getattr(other, "qargs", None)

        if not isinstance(other, SparsePauliOp):
            other = SparsePauliOp(other)

        # Validate composition dimensions and qargs match
        self._op_shape.compose(other._op_shape, qargs, front)

        x1 = np.reshape(
            np.stack(other.size * [self.paulis.x], axis=1),
            (self.size * other.size, self.num_qubits),
        )
        z1 = np.reshape(
            np.stack(other.size * [self.paulis.z], axis=1),
            (self.size * other.size, self.num_qubits),
        )
        p1 = np.reshape(
            np.stack(other.size * [self.paulis.phase], axis=1),
            self.size * other.size,
        )
        paulis1 = PauliList.from_symplectic(z1, x1, p1)
        x2 = np.reshape(
            np.stack(self.size * [other.paulis.x]), (self.size * other.size, other.num_qubits)
        )
        z2 = np.reshape(
            np.stack(self.size * [other.paulis.z]), (self.size * other.size, other.num_qubits)
        )
        p2 = np.reshape(
            np.stack(self.size * [other.paulis.phase]),
            self.size * other.size,
        )
        paulis2 = PauliList.from_symplectic(z2, x2, p2)

        pauli_list = paulis1.compose(paulis2, qargs, front)
        coeffs = np.kron(self.coeffs, other.coeffs)

        return SparsePauliOp(pauli_list, coeffs)
Esempio n. 12
0
 def _multiply(self, other):
     if not isinstance(other, Number):
         raise QiskitError("other is not a number")
     if other == 0:
         # Check edge case that we deleted all Paulis
         # In this case we return an identity Pauli with a zero coefficient
         paulis = PauliList.from_symplectic(
             np.zeros((1, self.num_qubits), dtype=bool),
             np.zeros((1, self.num_qubits), dtype=bool),
         )
         coeffs = np.array([0j])
         return SparsePauliOp(paulis, coeffs)
     # Otherwise we just update the phases
     return SparsePauliOp(self.paulis, other * self.coeffs)
Esempio n. 13
0
    def simplify(self, atol=None, rtol=None):
        """Simplify PauliList by combining duplicates and removing zeros.

        Args:
            atol (float): Optional. Absolute tolerance for checking if
                          coefficients are zero (Default: 1e-8).
            rtol (float): Optional. relative tolerance for checking if
                          coefficients are zero (Default: 1e-5).

        Returns:
            SparsePauliOp: the simplified SparsePauliOp operator.
        """
        # Get default atol and rtol
        if atol is None:
            atol = self.atol
        if rtol is None:
            rtol = self.rtol

        array = np.column_stack((self.paulis.x, self.paulis.z))
        flatten_paulis, indexes = np.unique(array, return_inverse=True, axis=0)
        coeffs = np.zeros(self.size, dtype=complex)
        for i, val in zip(indexes, self.coeffs):
            coeffs[i] += val
        # Delete zero coefficient rows
        # TODO: Add atol/rtol for zero comparison
        non_zero = [
            i for i in range(coeffs.size) if not np.isclose(coeffs[i], 0, atol=atol, rtol=rtol)
        ]
        # Check edge case that we deleted all Paulis
        # In this case we return an identity Pauli with a zero coefficient
        if len(non_zero) == 0:
            x = np.zeros((1, self.num_qubits), dtype=bool)
            z = np.zeros((1, self.num_qubits), dtype=bool)
            coeffs = np.array([0j], dtype=complex)
        else:
            x, z = (
                flatten_paulis[non_zero]
                .reshape((len(non_zero), 2, self.num_qubits))
                .transpose(1, 0, 2)
            )
            coeffs = coeffs[non_zero]
        return SparsePauliOp(PauliList.from_symplectic(z, x), coeffs)
Esempio n. 14
0
    def from_list(obj):
        """Construct from a list of Pauli strings and coefficients.

        For example, the 5-qubit Hamiltonian

        .. math::

            H = Z_1 X_4 + 2 Y_0 Y_3

        can be constructed as

        .. code-block:: python

            # via tuples and the full Pauli string
            op = SparsePauliOp.from_list([("XIIZI", 1), ("IYIIY", 2)])

        Args:
            obj (Iterable[Tuple[str, complex]]): The list of 2-tuples specifying the Pauli terms.

        Returns:
            SparsePauliOp: The SparsePauliOp representation of the Pauli terms.

        Raises:
            QiskitError: If the list of Paulis is empty.
        """
        obj = list(obj)  # To convert zip or other iterable

        size = len(obj)  # number of Pauli terms
        if size == 0:
            raise QiskitError("Input Pauli list is empty.")

        # determine the number of qubits
        num_qubits = len(obj[0][0])

        coeffs = np.zeros(size, dtype=complex)
        labels = np.zeros(size, dtype=f"<U{num_qubits}")
        for i, item in enumerate(obj):
            labels[i] = item[0]
            coeffs[i] = item[1]

        paulis = PauliList(labels)
        return SparsePauliOp(paulis, coeffs, copy=False)
Esempio n. 15
0
    def chop(self, tol=1e-14):
        """Set real and imaginary parts of the coefficients to 0 if ``< tol`` in magnitude.

        For example, the operator representing ``1+1e-17j X + 1e-17 Y`` with a tolerance larger
        than ``1e-17`` will be reduced to ``1 X`` whereas :meth:`.SparsePauliOp.simplify` would
        return ``1+1e-17j X``.

        If a both the real and imaginary part of a coefficient is 0 after chopping, the
        corresponding Pauli is removed from the operator.

        Args:
            tol (float): The absolute tolerance to check whether a real or imaginary part should
                be set to 0.

        Returns:
            SparsePauliOp: This operator with chopped coefficients.
        """
        realpart_nonzero = np.abs(self.coeffs.real) > tol
        imagpart_nonzero = np.abs(self.coeffs.imag) > tol

        remaining_indices = np.logical_or(realpart_nonzero, imagpart_nonzero)
        remaining_real = realpart_nonzero[remaining_indices]
        remaining_imag = imagpart_nonzero[remaining_indices]

        if len(remaining_real) == 0:  # if no Paulis are left
            x = np.zeros((1, self.num_qubits), dtype=bool)
            z = np.zeros((1, self.num_qubits), dtype=bool)
            coeffs = np.array([0j], dtype=complex)
        else:
            coeffs = np.zeros(np.count_nonzero(remaining_indices),
                              dtype=complex)
            coeffs.real[remaining_real] = self.coeffs.real[realpart_nonzero]
            coeffs.imag[remaining_imag] = self.coeffs.imag[imagpart_nonzero]

            x = self.paulis.x[remaining_indices]
            z = self.paulis.z[remaining_indices]

        return SparsePauliOp(PauliList.from_symplectic(z, x),
                             coeffs,
                             ignore_pauli_phase=True,
                             copy=False)
Esempio n. 16
0
    def _evolve_clifford(self, other, qargs=None, frame="h"):

        """Heisenberg picture evolution of a Pauli by a Clifford."""

        if frame == "s":
            adj = other
        else:
            adj = other.adjoint()

        if qargs is None:
            qargs_ = slice(None)
        else:
            qargs_ = list(qargs)

        # pylint: disable=cyclic-import
        from qiskit.quantum_info.operators.symplectic.pauli_list import PauliList

        num_paulis = self._x.shape[0]

        ret = self.copy()
        ret._x[:, qargs_] = False
        ret._z[:, qargs_] = False

        idx = np.concatenate((self._x[:, qargs_], self._z[:, qargs_]), axis=1)
        for idx_, row in zip(
            idx.T,
            PauliList.from_symplectic(z=adj.table.Z, x=adj.table.X, phase=2 * adj.table.phase),
        ):
            # most of the logic below is to properly index if self is a PauliList (2D),
            # while not trying to index if the object is just a Pauli (1D).
            if idx_.any():
                if np.sum(idx_) == num_paulis:
                    ret.compose(row, qargs=qargs, inplace=True)
                else:
                    ret[idx_] = ret[idx_].compose(row, qargs=qargs)

        return ret
Esempio n. 17
0
 def table(self, value):
     if not isinstance(value, PauliTable):
         value = PauliTable(value)
     self._pauli_list = PauliList(value)
Esempio n. 18
0
    def __init__(self,
                 data,
                 coeffs=None,
                 *,
                 ignore_pauli_phase=False,
                 copy=True):
        """Initialize an operator object.

        Args:
            data (PauliList or SparsePauliOp or PauliTable or Pauli or list or str): Pauli list of
                terms.  A list of Pauli strings or a Pauli string is also allowed.
            coeffs (np.ndarray): complex coefficients for Pauli terms.

                .. note::

                    If ``data`` is a :obj:`~SparsePauliOp` and ``coeffs`` is not ``None``, the value
                    of the ``SparsePauliOp.coeffs`` will be ignored, and only the passed keyword
                    argument ``coeffs`` will be used.

            ignore_pauli_phase (bool): if true, any ``phase`` component of a given :obj:`~PauliList`
                will be assumed to be zero.  This is more efficient in cases where a
                :obj:`~PauliList` has been constructed purely for this object, and it is already
                known that the phases in the ZX-convention are zero.  It only makes sense to pass
                this option when giving :obj:`~PauliList` data.  (Default: False)
            copy (bool): copy the input data if True, otherwise assign it directly, if possible.
                (Default: True)

        Raises:
            QiskitError: If the input data or coeffs are invalid.
        """
        if ignore_pauli_phase and not isinstance(data, PauliList):
            raise QiskitError(
                "ignore_pauli_list=True is only valid with PauliList data")

        if isinstance(data, SparsePauliOp):
            if coeffs is None:
                coeffs = data.coeffs
            data = data._pauli_list
            # `SparsePauliOp._pauli_list` is already compatible with the internal ZX-phase
            # convention.  See `BasePauli._from_array` for the internal ZX-phase convention.
            ignore_pauli_phase = True

        pauli_list = PauliList(
            data.copy() if copy and hasattr(data, "copy") else data)

        if coeffs is None:
            coeffs = np.ones(pauli_list.size, dtype=complex)
        else:
            coeffs = np.array(coeffs, copy=copy, dtype=complex)

        if ignore_pauli_phase:
            # Fast path used in copy operations, where the phase of the PauliList is already known
            # to be zero.  This path only works if the input data is compatible with the internal
            # ZX-phase convention.
            self._pauli_list = pauli_list
            self._coeffs = coeffs
        else:
            # move the phase of `pauli_list` to `self._coeffs`
            phase = pauli_list._phase
            count_y = pauli_list._count_y()
            self._coeffs = np.asarray((-1j)**(phase - count_y) * coeffs,
                                      dtype=complex)
            pauli_list._phase = np.mod(count_y, 4)
            self._pauli_list = pauli_list

        if self._coeffs.shape != (self._pauli_list.size, ):
            raise QiskitError("coeff vector is incorrect shape for number"
                              " of Paulis {} != {}".format(
                                  self._coeffs.shape, self._pauli_list.size))
        # Initialize LinearOp
        super().__init__(num_qubits=self._pauli_list.num_qubits)
Esempio n. 19
0
 def paulis(self, value):
     if not isinstance(value, PauliList):
         value = PauliList(value)
     self._pauli_list = value