qiskit-documentation/docs/guides/operators-overview.ipynb

579 lines
16 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "434beca8-b15d-4f42-a887-4636fb692789",
"metadata": {},
"source": [
"# Overview of operator classes"
]
},
{
"cell_type": "markdown",
"id": "434beca86fbddfbe-75b2-44d7-8783-b756382fd6d5",
"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]~=1.2.4\n",
"qiskit-aer~=0.15.1\n",
"qiskit-ibm-runtime~=0.31.0\n",
"qiskit-serverless~=0.17.1\n",
"qiskit-ibm-catalog~=0.1\n",
"```\n",
"</details>"
]
},
{
"cell_type": "markdown",
"id": "1c4cfc09-242c-4389-b03e-8c241c573306",
"metadata": {},
"source": [
"In Qiskit, quantum operators are represented using classes from the [`quantum_info`](/api/qiskit/quantum_info) module. The most important operator class is [`SparsePauliOp`](/api/qiskit/qiskit.quantum_info.SparsePauliOp), which represents a general quantum operator as a linear combination of Pauli strings. `SparsePauliOp` is the class most commonly used to represent quantum observables. The rest of this page explains how to use `SparsePauliOp` and other operator classes."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "6fc6f151-f2ca-44f6-811b-d15c71ee1fa6",
"metadata": {
"ExecuteTime": {
"end_time": "2019-08-21T09:02:56.554914Z",
"start_time": "2019-08-21T09:02:54.249612Z"
}
},
"outputs": [],
"source": [
"import numpy as np\n",
"from qiskit.quantum_info.operators import Operator, Pauli, SparsePauliOp"
]
},
{
"cell_type": "markdown",
"id": "23a940b3-fce0-4f84-8461-5a72c0ce9aa7",
"metadata": {},
"source": [
"## SparsePauliOp\n",
"\n",
"The [`SparsePauliOp`](/api/qiskit/qiskit.quantum_info.SparsePauliOp) class represents a linear combination of Pauli strings. There are several ways to initialize a `SparsePauliOp`, but the most flexible way is to use the [`from_sparse_list`](/api/qiskit/qiskit.quantum_info.SparsePauliOp#from_sparse_list) method, as demonstrated in the following code cell. The `from_sparse_list` accepts a list of `(pauli_string, qubit_indices, coefficient)` triplets."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "90053827-6a1f-4fb4-8188-808afe3ddd4f",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"SparsePauliOp(['XIIZI', 'IYIIY'],\n",
" coeffs=[ 1.+0.j, -1.+1.j])"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"op1 = SparsePauliOp.from_sparse_list(\n",
" [(\"ZX\", [1, 4], 1.0), (\"YY\", [0, 3], -1 + 1j)], num_qubits=5\n",
")\n",
"op1"
]
},
{
"cell_type": "markdown",
"id": "fc7ffabb-5245-4687-b84b-25176a64dc07",
"metadata": {},
"source": [
"`SparsePauliOp` supports arithmetic operations, as demonstrated in the following code cell."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "2e21467f-b6fe-4ac5-9654-66dec83a97fb",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"op1 + op2:\n",
"SparsePauliOp(['XIIZI', 'IYIIY', 'ZIIXX', 'IIZZI'],\n",
" coeffs=[ 1.+0.j, -1.+1.j, 1.+2.j, -1.+1.j])\n",
"\n",
"2 * op1:\n",
"SparsePauliOp(['XIIZI', 'IYIIY'],\n",
" coeffs=[ 2.+0.j, -2.+2.j])\n",
"\n",
"op1 @ op2:\n",
"SparsePauliOp(['YIIYX', 'XIZII', 'ZYIXZ', 'IYZZY'],\n",
" coeffs=[ 1.+2.j, -1.+1.j, -1.+3.j, 0.-2.j])\n",
"\n",
"op1.tensor(op2):\n",
"SparsePauliOp(['XIIZIZIIXX', 'XIIZIIIZZI', 'IYIIYZIIXX', 'IYIIYIIZZI'],\n",
" coeffs=[ 1.+2.j, -1.+1.j, -3.-1.j, 0.-2.j])\n"
]
}
],
"source": [
"op2 = SparsePauliOp.from_sparse_list(\n",
" [(\"XXZ\", [0, 1, 4], 1 + 2j), (\"ZZ\", [1, 2], -1 + 1j)], num_qubits=5\n",
")\n",
"\n",
"# Addition\n",
"print(\"op1 + op2:\")\n",
"print(op1 + op2)\n",
"print()\n",
"# Multiplication by a scalar\n",
"print(\"2 * op1:\")\n",
"print(2 * op1)\n",
"print()\n",
"# Operator multiplication (composition)\n",
"print(\"op1 @ op2:\")\n",
"print(op1 @ op2)\n",
"print()\n",
"# Tensor product\n",
"print(\"op1.tensor(op2):\")\n",
"print(op1.tensor(op2))"
]
},
{
"cell_type": "markdown",
"id": "85fb16f2-5296-4c4d-9836-249358fd7e12",
"metadata": {},
"source": [
"## Pauli\n",
"\n",
"The [`Pauli`](/api/qiskit/qiskit.quantum_info.Pauli) class represents a single Pauli string with an optional phase coefficient from the set $\\set{+1, i, -1, -i}$. A `Pauli` can be initialized by passing a string of characters from the set `{\"I\", \"X\", \"Y\", \"Z\"}`, optionally prefixed by one of `{\"\", \"i\", \"-\", \"-i\"}` to represent the phase coefficient."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "edc33fe7-989e-489b-92f6-81975b20bd05",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Pauli('iXX')"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"op1 = Pauli(\"iXX\")\n",
"op1"
]
},
{
"cell_type": "markdown",
"id": "82c19270-98d0-4543-bad5-5bfaacee406f",
"metadata": {},
"source": [
"The following code cell demonstrates the use of some attributes and methods."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "69b105cd-e978-45be-a3e9-bab344d9111f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dimension of iXX: (4, 4)\n",
"Phase of iXX: 3\n",
"Matrix representation of iXX: \n",
" [[0.+0.j 0.+0.j 0.+0.j 0.+1.j]\n",
" [0.+0.j 0.+0.j 0.+1.j 0.+0.j]\n",
" [0.+0.j 0.+1.j 0.+0.j 0.+0.j]\n",
" [0.+1.j 0.+0.j 0.+0.j 0.+0.j]]\n"
]
}
],
"source": [
"print(f\"Dimension of {op1}: {op1.dim}\")\n",
"print(f\"Phase of {op1}: {op1.phase}\")\n",
"print(f\"Matrix representation of {op1}: \\n {op1.to_matrix()}\")"
]
},
{
"cell_type": "markdown",
"id": "4c4b1efe-4025-4b88-bbce-d0b3060e0ab1",
"metadata": {},
"source": [
"`Pauli` objects possess a number of other methods to manipulate the operators such as determining its adjoint, whether it (anti)commutes with another `Pauli`, and computing the dot product with another `Pauli`. Refer to the [API documentation](/api/qiskit/qiskit.quantum_info.Pauli) for more info."
]
},
{
"cell_type": "markdown",
"id": "0f02f8da-fab6-4ba6-b4ec-80d577cf8914",
"metadata": {},
"source": [
"## Operator\n",
"\n",
"The [`Operator`](/api/qiskit/qiskit.quantum_info.Operator) class represents a general linear operator. Unlike `SparsePauliOp`, `Operator` stores the linear operator as a dense matrix. Because the memory required to store a dense matrix scales exponentially with the number of qubits, the `Operator` class is only suitable for use with a small number of qubits.\n",
"\n",
"You can initialize an `Operator` by directly passing a Numpy array storing the matrix of the operator. For example, the following code cell creates a two-qubit Pauli XX operator:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "f8d9d183-586c-44ac-aa93-317a2adb40ad",
"metadata": {
"ExecuteTime": {
"end_time": "2019-08-21T09:02:56.572857Z",
"start_time": "2019-08-21T09:02:56.566140Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Operator([[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],\n",
" [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],\n",
" [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],\n",
" [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]],\n",
" input_dims=(2, 2), output_dims=(2, 2))\n"
]
}
],
"source": [
"XX = Operator(\n",
" np.array(\n",
" [\n",
" [0, 0, 0, 1],\n",
" [0, 0, 1, 0],\n",
" [0, 1, 0, 0],\n",
" [1, 0, 0, 0],\n",
" ]\n",
" )\n",
")\n",
"XX"
]
},
{
"cell_type": "markdown",
"id": "4ded9878-c239-4e79-a60e-fff048c15784",
"metadata": {},
"source": [
"The operator object stores the underlying matrix, and the input and output dimension of subsystems.\n",
"\n",
"* `data`: To access the underlying Numpy array, you can use the `Operator.data` property.\n",
"* `dims`: To return the total input and output dimension of the operator, you can use the `Operator.dim` property. *Note: the output is returned as a tuple* `(input_dim, output_dim)`, *which is the reverse of the shape of the underlying matrix.*"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "d9a6fe93-00a1-498f-9110-67b022db0a4f",
"metadata": {
"ExecuteTime": {
"end_time": "2019-08-21T09:02:56.589962Z",
"start_time": "2019-08-21T09:02:56.585681Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"array([[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],\n",
" [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],\n",
" [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],\n",
" [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"XX.data"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "784a657a-1731-4ecd-9bc0-aa0b96bc27e8",
"metadata": {
"ExecuteTime": {
"end_time": "2019-08-21T09:02:56.615497Z",
"start_time": "2019-08-21T09:02:56.611146Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"(4, 4)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"input_dim, output_dim = XX.dim\n",
"input_dim, output_dim"
]
},
{
"cell_type": "markdown",
"id": "0f84bf31-ce41-454a-9e2c-11c0ec4a04dc",
"metadata": {},
"source": [
"The operator class also keeps track of subsystem dimensions, which can be used for composing operators together. These can be accessed using the `input_dims` and `output_dims` functions.\n",
"\n",
"For $2^N$ by $2^M$ operators, the input and output dimensions are automatically assumed to be M-qubit and N-qubit:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "b4576985-9ae2-46f0-a29d-9ca3bea53bf0",
"metadata": {
"ExecuteTime": {
"end_time": "2019-08-21T09:02:56.804167Z",
"start_time": "2019-08-21T09:02:56.798857Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Input dimensions: (2, 2)\n",
"Output dimensions: (2,)\n"
]
}
],
"source": [
"op = Operator(np.random.rand(2**1, 2**2))\n",
"print(\"Input dimensions:\", op.input_dims())\n",
"print(\"Output dimensions:\", op.output_dims())"
]
},
{
"cell_type": "markdown",
"id": "9bae9b8c-b7f5-4e1e-ad8b-4482f19af531",
"metadata": {},
"source": [
"If the input matrix is not divisible into qubit subsystems, then it will be stored as a single-qubit operator. For example, for a $6\\times6$ matrix:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "186c1ac5-0bf2-4a86-84d8-bffa3f1763a1",
"metadata": {
"ExecuteTime": {
"end_time": "2019-08-21T09:02:57.764881Z",
"start_time": "2019-08-21T09:02:57.760401Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Input dimensions: (6,)\n",
"Output dimensions: (6,)\n"
]
}
],
"source": [
"op = Operator(np.random.rand(6, 6))\n",
"print(\"Input dimensions:\", op.input_dims())\n",
"print(\"Output dimensions:\", op.output_dims())"
]
},
{
"cell_type": "markdown",
"id": "e813709d-4ac3-4abc-863f-9d5d262ba753",
"metadata": {},
"source": [
"The input and output dimension can also be manually specified when initializing a new operator:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "e14faef6-3b05-4447-9960-3b140ddff1a1",
"metadata": {
"ExecuteTime": {
"end_time": "2019-08-21T09:02:58.292849Z",
"start_time": "2019-08-21T09:02:58.287354Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Input dimensions: (4,)\n",
"Output dimensions: (2,)\n"
]
}
],
"source": [
"# Force input dimension to be (4,) rather than (2, 2)\n",
"op = Operator(np.random.rand(2**1, 2**2), input_dims=[4])\n",
"print(\"Input dimensions:\", op.input_dims())\n",
"print(\"Output dimensions:\", op.output_dims())"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "41845475-f6e9-4057-b21e-89cf1a62f672",
"metadata": {
"ExecuteTime": {
"end_time": "2019-08-21T09:02:58.779572Z",
"start_time": "2019-08-21T09:02:58.774878Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Input dimensions: (2, 3)\n",
"Output dimensions: (2, 3)\n"
]
}
],
"source": [
"# Specify system is a qubit and qutrit\n",
"op = Operator(np.random.rand(6, 6), input_dims=[2, 3], output_dims=[2, 3])\n",
"print(\"Input dimensions:\", op.input_dims())\n",
"print(\"Output dimensions:\", op.output_dims())"
]
},
{
"cell_type": "markdown",
"id": "1ed55128-5b97-4733-ac0f-6b762e48691b",
"metadata": {},
"source": [
"You can also extract just the input or output dimensions of a subset of subsystems using the `input_dims` and `output_dims` functions:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "c9fe7460-8e93-47aa-acc1-425bfe797c17",
"metadata": {
"ExecuteTime": {
"end_time": "2019-08-21T09:03:02.187313Z",
"start_time": "2019-08-21T09:03:02.183719Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dimension of input system 0: (2,)\n",
"Dimension of input system 1: (3,)\n"
]
}
],
"source": [
"print(\"Dimension of input system 0:\", op.input_dims([0]))\n",
"print(\"Dimension of input system 1:\", op.input_dims([1]))"
]
},
{
"cell_type": "markdown",
"id": "3e8538f5-77d4-4683-838f-abff122cd3f7",
"metadata": {},
"source": [
"## Next steps\n",
"\n",
"<Admonition type=\"tip\" title=\"Recommendations\">\n",
" - Learn how to [specify observables in the Pauli basis](./specify-observables-pauli).\n",
" - See an example of using operators in the [Combine error mitigation options with the estimator primitive](https://learning.quantum.ibm.com/tutorial/combine-error-mitigation-options-with-the-estimator-primitive) tutorial.\n",
" - Read more [in-depth coverage of the Operator class](./operator-class).\n",
" - Explore the [Operator API](/api/qiskit/qiskit.quantum_info.Operator#operator) reference.\n",
"</Admonition>"
]
}
],
"metadata": {
"anaconda-cloud": {},
"celltoolbar": "Tags",
"description": "Use the Qiskit quantum information module to construct and manipulate operators",
"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": "Operators module overview",
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}