qml.pauli.pauli_decompose

pauli_decompose(H, hide_identity=False, wire_order=None, pauli=False, check_hermitian=True)[source]

Decomposes a Hermitian matrix into a linear combination of Pauli operators.

Parameters:
  • H (tensor_like[complex] or scipy.sparse matrix) – a Hermitian matrix of dimension \(2^n\times 2^n\). Scipy sparse matrices are also supported and are processed natively without converting to dense format, enabling efficient decomposition of large sparse matrices.

  • hide_identity (bool) – does not include the Identity observable within the tensor products of the decomposition if True.

  • wire_order (list[Union[int, str]]) – the ordered list of wires with respect to which the operator is represented as a matrix.

  • pauli (bool) – return a PauliSentence instance if True.

  • check_hermitian (bool) – check if the provided matrix is Hermitian if True.

Returns:

the matrix decomposed as a linear combination of Pauli operators, returned either as a LinearCombination or PauliSentence instance.

Return type:

Union[LinearCombination, PauliSentence]

Example:

We can use this function to compute the Pauli operator decomposition of an arbitrary Hermitian matrix:

>>> import pennylane as qml
>>> import numpy as np
>>> A = np.array(
... [[-2, -2+1j, -2, -2], [-2-1j,  0,  0, -1], [-2,  0, -2, -1], [-2, -1, -1,  0]])
>>> H = qml.pauli_decompose(A)
>>> import pprint
>>> pprint.pprint(H)
(
    -1.0 * (I(0) @ I(1))
  + -1.5 * (I(0) @ X(1))
  + -0.5 * (I(0) @ Y(1))
  + -1.0 * (I(0) @ Z(1))
  + -1.5 * (X(0) @ I(1))
  + -1.0 * (X(0) @ X(1))
  + -0.5 * (X(0) @ Z(1))
  + 1.0 * (Y(0) @ Y(1))
  + -0.5 * (Z(0) @ X(1))
  + -0.5 * (Z(0) @ Y(1))
)

We can return a PauliSentence instance by using the keyword argument pauli=True:

>>> ps = qml.pauli_decompose(A, pauli=True)
>>> print(ps)
-1.0 * I
+ -1.5 * X(1)
+ -0.5 * Y(1)
+ -1.0 * Z(1)
+ -1.5 * X(0)
+ -1.0 * X(0) @ X(1)
+ -0.5 * X(0) @ Z(1)
+ 1.0 * Y(0) @ Y(1)
+ -0.5 * Z(0) @ X(1)
+ -0.5 * Z(0) @ Y(1)

By default the wires are numbered [0, 1, …, n], but we can also set custom wires using the wire_order argument:

>>> ps = qml.pauli_decompose(A, pauli=True, wire_order=['a', 'b'])
>>> print(ps)
-1.0 * I
+ -1.5 * X(b)
+ -0.5 * Y(b)
+ -1.0 * Z(b)
+ -1.5 * X(a)
+ -1.0 * X(a) @ X(b)
+ -0.5 * X(a) @ Z(b)
+ 1.0 * Y(a) @ Y(b)
+ -0.5 * Z(a) @ X(b)
+ -0.5 * Z(a) @ Y(b)

This method internally uses a generalized decomposition routine to convert the matrix to a weighted sum of Pauli words acting on \(n\) qubits in time \(O(n 4^n)\). The input matrix is written as a quantum state in the computational basis following the channel-state duality. A Bell basis transformation is then performed using the Walsh-Hadamard transform, after which coefficients for each of the \(4^n\) Pauli words are computed while accounting for the phase from each PauliY term occurring in the word.

Scipy sparse matrices are also supported and processed natively without converting to dense format, enabling efficient decomposition of large sparse matrices. For example:

>>> import scipy.sparse as sps
>>> sparse_H = sps.csr_matrix([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])
>>> qml.pauli_decompose(sparse_H)
1.0 * (Z(0) @ Z(1))