qiskit-documentation/docs/guides/specify-observables-pauli.i...

287 lines
10 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "212400e8-9fb9-4969-982c-8e13b369ef3d",
"metadata": {},
"source": [
"# Specify observables in the Pauli basis"
]
},
{
"cell_type": "markdown",
"id": "15c3654c-0235-44c4-9223-2251c24ef060",
"metadata": {
"tags": [
"version-info"
]
},
"source": [
"<details>\n",
"<summary><b>Package versions</b></summary>\n",
"\n",
"The code on this page was developed using the following requirements.\n",
"We recommend using these versions or newer.\n",
"\n",
"```\n",
"qiskit[all]~=2.0.0\n",
"```\n",
"</details>"
]
},
{
"cell_type": "markdown",
"id": "a9c68a4e-189c-424b-9255-24226307c8ac",
"metadata": {},
"source": [
"In quantum mechanics, observables correspond to physical properties that can be measured.\n",
"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.\n",
"\n",
"To measure an $n$-qubit observable $O$ on a quantum computer, you must represent it as a sum of tensor products of Pauli operators, that is\n",
"\n",
"$$\n",
"O = \\sum_{k=1}^K \\alpha_k P_k,~~ P_k \\in \\{I, X, Y, Z\\}^{\\otimes n},~~ \\alpha_k \\in \\mathbb{R},\n",
"$$\n",
"\n",
"where\n",
"\n",
"$$\n",
"I = \\begin{pmatrix}\n",
"1 & 0 \\\\ 0 & 1\n",
"\\end{pmatrix}\n",
"~~\n",
"X = \\begin{pmatrix}\n",
"0 & 1 \\\\ 1 & 0\n",
"\\end{pmatrix}\n",
"~~\n",
"Y = \\begin{pmatrix}\n",
"0 & -i \\\\ i & 0\n",
"\\end{pmatrix}\n",
"~~\n",
"Z = \\begin{pmatrix}\n",
"1 & 0 \\\\ 0 & -1\n",
"\\end{pmatrix}\n",
"$$\n",
"\n",
"and you use the fact that an observable is Hermitian, as in, $O^\\dagger = O$. If $O$ is not Hermitian it can still be decomposed as a sum of Paulis, but the coefficient $\\alpha_k$ becomes complex.\n",
"\n",
"In many cases, the observable is naturally specified in this representation after mapping the system of interest to qubits.\n",
"For example, a spin-1/2 system can be mapped to an Ising Hamiltonian\n",
"\n",
"$$\n",
"H = \\sum_{\\langle i, j\\rangle} Z_i Z_j - \\sum_{i=1}^n X_i,\n",
"$$\n",
"\n",
"where the indices $\\langle i, j\\rangle$ run over interacting spins and the spins are subject to a transversal field in $X$.\n",
"The subscript index indicates which qubit the Pauli operator acts on, i.e. $X_i$ applies an $X$ operator on qubit $i$ and leaves the rest unchanged.\n",
"\n",
"In the Qiskit SDK, this Hamiltonian could be constructed with the following code."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "7a06c7c4-582d-47ef-951e-52b40c1bfffb",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"SparsePauliOp(['IIIIIIIIIIZZ', 'IIIIIIIIIZZI', 'IIIIIIIIZZII', 'IIIIIIIZZIII', 'IIIIIIZZIIII', 'IIIIIZZIIIII', 'IIIIZZIIIIII', 'IIIZZIIIIIII', 'IIZZIIIIIIII', 'IZZIIIIIIIII', 'ZZIIIIIIIIII', 'IIIIIIIIIIIX', 'IIIIIIIIIIXI', 'IIIIIIIIIXII', 'IIIIIIIIXIII', 'IIIIIIIXIIII', 'IIIIIIXIIIII', 'IIIIIXIIIIII', 'IIIIXIIIIIII', 'IIIXIIIIIIII', 'IIXIIIIIIIII', 'IXIIIIIIIIII', 'XIIIIIIIIIII'],\n",
" 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,\n",
" 1.+0.j, 1.+0.j, 1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j,\n",
" -1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j, -1.+0.j])\n"
]
}
],
"source": [
"from qiskit.quantum_info import SparsePauliOp\n",
"\n",
"# define the number of qubits\n",
"n = 12\n",
"\n",
"# define the single Pauli terms as (\"Paulis\", [indices], coefficient)\n",
"interactions = [\n",
" (\"ZZ\", [i, i + 1], 1) for i in range(n - 1)\n",
"] # we assume spins on a 1D line\n",
"field = [(\"X\", [i], -1) for i in range(n)]\n",
"\n",
"# build the operator\n",
"hamiltonian = SparsePauliOp.from_sparse_list(\n",
" interactions + field, num_qubits=n\n",
")\n",
"print(hamiltonian)"
]
},
{
"cell_type": "markdown",
"id": "a8624db2-9658-48e4-ae16-d2dcabe1d822",
"metadata": {},
"source": [
"If we would like to measure the energy the observable is the Hamiltonian itself. Alternatively, we could be\n",
"interested in measuring system properties like the average magnetization by counting the number of spins\n",
"aligned in the $Z$-direction with the observable\n",
"\n",
"$$\n",
"O = \\frac{1}{n} \\sum_{i=1} Z_i\n",
"$$\n",
"\n",
"For observables that are not given in terms of Pauli operators but in a matrix form, we first have to reformulate them\n",
"in the Pauli basis in order to evaluate them on a quantum computer.\n",
"We are always able to find such a representation as the Pauli matrices form a basis for the Hermitian $2^n \\times 2^n$ matrices.\n",
"We expand the observable $O$ as\n",
"\n",
"$$\n",
"O = \\sum_{P \\in \\{I, X, Y, Z\\}^{\\otimes n}} \\mathrm{Tr}(O P) P,\n",
"$$\n",
"\n",
"where the sum runs over all possible $n$-qubit Pauli terms and $\\mathrm{Tr}(\\cdot)$ is the trace of a matrix, which acts as inner product.\n",
"You can implement this decomposition from a matrix to Pauli terms using the `SparsePauliOp.from_operator` method, like so:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "82856434-b283-4bb2-a9b0-300c2c9388af",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"SparsePauliOp(['IZ', 'XI', 'YY'],\n",
" coeffs=[-1. +0.j, 0.5+0.j, 1. -0.j])\n"
]
}
],
"source": [
"import numpy as np\n",
"from qiskit.quantum_info import SparsePauliOp\n",
"\n",
"matrix = np.array(\n",
" [[-1, 0, 0.5, -1], [0, 1, 1, 0.5], [0.5, 1, -1, 0], [-1, 0.5, 0, 1]]\n",
")\n",
"\n",
"observable = SparsePauliOp.from_operator(matrix)\n",
"print(observable)"
]
},
{
"cell_type": "markdown",
"id": "444aa9c6-1b6f-4834-a96d-1fcba9e0a3af",
"metadata": {},
"source": [
"This means the matrix can be written as Pauli terms as $O = -Z_1 + 0.5 X_2 + Y_2 Y_1$.\n",
"\n",
"<Admonition type=\"note\">\n",
" Remember the tensor product order maps to qubits as $q_n \\otimes q_{n-1} \\otimes \\cdots \\otimes q_1$.\n",
"</Admonition>\n",
"\n",
"<Admonition type=\"note\">\n",
" If the observable is Hermitian (meaning $O^\\dagger = O$), the Pauli coefficients are real numbers.\n",
" We can, however, also decompose any other complex matrix in terms of Paulis, if we allow for complex-valued coefficients.\n",
"</Admonition>\n",
"\n",
"\n",
"## Measure in Pauli bases\n",
"\n",
"A measurement projects the qubit state to the computational basis $\\{|0\\rangle, |1\\rangle\\}$. This implies that you can only measure observables that are diagonal in this basis, such as Paulis consisting only of $I$ and $Z$ terms.\n",
"Measuring arbitrary Pauli terms therefore requires a change of basis to diagonalize them. To do this, perform the following transformations,\n",
"\n",
"$$\n",
"\\begin{aligned}\n",
" X &\\rightarrow Z = H X H \\\\\n",
" Y &\\rightarrow Z = H S^\\dagger Y S H,\n",
"\\end{aligned}\n",
"$$\n",
"\n",
"where $H$ is the Hadamard gate and $S = \\sqrt{Z}$ is sometimes referred to as the phase gate.\n",
"If you are using an [Estimator](/docs/api/qiskit/1.4/qiskit.primitives.Estimator) to compute expectation values, the basis transformations are automatically performed.\n",
"\n",
"Below is an example demonstrating how to prepare a quantum circuit and manually measure the qubit 0 in the X basis,\n",
"qubit 1 in the Y basis and qubit 2 in the Z basis.\n",
"We apply the transformations shown in the previous equation and obtain the following circuit:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "ce4b1984-ebe0-44f6-a78c-d67b9e9bb361",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<Image src=\"/docs/images/guides/specify-observables-pauli/extracted-outputs/ce4b1984-ebe0-44f6-a78c-d67b9e9bb361-0.svg\" alt=\"Output of the previous code cell\" />"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from qiskit.circuit import QuantumCircuit\n",
"\n",
"# create a circuit, where we would like to measure\n",
"# q0 in the X basis, q1 in the Y basis and q2 in the Z basis\n",
"circuit = QuantumCircuit(3)\n",
"circuit.ry(0.8, 0)\n",
"circuit.cx(0, 1)\n",
"circuit.cx(1, 2)\n",
"circuit.barrier()\n",
"\n",
"# diagonalize X with the Hadamard gate\n",
"circuit.h(0)\n",
"\n",
"# diagonalize Y with Hadamard as S^\\dagger\n",
"circuit.sdg(1)\n",
"circuit.h(1)\n",
"\n",
"# the Z basis is the default, no action required here\n",
"\n",
"# measure all qubits\n",
"circuit.measure_all()\n",
"circuit.draw(\"mpl\")"
]
},
{
"cell_type": "markdown",
"id": "6e52d357-b225-4c50-abba-7d78211e2fa5",
"metadata": {},
"source": [
"## Next steps\n",
"\n",
"<Admonition type=\"tip\" title=\"Recommendations\">\n",
" - See an example of circuit decomposition in the [Variational quantum eigensolver](https://learning.quantum.ibm.com/tutorial/variational-quantum-eigensolver) tutorial.\n",
" - Read the [SparsePauliOp API](/docs/api/qiskit/qiskit.quantum_info.SparsePauliOp#sparsepauliop) reference.\n",
"</Admonition>"
]
}
],
"metadata": {
"description": "Measure circuits in different Pauli bases, which is required to measure observables that are not diagonal in the computational basis.",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3"
},
"title": "Specify observables in the Pauli basis"
},
"nbformat": 4,
"nbformat_minor": 5
}