1070 lines
45 KiB
Plaintext
1070 lines
45 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Operators module overview"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"The `Operator` class is used in Qiskit to represent matrix operators acting on a quantum system. It has several methods to build composite operators using tensor products of smaller operators, and to compose operators.\n",
|
|
"\n",
|
|
"### Creating Operators\n",
|
|
"\n",
|
|
"The easiest way to create an operator object is to initialize it with a matrix given as a list or a Numpy array. For example, to create a two-qubit Pauli-XX operator:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"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",
|
|
"\n",
|
|
"from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister\n",
|
|
"from qiskit import BasicAer\n",
|
|
"from qiskit.quantum_info.operators import Operator, Pauli\n",
|
|
"from qiskit.quantum_info import process_fidelity\n",
|
|
"\n",
|
|
"from qiskit.extensions import RXGate, XGate, CXGate"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"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([[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]])\n",
|
|
"XX"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Operator Properties\n",
|
|
"\n",
|
|
"The operator object stores the underlying matrix, and the input and output dimension of subsystems. \n",
|
|
"\n",
|
|
"* `data`: To access the underlying Numpy array, we may use the `Operator.data` property.\n",
|
|
"* `dims`: To return the total input and output dimension of the operator, we may 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": 3,
|
|
"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": 3,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"XX.data"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"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": 4,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"input_dim, output_dim = XX.dim\n",
|
|
"input_dim, output_dim"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Input and Output Dimensions\n",
|
|
"\n",
|
|
"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 dimension will be automatically assumed to be M-qubit and N-qubit:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"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",
|
|
"metadata": {},
|
|
"source": [
|
|
"If the input matrix is not divisible into qubit subsystems, then it will be stored as a single-qubit operator. For example, if we have a $6\\times6$ matrix:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"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",
|
|
"metadata": {},
|
|
"source": [
|
|
"The input and output dimension can also be manually specified when initializing a new operator:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"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": 8,
|
|
"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),\n",
|
|
" 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",
|
|
"metadata": {},
|
|
"source": [
|
|
"We 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": 9,
|
|
"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",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Converting classes to Operators\n",
|
|
"\n",
|
|
"Several other classes in Qiskit can be directly converted to an `Operator` object using the operator initialization method. For example:\n",
|
|
"\n",
|
|
"* `Pauli` objects\n",
|
|
"* `Gate` and `Instruction` objects\n",
|
|
"* `QuantumCircuit` objects\n",
|
|
"\n",
|
|
"Note that the last point means we can use the `Operator` class as a unitary simulator to compute the final unitary matrix for a quantum circuit, without having to call a simulator backend. If the circuit contains any unsupported operations, an exception will be raised. Unsupported operations are: measure, reset, conditional operations, or a gate that does not have a matrix definition or decomposition in terms of gate with matrix definitions."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:03:02.854419Z",
|
|
"start_time": "2019-08-21T09:03:02.842387Z"
|
|
}
|
|
},
|
|
"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": [
|
|
"# Create an Operator from a Pauli object\n",
|
|
"\n",
|
|
"pauliXX = Pauli('XX')\n",
|
|
"Operator(pauliXX)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:03:03.064145Z",
|
|
"start_time": "2019-08-21T09:03:03.058953Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Operator([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n",
|
|
" [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",
|
|
" input_dims=(2, 2), output_dims=(2, 2))\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# Create an Operator for a Gate object\n",
|
|
"Operator(CXGate())"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:03:03.353613Z",
|
|
"start_time": "2019-08-21T09:03:03.345462Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Operator([[0.70710678+0.j , 0. -0.70710678j],\n",
|
|
" [0. -0.70710678j, 0.70710678+0.j ]],\n",
|
|
" input_dims=(2,), output_dims=(2,))\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# Create an operator from a parameterized Gate object\n",
|
|
"Operator(RXGate(np.pi / 2))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 13,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:03:47.550069Z",
|
|
"start_time": "2019-08-21T09:03:47.408126Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Operator([[ 0.70710678+0.j, 0.70710678+0.j, 0. +0.j, ...,\n",
|
|
" 0. +0.j, 0. +0.j, 0. +0.j],\n",
|
|
" [ 0. +0.j, 0. +0.j, 0.70710678+0.j, ...,\n",
|
|
" 0. +0.j, 0. +0.j, 0. +0.j],\n",
|
|
" [ 0. +0.j, 0. +0.j, 0. +0.j, ...,\n",
|
|
" 0. +0.j, 0. +0.j, 0. +0.j],\n",
|
|
" ...,\n",
|
|
" [ 0. +0.j, 0. +0.j, 0. +0.j, ...,\n",
|
|
" 0. +0.j, 0. +0.j, 0. +0.j],\n",
|
|
" [ 0. +0.j, 0. +0.j, 0.70710678+0.j, ...,\n",
|
|
" 0. +0.j, 0. +0.j, 0. +0.j],\n",
|
|
" [ 0.70710678+0.j, -0.70710678+0.j, 0. +0.j, ...,\n",
|
|
" 0. +0.j, 0. +0.j, 0. +0.j]],\n",
|
|
" input_dims=(2, 2, 2, 2, 2, 2, 2, 2, 2, 2), output_dims=(2, 2, 2, 2, 2, 2, 2, 2, 2, 2))\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# Create an operator from a QuantumCircuit object\n",
|
|
"circ = QuantumCircuit(10)\n",
|
|
"circ.h(0)\n",
|
|
"for j in range(1, 10):\n",
|
|
" circ.cx(j-1, j)\n",
|
|
"\n",
|
|
"# Convert circuit to an operator by implicit unitary simulation\n",
|
|
"Operator(circ)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Using Operators in circuits\n",
|
|
"\n",
|
|
"Unitary `Operators` can be directly inserted into a `QuantumCircuit` using the `QuantumCircuit.append` method. This converts the `Operator` into a `UnitaryGate` object, which is added to the circuit.\n",
|
|
"\n",
|
|
"If the operator is not unitary, an exception will be raised. This can be checked using the `Operator.is_unitary()` function, which will return `True` if the operator is unitary and `False` otherwise."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 14,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:03:49.196556Z",
|
|
"start_time": "2019-08-21T09:03:49.161398Z"
|
|
},
|
|
"tags": [
|
|
"nbsphinx-thumbnail"
|
|
]
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"image/png": "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",
|
|
"text/plain": [
|
|
"<Figure size 454.517x284.278 with 1 Axes>"
|
|
]
|
|
},
|
|
"execution_count": 14,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"# Create an operator\n",
|
|
"XX = Operator(Pauli('XX'))\n",
|
|
"\n",
|
|
"# Add to a circuit\n",
|
|
"circ = QuantumCircuit(2, 2)\n",
|
|
"circ.append(XX, [0, 1])\n",
|
|
"circ.measure([0,1], [0,1])\n",
|
|
"circ.draw('mpl')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Note that in the above example we initialize the operator from a `Pauli` object. However, the `Pauli` object may also be directly inserted into the circuit itself and will be converted into a sequence of single-qubit Pauli gates:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 15,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"{'11': 1024}"
|
|
]
|
|
},
|
|
"execution_count": 15,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
|
|
"backend = BasicAer.get_backend('qasm_simulator')\n",
|
|
"circ = generate_preset_pass_manager(optimization_level=1, backend=backend).run(circ)\n",
|
|
"job = backend.run(circ)\n",
|
|
"job.result().get_counts(0)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 16,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:04:12.017240Z",
|
|
"start_time": "2019-08-21T09:04:11.989825Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<pre style=\"word-wrap: normal;white-space: pre;background: #fff0;line-height: 1.1;font-family: "Courier New",Courier,monospace\"> ┌────────────┐┌─┐ \n",
|
|
"q_0: ┤0 ├┤M├───\n",
|
|
" │ Pauli(XX) │└╥┘┌─┐\n",
|
|
"q_1: ┤1 ├─╫─┤M├\n",
|
|
" └────────────┘ ║ └╥┘\n",
|
|
"c: 2/═══════════════╩══╩═\n",
|
|
" 0 1 </pre>"
|
|
],
|
|
"text/plain": [
|
|
" ┌────────────┐┌─┐ \n",
|
|
"q_0: ┤0 ├┤M├───\n",
|
|
" │ Pauli(XX) │└╥┘┌─┐\n",
|
|
"q_1: ┤1 ├─╫─┤M├\n",
|
|
" └────────────┘ ║ └╥┘\n",
|
|
"c: 2/═══════════════╩══╩═\n",
|
|
" 0 1 "
|
|
]
|
|
},
|
|
"execution_count": 16,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"# Add to a circuit\n",
|
|
"circ2 = QuantumCircuit(2, 2)\n",
|
|
"circ2.append(Pauli('XX'), [0, 1])\n",
|
|
"circ2.measure([0,1], [0,1])\n",
|
|
"circ2.draw()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Combining Operators\n",
|
|
"\n",
|
|
"Operators may be combined using several methods. \n",
|
|
"\n",
|
|
"### Tensor Product\n",
|
|
"\n",
|
|
"Two operators $A$ and $B$ may be combined into a tensor product operator $A\\otimes B$ using the `Operator.tensor` function. Note that if both $A$ and $B$ are single-qubit operators, then `A.tensor(B)` = $A\\otimes B$ will have the subsystems indexed as matrix $B$ on subsystem 0, and matrix $A$ on subsystem 1."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 17,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:04:14.208734Z",
|
|
"start_time": "2019-08-21T09:04:14.201058Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Operator([[ 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],\n",
|
|
" [ 0.+0.j, -0.+0.j, 0.+0.j, -1.+0.j],\n",
|
|
" [ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n",
|
|
" [ 0.+0.j, -1.+0.j, 0.+0.j, -0.+0.j]],\n",
|
|
" input_dims=(2, 2), output_dims=(2, 2))\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"A = Operator(Pauli('X'))\n",
|
|
"B = Operator(Pauli('Z'))\n",
|
|
"A.tensor(B)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Tensor Expansion\n",
|
|
"\n",
|
|
"A closely related operation is `Operator.expand`, which acts like a tensor product but in the reverse order. Hence, for two operators $A$ and $B$ we have `A.expand(B)` = $B\\otimes A$ where the subsystems indexed as matrix $A$ on subsystem 0, and matrix $B$ on subsystem 1."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 18,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:04:14.899024Z",
|
|
"start_time": "2019-08-21T09:04:14.891072Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Operator([[ 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",
|
|
" [ 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",
|
|
" input_dims=(2, 2), output_dims=(2, 2))\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"A = Operator(Pauli('X'))\n",
|
|
"B = Operator(Pauli('Z'))\n",
|
|
"A.expand(B)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Composition\n",
|
|
"\n",
|
|
"We can also compose two operators $A$ and $B$ to implement matrix multiplication using the `Operator.compose` method. We have that `A.compose(B)` returns the operator with matrix $B.A$:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 19,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:04:15.655155Z",
|
|
"start_time": "2019-08-21T09:04:15.648295Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Operator([[ 0.+0.j, 1.+0.j],\n",
|
|
" [-1.+0.j, 0.+0.j]],\n",
|
|
" input_dims=(2,), output_dims=(2,))\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"A = Operator(Pauli('X'))\n",
|
|
"B = Operator(Pauli('Z'))\n",
|
|
"A.compose(B)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"We can also compose in the reverse order by applying $B$ in front of $A$ using the `front` kwarg of `compose`: `A.compose(B, front=True)` = $A.B$:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 20,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:04:16.460560Z",
|
|
"start_time": "2019-08-21T09:04:16.452319Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Operator([[ 0.+0.j, -1.+0.j],\n",
|
|
" [ 1.+0.j, 0.+0.j]],\n",
|
|
" input_dims=(2,), output_dims=(2,))\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"A = Operator(Pauli('X'))\n",
|
|
"B = Operator(Pauli('Z'))\n",
|
|
"A.compose(B, front=True)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Subsystem Composition\n",
|
|
"\n",
|
|
"Note that the previous compose requires that the total output dimension of the first operator $A$ is equal to total input dimension of the composed operator $B$ (and similarly, the output dimension of $B$ must be equal to the input dimension of $A$ when composing with `front=True`).\n",
|
|
"\n",
|
|
"We can also compose a smaller operator with a selection of subsystems on a larger operator using the `qargs` kwarg of `compose`, either with or without `front=True`. In this case, the relevant input and output dimensions of the subsystems being composed must match. *Note that the smaller operator must always be the argument of* `compose` *method.*\n",
|
|
"\n",
|
|
"For example, to compose a two-qubit gate with a three-qubit Operator:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 21,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:04:17.113510Z",
|
|
"start_time": "2019-08-21T09:04:17.105398Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Operator([[ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j,\n",
|
|
" 0.+0.j],\n",
|
|
" [ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, -1.+0.j, 0.+0.j,\n",
|
|
" 0.+0.j],\n",
|
|
" [ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j,\n",
|
|
" 0.+0.j],\n",
|
|
" [ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,\n",
|
|
" -1.+0.j],\n",
|
|
" [ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,\n",
|
|
" 0.+0.j],\n",
|
|
" [ 0.+0.j, -1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,\n",
|
|
" 0.+0.j],\n",
|
|
" [ 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,\n",
|
|
" 0.+0.j],\n",
|
|
" [ 0.+0.j, 0.+0.j, 0.+0.j, -1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,\n",
|
|
" 0.+0.j]],\n",
|
|
" input_dims=(2, 2, 2), output_dims=(2, 2, 2))\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# Compose XZ with a 3-qubit identity operator\n",
|
|
"op = Operator(np.eye(2 ** 3))\n",
|
|
"XZ = Operator(Pauli('XZ'))\n",
|
|
"op.compose(XZ, qargs=[0, 2])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 22,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:04:17.324353Z",
|
|
"start_time": "2019-08-21T09:04:17.315952Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Operator([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j, 0.+0.j, 0.+0.j],\n",
|
|
" [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j, 0.+0.j, 0.+0.j, 0.+0.j],\n",
|
|
" [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j],\n",
|
|
" [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 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, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n",
|
|
" [0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n",
|
|
" [0.+0.j, 0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n",
|
|
" [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]],\n",
|
|
" input_dims=(2, 2, 2), output_dims=(2, 2, 2))\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# Compose YX in front of the previous operator\n",
|
|
"op = Operator(np.eye(2 ** 3))\n",
|
|
"YX = Operator(Pauli('YX'))\n",
|
|
"op.compose(YX, qargs=[0, 2], front=True)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Linear combinations\n",
|
|
"\n",
|
|
"Operators may also be combined using standard linear operators for addition, subtraction and scalar multiplication by complex numbers. "
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 23,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:04:18.829988Z",
|
|
"start_time": "2019-08-21T09:04:18.812834Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Operator([[-1.5+0.j, 0. +0.j, 0. +0.j, 0. +0.j],\n",
|
|
" [ 0. +0.j, 1.5+0.j, 1. +0.j, 0. +0.j],\n",
|
|
" [ 0. +0.j, 1. +0.j, 1.5+0.j, 0. +0.j],\n",
|
|
" [ 0. +0.j, 0. +0.j, 0. +0.j, -1.5+0.j]],\n",
|
|
" input_dims=(2, 2), output_dims=(2, 2))\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"XX = Operator(Pauli('XX'))\n",
|
|
"YY = Operator(Pauli('YY'))\n",
|
|
"ZZ = Operator(Pauli('ZZ'))\n",
|
|
"\n",
|
|
"op = 0.5 * (XX + YY - 3 * ZZ)\n",
|
|
"op"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"An important point is that while `tensor`, `expand` and `compose` will preserve the unitarity of unitary operators, linear combinations will not; hence, adding two unitary operators will, in general, result in a non-unitary operator:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 24,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:04:19.151814Z",
|
|
"start_time": "2019-08-21T09:04:19.147497Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"False"
|
|
]
|
|
},
|
|
"execution_count": 24,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"op.is_unitary()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Implicit Conversion to Operators\n",
|
|
"\n",
|
|
"Note that for all the following methods, if the second object is not already an `Operator` object, it will be implicitly converted into one by the method. This means that matrices can be passed in directly without being explicitly converted to an `Operator` first. If the conversion is not possible, an exception will be raised."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 25,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:04:20.045005Z",
|
|
"start_time": "2019-08-21T09:04:20.039841Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Operator([[0.+0.j, 1.+0.j],\n",
|
|
" [1.+0.j, 0.+0.j]],\n",
|
|
" input_dims=(2,), output_dims=(2,))\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# Compose with a matrix passed as a list\n",
|
|
"Operator(np.eye(2)).compose([[0, 1], [1, 0]])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Comparison of Operators\n",
|
|
"\n",
|
|
"Operators implement an equality method that can be used to check if two operators are approximately equal. "
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 26,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:04:20.821642Z",
|
|
"start_time": "2019-08-21T09:04:20.815611Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"True"
|
|
]
|
|
},
|
|
"execution_count": 26,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"Operator(Pauli('X')) == Operator(XGate())"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Note that this checks that each matrix element of the operators is approximately equal; two unitaries that differ by a global phase will not be considered equal:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 27,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:04:21.146256Z",
|
|
"start_time": "2019-08-21T09:04:21.141242Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"False"
|
|
]
|
|
},
|
|
"execution_count": 27,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"Operator(XGate()) == np.exp(1j * 0.5) * Operator(XGate())"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Process Fidelity\n",
|
|
"\n",
|
|
"We may also compare operators using the `process_fidelity` function from the *Quantum Information* module. This is an information theoretic quantity for how close two quantum channels are to each other, and in the case of unitary operators it does not depend on global phase."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 28,
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2019-08-21T09:04:22.171481Z",
|
|
"start_time": "2019-08-21T09:04:22.147477Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Process fidelity = 1.0\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# Two operators which differ only by phase\n",
|
|
"op_a = Operator(XGate()) \n",
|
|
"op_b = np.exp(1j * 0.5) * Operator(XGate())\n",
|
|
"\n",
|
|
"# Compute process fidelity\n",
|
|
"F = process_fidelity(op_a, op_b)\n",
|
|
"print('Process fidelity =', F)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Note that process fidelity is generally only a valid measure of closeness if the input operators are unitary (or CP in the case of quantum channels), and an exception will be raised if the inputs are not CP."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Next steps\n",
|
|
"\n",
|
|
"<Admonition type=\"tip\" title=\"Recommendations\">\n",
|
|
" - See an example of using operators in the [Grover's Algorithm](https://learning.quantum.ibm.com/tutorial/grovers-algorithm) tutorial.\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 (ipykernel)",
|
|
"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.11.4"
|
|
},
|
|
"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
|
|
} |