Skip to main contentIBM Quantum Documentation

Specify observables in the Pauli basis

Package versions

The code on this page was developed using the following requirements. We recommend using these versions or newer.

qiskit[all]~=1.2.4
qiskit-aer~=0.15.1
qiskit-ibm-runtime~=0.31.0
qiskit-serverless~=0.17.1
qiskit-ibm-catalog~=0.1

In quantum mechanics, observables correspond to physical properties that can be measured. When considering a system of spins, for example, you could be interested in measuring the system's energy or obtaining information about the alignment of the spins, such as the magnetization or the correlations between spins.

To measure an nn-qubit observable OO on a quantum computer, you must represent it as a sum of tensor products of Pauli operators, that is

O=k=1KαkPk,  Pk{I,X,Y,Z}n,  αkR,O = \sum_{k=1}^K \alpha_k P_k,~~ P_k \in \{I, X, Y, Z\}^{\otimes n},~~ \alpha_k \in \mathbb{R},

where

I=(1001)  X=(0110)  Y=(0ii0)  Z=(1001)I = \begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix} ~~ X = \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix} ~~ Y = \begin{pmatrix} 0 & -i \\ i & 0 \end{pmatrix} ~~ Z = \begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix}

and you use the fact that an observable is Hermitian, as in, O=OO^\dagger = O. If OO is not Hermitian it can still be decomposed as a sum of Paulis, but the coefficient αk\alpha_k becomes complex.

In many cases, the observable is naturally specified in this representation after mapping the system of interest to qubits. For example, a spin-1/2 system can be mapped to an Ising Hamiltonian

H=i,jZiZji=1nXi,H = \sum_{\langle i, j\rangle} Z_i Z_j - \sum_{i=1}^n X_i,

where the indices i,j\langle i, j\rangle run over interacting spins and the spins are subject to a transversal field in XX. The subscript index indicates which qubit the Pauli operator acts on, i.e. XiX_i applies an XX operator on qubit ii and leaves the rest unchanged.

In the Qiskit SDK, this Hamiltonian could be constructed with the following code.

from qiskit.quantum_info import SparsePauliOp
 
# define the number of qubits
n = 12
 
# define the single Pauli terms as ("Paulis", [indices], coefficient)
interactions = [
    ("ZZ", [i, i + 1], 1) for i in range(n - 1)
]  # we assume spins on a 1D line
field = [("X", [i], -1) for i in range(n)]
 
# build the operator
hamiltonian = SparsePauliOp.from_sparse_list(
    interactions + field, num_qubits=n
)
print(hamiltonian)

Output:

SparsePauliOp(['IIIIIIIIIIZZ', 'IIIIIIIIIZZI', 'IIIIIIIIZZII', 'IIIIIIIZZIII', 'IIIIIIZZIIII', 'IIIIIZZIIIII', 'IIIIZZIIIIII', 'IIIZZIIIIIII', 'IIZZIIIIIIII', 'IZZIIIIIIIII', 'ZZIIIIIIIIII', 'IIIIIIIIIIIX', 'IIIIIIIIIIXI', 'IIIIIIIIIXII', 'IIIIIIIIXIII', 'IIIIIIIXIIII', 'IIIIIIXIIIII', 'IIIIIXIIIIII', 'IIIIXIIIIIII', 'IIIXIIIIIIII', 'IIXIIIIIIIII', 'IXIIIIIIIIII', 'XIIIIIIIIIII'],
              coeffs=[ 1.+0.j,  1.+0.j,  1.+0.j,  1.+0.j,  1.+0.j,  1.+0.j,  1.+0.j,  1.+0.j,
  1.+0.j,  1.+0.j,  1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j,
 -1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j])

If we would like to measure the energy the observable is the Hamiltonian itself. Alternatively, we could be interested in measuring system properties like the average magnetization by counting the number of spins aligned in the ZZ-direction with the observable

O=1ni=1ZiO = \frac{1}{n} \sum_{i=1} Z_i

For observables that are not given in terms of Pauli operators but in a matrix form, we first have to reformulate them in the Pauli basis in order to evaluate them on a quantum computer. We are always able to find such a representation as the Pauli matrices form a basis for the Hermitian 2n×2n2^n \times 2^n matrices. We expand the observable OO as

O=P{I,X,Y,Z}nTr(OP)P,O = \sum_{P \in \{I, X, Y, Z\}^{\otimes n}} \mathrm{Tr}(O P) P,

where the sum runs over all possible nn-qubit Pauli terms and Tr()\mathrm{Tr}(\cdot) is the trace of a matrix, which acts as inner product. You can implement this decomposition from a matrix to Pauli terms using the SparsePauliOp.from_operator method, like so:

import numpy as np
from qiskit.quantum_info import SparsePauliOp
 
matrix = np.array(
    [[-1, 0, 0.5, -1], [0, 1, 1, 0.5], [0.5, 1, -1, 0], [-1, 0.5, 0, 1]]
)
 
observable = SparsePauliOp.from_operator(matrix)
print(observable)

Output:

SparsePauliOp(['IZ', 'XI', 'YY'],
              coeffs=[-1. +0.j,  0.5+0.j,  1. -0.j])

This means the matrix can be written as Pauli terms as O=Z1+0.5X2+Y2Y1O = -Z_1 + 0.5 X_2 + Y_2 Y_1.

Note

Remember the tensor product order maps to qubits as qnqn1q1q_n \otimes q_{n-1} \otimes \cdots \otimes q_1.

Note

If the observable is Hermitian (meaning O=OO^\dagger = O), the Pauli coefficients are real numbers. We can, however, also decompose any other complex matrix in terms of Paulis, if we allow for complex-valued coefficients.


Measure in Pauli bases

A measurement projects the qubit state to the computational basis {0,1}\{|0\rangle, |1\rangle\}. This implies that you can only measure observables that are diagonal in this basis, such as Paulis consisting only of II and ZZ terms. Measuring arbitrary Pauli terms therefore requires a change of basis to diagonalize them. To do this, perform the following transformations,

XZ=HXHYZ=HSYSH,\begin{aligned} X &\rightarrow Z = H X H \\ Y &\rightarrow Z = H S^\dagger Y S H, \end{aligned}

where HH is the Hadamard gate and S=ZS = \sqrt{Z} is sometimes referred to as the phase gate. If you are using an Estimator to compute expectation values, the basis transformations are automatically performed.

Below is an example demonstrating how to prepare a quantum circuit and manually measure the qubit 0 in the X basis, qubit 1 in the Y basis and qubit 2 in the Z basis. We apply the transformations shown in the previous equation and obtain the following circuit:

from qiskit.circuit import QuantumCircuit
 
# create a circuit, where we would like to measure
# q0 in the X basis, q1 in the Y basis and q2 in the Z basis
circuit = QuantumCircuit(3)
circuit.ry(0.8, 0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.barrier()
 
# diagonalize X with the Hadamard gate
circuit.h(0)
 
# diagonalize Y with Hadamard as S^\dagger
circuit.sdg(1)
circuit.h(1)
 
# the Z basis is the default, no action required here
 
# measure all qubits
circuit.measure_all()
circuit.draw("mpl")

Output:


Next steps

Recommendations
Was this page helpful?
Report a bug or request content on GitHub.