回路の基本¶
ここでは、Qiskitでの作業概要を説明します。Qiskitは、量子コンピューターのプログラミングに必要な、基本構成要素を提供します。Qiskitの基本単位は 量子回路(quantum circuit) です。Qiskitを使用した基本的なワークフローは、 構築 と 実行 の2つのステージで構成されます。 構築 では、あなたが解きたい問題を表現するさまざまな量子回路を構築でき、 実行 では、その量子回路をさまざまなバックエンドで実行します。ジョブが実行された後、目的とする出力に応じたデータが収集され、後処理されます。
[1]:
import numpy as np
from qiskit import QuantumCircuit
%matplotlib inline
回線の構築¶
最初のプログラムに必要な基本要素は、QuantumCircuitです。まず、3つの量子ビットで構成される QuantumCircuit
を作成します。
[2]:
# Create a Quantum Circuit acting on a quantum register of three qubits
circ = QuantumCircuit(3)
レジスタで回路を作成した後、レジスタを操作するためのゲート (「演算」) を追加することができます。チュートリアルを進めていくと、さらに多くのゲートと回路が見つかります。;以下は3量子ビットのGHZ状態を作る量子回路の例です。
このような状態を作成するには、3量子ビットの量子レジスタから始めます。デフォルトでは、レジスタの各量子ビットは \(|0\rangle\) に初期化されています。GHZ状態を作成するには、次のゲートを適用します: - 量子ビット0にアダマールゲート \(H\) を適用して、重ね合わせ状態 \(\left(|0\rangle+|1\rangle\right)/\sqrt{2}\) にする。 - 0量子ビットと1量子ビットの間に、制御NOT演算子( \(C_{X}\) )を適用する。 - 0量子ビットと2量子ビットの間に、制御NOT演算子を適用する。
理想的な量子コンピューターでは、この回路を実行することによって生成される状態は、上記のGHZ状態になります。
Qiskitでは、以下に示すように、回路に操作を1つずつ追加することができます。
[3]:
# Add a H gate on qubit 0, putting this qubit in superposition.
circ.h(0)
# Add a CX (CNOT) gate on control qubit 0 and target qubit 1, putting
# the qubits in a Bell state.
circ.cx(0, 1)
# Add a CX (CNOT) gate on control qubit 0 and target qubit 2, putting
# the qubits in a GHZ state.
circ.cx(0, 2)
[3]:
<qiskit.circuit.instructionset.InstructionSet at 0x7fbfb0bd5400>
回路の可視化¶
Qiskitの QuantumCircuit.draw()
を使うことで、多くの教科書で見られるような形式に回路をプロットし、可視化することができます。
[4]:
circ.draw('mpl')
[4]:

この回路では、量子ビットが順番に配置されており、一番上が量子ビット0、一番下が量子ビット2です。回路は左から右に読みます(つまり、回路の初めに適用されたゲートが左側に表示されます)。
複数の量子ビットのシステムの状態を表現する際にQiskitで使われるテンソル積の順番は、多くの物理の教科書で使われる順番と異なります。\(n\) 個の量子ビットがあり、\(j\) 番目の量子ビットは \(Q_{j}\) とラベル付けされていると仮定します。Qiskitでは、 \(n^{\mathrm{th}}\) 番目の量子ビットはテンソル積の左側にあるので、基底ベクトルは、\(Q_{n-1}\otimes \cdots \otimes Q_1\otimes Q_0\) とラベル付けされます。
例えば、量子ビットゼロが0、量子ビット1が0、量子ビット2が1のとき、Qiskitはこの状態を \(|100\rangle\) と表現します。一方で、多くの物理の教科書はこの状態を \(|001\rangle\) と表現します。
このラベリングの違いは、複数量子ビットの演算子が行列として表現されるときの方法に影響します。例えば、Qiskitは制御X (\(C_{X}\)) 演算子で量子ビット0を制御ビット、量子ビット1をターゲット・ビットとするとき、以下のように表現します。
回路のシミュレーション¶
回路をシミュレートするには、Qiskitのquant-infoモジュールを使います。このシミュレーターは、 \(2^n\) 次元の複素ベクトルである量子状態を返します。ここで \(n\) は量子ビットの数です。(ですので、ご自身のマシンで実行するには大きすぎる数にすぐ到達してしまうことに注意してください。)
シミュレーターには 2 つのステージがあります。 1つ目は、入力状態を設定し、2つ目は量子回路で状態を進化させます。
[5]:
from qiskit.quantum_info import Statevector
# Set the intial state of the simulator to the ground state using from_int
state = Statevector.from_int(0, 2**3)
# Evolve the state by the quantum circuit
state = state.evolve(circ)
#draw using latex
state.draw('latex')
[5]:
Qiskitには、この結果を見るための視覚化ツールボックスも用意されています。
以下のように、qsphereのプロット、また状態の密度行列である \rho の実数部と虚数部をhinton表示でプロットする機能が使えます。
[6]:
state.draw('qsphere')
[6]:

[7]:
state.draw('hinton')
[7]:

回路のユニタリー表現¶
Qiskitのquant_infoモジュールには、回路のユニタリー演算子を作成するために使用できる演算子メソッドもあります。 これにより、量子回路を表す \(2^n \times 2^n\) 行列が計算されます。
[8]:
from qiskit.quantum_info import Operator
U = Operator(circ)
# Show the results
U.data
[8]:
array([[ 0.70710678+0.j, 0.70710678+0.j, 0. +0.j,
0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +0.j, 0. +0.j,
0.70710678+0.j, -0.70710678+0.j],
[ 0. +0.j, 0. +0.j, 0.70710678+0.j,
0.70710678+0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0.70710678+0.j, -0.70710678+0.j,
0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0.70710678+0.j, 0.70710678+0.j,
0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0.70710678+0.j,
-0.70710678+0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +0.j, 0. +0.j,
0.70710678+0.j, 0.70710678+0.j],
[ 0.70710678+0.j, -0.70710678+0.j, 0. +0.j,
0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +0.j]])
OpenQASM バックエンド¶
上記のシミュレーションは、理想的な回路と回路の行列表示で状態の情報を出力してくれるため便利です。しかし、実際の実験は、各量子ビットを 測定 することで終了します(一般には計算基底 \(|0\rangle, |1\rangle\) を測定に使います)。測定なしでは、状態の情報を得ることはできません。測定により、量子システムは古典的なビットに崩壊します。
例えば、3量子ビットのGHZ状態の各量子ビットを独立に測定するとしましょう。
\(xyz\) が結果のビット列を示すとしましょう。 Qiskitで使用される量子ビットのラベリング方法では、\(x\) は量子ビット2の結果に対応し、\(y\) は量子ビット1の結果に対応し、そして、 \(z\) は量子ビット0の結果に対応します。
注記:このビット文字列の表現では最上位ビットが左側、最下位ビットが右側に配置されます。これは、バイナリビット文字列における標準的な順序です。そのため、同じ方法で量子ビットも並べます(最上位ビットを表す量子ビットのインデックスは0です)。これが、Qiskitが非標準的なテンソル積の順序を使用する理由です。
\(xyz\) の結果が得られる確率は、以下のように与えられることを思い出してください。
そして、GHZ状態の場合、000または111が得られる確率はどちらも1/2です。
測定を含む回路をシミュレートするためには、上記の回路に測定を追加し、異なるAerバックエンドを使用する必要があります。
[9]:
# Create a Quantum Circuit
meas = QuantumCircuit(3, 3)
meas.barrier(range(3))
# map the quantum measurement to the classical bits
meas.measure(range(3), range(3))
# The Qiskit circuit object supports composition.
# Here the meas has to be first and front=True (putting it before)
# as compose must put a smaller circuit into a larger one.
qc = meas.compose(circ, range(3), front=True)
#drawing the circuit
qc.draw('mpl')
[9]:

この回路は古典レジスターと3つの測定を追加して、量子ビットの結果を古典ビットにマップします。
この回路をシミュレートするためには、Qiskit Aerの qasm_simulator
を使います。この回路を実行するたびに000または111が生成されます。ビット列の分布についての統計を取るために(例えば、\(\mathrm{Pr}(000)\) を見積もるために)、何回も回路を繰り返す必要があります。回路の繰り返し回数は execute
関数の shots
キーワードで指定できます。
[10]:
# Adding the transpiler to reduce the circuit to QASM instructions
# supported by the backend
from qiskit import transpile
# Use Aer's qasm_simulator
from qiskit.providers.aer import QasmSimulator
backend = QasmSimulator()
# First we have to transpile the quantum circuit
# to the low-level QASM instructions used by the
# backend
qc_compiled = transpile(qc, backend)
# Execute the circuit on the qasm simulator.
# We've set the number of repeats of the circuit
# to be 1024, which is the default.
job_sim = backend.run(qc_compiled, shots=1024)
# Grab the results from the job.
result_sim = job_sim.result()
result オブジェクトを取得できたら、get_counts(circuit)
関数を使用して回数を取得することができます。これにより、送信した回路の 集計 されたバイナリー結果が得られます。
[11]:
counts = result_sim.get_counts(qc_compiled)
print(counts)
{'000': 505, '111': 519}
約50%の回数で、出力ビット文字列は000です。Qiskitは、結果を表示できる関数 plot_histogram
も提供します。
[12]:
from qiskit.visualization import plot_histogram
plot_histogram(counts)
[12]:

推定された結果の確率 \(\mathrm{Pr}(000)\) と \(\mathrm{Pr}(111)\) は、カウントを集計し、ショット数(回路が繰り返された回数)で割ることによって計算されます。 execute
関数の shots
キーワードを変更してみて、推定される確率がどのように変化するか確認してください。
[13]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
Qiskit | 0.25.0 |
Terra | 0.17.0 |
Aer | 0.8.0 |
Ignis | 0.6.0 |
Aqua | 0.9.0 |
IBM Q Provider | 0.12.2 |
System information | |
Python | 3.8.8 (default, Feb 24 2021, 13:46:16) [Clang 10.0.0 ] |
OS | Darwin |
CPUs | 4 |
Memory (Gb) | 32.0 |
Tue Apr 06 21:48:52 2021 EDT |
This code is a part of Qiskit
© Copyright IBM 2017, 2021.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.
[ ]: