メインコンテンツへスキップ
このプロジェクトはベータ版です。バグを見つけましたか?GitHub Issueを開く。質問やアイデアがありますか?Discussionsで質問する — フィードバックをお待ちしています!
このページの翻訳品質はいかがですか?

教室でQiskitを使ってみよう

このQiskit in Classroomsモジュールでは、以下のパッケージをインストールした動作するPython環境が必要です:

  • qiskit v2.1.0以降
  • qiskit-ibm-runtime v0.40.1以降
  • qiskit-aer v0.17.0以降
  • qiskit.visualization
  • numpy
  • pylatexenc

上記パッケージのセットアップとインストールについては、Qiskitのインストールガイドを参照してください。 実際の量子コンピューターでジョブを実行するには、IBM Cloud®アカウントの設定ガイドの手順に従ってIBM Quantum®のアカウントを作成する必要があります。

このモジュールはHeron v2プロセッサー上でテストされ、2秒のQPU時間を使用しました。これはあくまで推定値であり、実際の使用量は異なる場合があります。

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"qiskit": "qiskit", "qiskit_aer": "qiskit-aer", "qiskit_ibm_runtime": "qiskit-ibm-runtime"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
# Uncomment and modify this line as needed to install dependencies
#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'

はじめに​

Qiskit in the Classroomモジュールでは、量子コンピューターを使って、量子力学・コンピューターサイエンス・化学などの量子コンピューティングに関連する様々な分野の概念を探求する機会があります。このモジュールは他のモジュールの前提条件として機能しており、量子コンピューティングの基礎と、Qiskitを使って量子Circuit(回路)を実行する方法を紹介します。

まず古典的なコンピューターの仕組みについて簡単に説明し、次にこれらの概念が量子コンピューティングのパラダイムにどのように適用されるかを示します。最後に、これらの概念をまとめて最初の量子Circuit(回路)を構築・実行する方法をお見せします。

古典的なコンピューター​

古典的なコンピューターの仕組みの基礎はすでにご存知かもしれませんが、ここでは量子コンピューターとの比較ができるよう、主要な特徴をいくつか取り上げます。

情報の基本単位:ビット​

古典的なコンピューターは古典的な情報を処理しており、古典的な情報の基本単位はビットです。1つのビットは「はい/いいえ」という1つの問いへの答えを格納できます。ビットの2つの二進状態は通常「0」と「1」で表されます。

二進数の復習​

ビットを組み合わせることで、より多くの情報を格納できます。例えば、0から15の数値を格納したい場合、次のように4ビットで表現できます:

0 = 00004 = 01008 = 100012 = 1100
1 = 00015 = 01019 = 100113 = 1101
2 = 00106 = 011010 = 101014 = 1110
3 = 00117 = 011111 = 101115 = 1111

一般に、NNビットの二進数を馴染みのある10進数に変換するには、最下位(最右端)のビットを20=12^0 = 1で乗算し、その左のビットを21=22^1 = 2で、次のビットを22=42^2 = 4で乗算し、最上位(最左端)のビットに達するまで2N−12^{N-1}で乗算するまで続けます。

つまり、NNビットは2N2^N通りの異なる状態のうちの1つになり得ます。

理解度チェック​

数86を表すのに何ビット必要でしょうか。この数を2進数でエンコードするビット文字列を書き出してください。

Answer

NN ビットで数 00 から 2N−12^N - 1 まで表現できることを思い出してください。したがって、6ビットを使用すると 26−1=632^6 - 1 = 63 まで表現できます。それでは十分ではありません。もう1ビット追加すると 27−1=1272^7 - 1 = 127 まで表現できます。それでは86を2の累乗に分解してみましょう。

86=64+16+4+2=26×1+25×0+24×1+23×0+22×1+21×1+20×0=1010110\begin{aligned} 86 &= 64 + 16 + 4 + 2 \\ &= 2^6 \times 1 + 2^5 \times 0 + 2^4 \times 1 + 2^3 \times 0 + 2^2 \times 1 + 2^1 \times 1 + 2^0 \times 0 \\ &= 1010110 \end{aligned}

基本演算:Gate(ゲート)​

コンピューターは、計算を行うためにビットに対して何らかの操作を実行できる必要があります。二進Gate(ゲート)は、より複雑なアルゴリズムやコードすべての基本的な構成要素となる演算です。

1ビットGate(ゲート):​

NOT​

1つのビットしかない場合、その状態を変換する方法は1つだけです:状態を0から1へ、または1から0へ反転させます。これを「NOT」Gate(ゲート)と呼びます。このGate(ゲート)の効果——および以下で説明する他のGate(ゲート)の効果——は、いわゆる「真理値表」で表すことができます。真理値表には、Qubitの入力状態と出力状態の列があります。NOT Gate(ゲート)の真理値表は以下のとおりです:

入力出力
01
10

複数ビットGate(ゲート):​

AND​

ANDは2つの入力ビットを受け取り、1つのビットを出力する2ビットGate(ゲート)です。両方の入力ビットが1の場合に1を出力し、それ以外は0を出力します:

入力出力
000
010
100
111

OR​

ORも単一の出力ビットを持つ2ビットGate(ゲート)です。どちらかのビットが1であれば1を出力します:

入力出力
000
011
101
111

XOR​

XORは「排他的論理和(exclusive OR)」の略で、OR Gate(ゲート)に似ていますが、入力ビットのうちの1つだけが1の場合に1を出力します。両方が1または両方が0の場合は0を出力します:

入力出力
000
011
101
110

測定:​

古典的なコンピューティングを学ぶ際、ビットの状態を読み出すプロセスにはあまり注意が払われません。これは、概念的な観点から見るとそれほど複雑ではないためです。ビットは計算の前後いつでも測定でき、結果に影響を与えません。これは量子コンピューティングには当てはまらず、以下で説明します。

Circuit(回路):​

上記のGate(ゲート)を組み合わせることで、コンピューター上で任意の操作を実行できます。簡単な例として、ANDとXOR Gate(ゲート)を使って、2ビットの和を計算する半加算器Circuit(回路)を構成できます。これは論理Circuit(回路)図で表され、ワイヤーがビットを表し、各ビットに作用するGate(ゲート)が対応するワイヤー上のシンボルとして示されます:

半加算器Circuit(回路)の古典的なCircuit(回路)図。XOR Gate(ゲート)がSum出力ビットを生成し、AND Gate(ゲート)がCarry出力ビットを生成します。

つまり、2つのビットがコピーされ、AND Gate(ゲート)とXOR Gate(ゲート)の両方に入力されます。XOR Gate(ゲート)の結果は「和ビット」(S)で、二進数の1の位の値を表し、AND Gate(ゲート)の結果は「桁上げビット」(C)で、二進数の次の上位桁の値を表します。真理値表は以下のとおりです:

AABB和 (A⊕BA \oplus B)桁上げ (A∧BA \wedge B)
0000
0110
1010
1101

理解度チェック​

上記の真理値表が加算器回路の正しい解を与えることを検証してください。つまり、AとBの4通りの選択肢それぞれについて、A+B=S+2×CA+B=S+2 \times C が成り立つことを確認してください。

Answer
0+0=0+0=0 ✓0+1=1+0=1 ✓1+0=1+0=1 ✓1+1=0+2=2 ✓\begin{aligned} 0+0 &= 0+0 = 0 ~\checkmark \\ 0+1 &= 1+0 = 1 ~\checkmark \\ 1+0 &= 1+0 = 1 ~\checkmark \\ 1+1 &= 0+2 = 2 ~\checkmark \\ \end{aligned}

量子コンピューター​

ビット →\rightarrow qubit​

ビットが古典的な情報の基本単位であるように、量子ビット(qubit)は量子情報の基本単位です。古典的なビットと同様に、Qubitの状態は0または1のいずれかで、通常∣0⟩\vert 0\rangleおよび∣1⟩\vert 1\rangleと表記します。しかし古典的なビットとは異なり、量子ビットは∣0⟩\vert 0\rangle状態と∣1⟩\vert 1\rangle状態の両方の重ね合わせに同時になることができます。一般に、Qubitは以下の形式の任意の状態∣ψ⟩\vert \psi\rangleになれます:

∣ψ⟩=c0∣0⟩+c1∣1⟩\vert \psi\rangle = c_0 \vert 0\rangle + c_1 \vert 1\rangle

ここでc0c_0およびc1c_1は∣c0∣2+∣c1∣2=1\vert c_0 \vert ^2+\vert c_1\vert ^2=1を満たす複素振幅です。

量子位相​

c0c_0 と c1c_1 は複素数であるため、それぞれ cj=∣cj∣eiϕjc_j = \vert c_j\vert e^{i\phi_j} と書けます。ここで ϕj\phi_j は位相と呼ばれます。状態全体に同じ全体位相因子を乗算しても、物理的には何も変わりません——これをグローバル位相と呼び、観測可能な影響はありません。

そのため、eiϕ0e^{i\phi_0}を「括り出す」ことが慣例となっており、次のように書けます:

∣ψ⟩=∣c0∣∣0⟩+∣c1∣eiϕ∣1⟩\vert \psi\rangle = \vert c_0\vert \vert 0\rangle + \vert c_1\vert e^{i\phi}\vert 1\rangle

ここでϕ=ϕ1−ϕ0\phi = \phi_1-\phi_0は量子状態の相対位相であり、これは観測可能な影響を持ちます。

この位相は量子コンピューティングにおいて非常に重要な役割を果たしており、続くQiskit in the Classroomモジュールでその様々な影響を探求していきます。

複数のQubit​

複数のビットの状態は単純に0と1の文字列で表せますが、複数のQubitの状態は重ね合わせとエンタングルメントの原理により、少し複雑になります。

NNビットは二進数の000...000から111...111までの2N2^N通りの可能な状態のうちの1つになれることを思い出してください。しかし今度は重ね合わせの原理により、NN個のqubitはこれらすべての状態の重ね合わせに同時になることができます!

これは次のように表現できます:

ψN=∑j=02N−1cj∣j⟩\psi_N = \sum_{j=0}^{2^N-1} c_j \vert j\rangle

ここで古典的な場合と同様に、状態 ∣j⟩\vert j\rangle は各 Qubit が 0 と 1 の適切な組み合わせになって二進数 jj を生成する状態に対応します。これらは量子系の「計算基底状態」として知られています。例えば、3Qubit 状態はその 8 つの計算基底状態の重ね合わせとして書けます:

ψ3=c0∣000⟩+c1∣001⟩+c2∣010⟩+c3∣011⟩+c4∣100⟩+c5∣101⟩+c6∣110⟩+c7∣111⟩\psi_3 = c_0 \vert 000\rangle + c_1 \vert 001\rangle + c_2 \vert 010\rangle + c_3 \vert 011\rangle + c_4 \vert 100\rangle + c_5 \vert 101\rangle + c_6 \vert 110\rangle + c_7 \vert 111\rangle

系の各Qubitはインデックス00からN−1N-1で示されます。慣例として、Qubitの状態は右から左に読みます。つまりQubit 00の状態が最右端で、qubit N−1N-1の状態が最左端になります。これは「リトルエンディアン」記法として知られており、左から右に読むことに慣れているため、最初は直感に反して感じるかもしれません。

理解度チェック​

一見すると、リトルエンディアン記法のようにQubitを右から左に並べることは直感に反するように思えるかもしれませんが、実は非常に論理的なことです!その理由を説明してください。(上記の二進数から10進数への変換の話を思い出してください。)

Answer

Qubitを右から左に並べ、qubit 0が最右端でQubit N-1が最左端になるようにすると、qubit 00を202^0で乗算される最下位ビットに対応させ、qubit N−1N-1を2N−12^{N-1}で乗算される最上位ビットに対応させることが論理的です。

エンタングルメント​

先ほど述べたように、Qubitのもう1つの重要な特徴は、互いにエンタングルできることです。c0=c3=12c_0 = c_3 = \frac{1}{\sqrt{2}}、c1=c2=0c_1 = c_2 = 0の2Qubit状態の例を見てみましょう:

∣ψ⟩=12(∣00⟩+∣11⟩)\vert \psi\rangle = \frac{1}{\sqrt{2}}(\vert 00\rangle + \vert 11\rangle)

つまり、qubit 0の状態は等しい確率で∣0⟩\vert 0\rangleまたは∣1⟩\vert 1\rangleになり得て、qubit 1も同様です。しかし、これらの確率はもはや互いに独立ではありません。qubit 0の状態が∣0⟩\vert 0\rangleとわかれば、qubit 1も∣0⟩\vert 0\rangleにあることがわかります。これは互いにどれだけ離れていても成り立つため、エンタングルした状態を測定する行為はときに「不気味な遠隔作用」と呼ばれます。

エンタングルメントは他の形でも現れます。例えば、状態

∣ψ⟩=12(∣01⟩+∣10⟩)\vert \psi\rangle = \frac{1}{\sqrt{2}}(\vert 01\rangle + \vert 10\rangle)

は常に反対の結果をもたらします:一方のQubitが∣0⟩\vert 0\rangleと測定されれば、もう一方は必ず∣1⟩\vert 1\rangleの状態で見つかります。

理解度チェック​

状態∣ψ⟩=∣11⟩\vert \psi\rangle = \vert 11\rangleはエンタングルしていますか?その理由を答えてください。

Answer

エンタングルしていません。両方のQubitを測定すると結果が常に同じになりますが、これは各Qubitが常に∣1⟩\vert 1\rangleの状態に固定されているためです。一方のQubitを測定した結果は実際にはもう一方に依存しておらず、どちらも常に∣1⟩\vert 1\rangleなのです。

一般に、各Qubitの状態を個別に記述してから次のように積を取ることができる場合:

∣ψ⟩=∣ψ1⟩∣ψ0⟩\vert \psi\rangle = \vert \psi_1\rangle \vert \psi_0\rangle

これは「積状態」として知られており、エンタングルしていません。

ベクトル記法​

量子状態が異なる演算の下でどのように変換されるかを確認するには、ベクトルと行列を使用すると便利です。この表現では、量子状態はベクトルであり、量子Gate(ゲート)(次のセクションで説明)はベクトルを変換する行列となります。

1つのQubitについて、各状態のベクトル形式は次のように選ばれます: ∣0⟩=(10)\vert 0\rangle = \begin{pmatrix}1 \\ 0\end{pmatrix} ∣1⟩=(01)\vert 1\rangle = \begin{pmatrix}0 \\ 1\end{pmatrix} このようにして、任意の状態∣ψ⟩=a∣0⟩+b∣1⟩\vert \psi\rangle = a\vert 0\rangle+b\vert 1\rangleは次のように書けます: ∣ψ⟩=(ab)\vert \psi\rangle =\begin{pmatrix}a \\ b\end{pmatrix}

一般的なnnQubit状態では、2n2^n次元のベクトルが必要であり、基底状態は二進数の値の昇順に並べられます:

∣0…000⟩=(100⋮0),∣0…001⟩=∣1…110⟩=(0⋮010),∣1…111⟩=(0⋮001)\vert 0 \dots 000\rangle = \begin{pmatrix}1 \\ 0 \\ 0 \\ \vdots \\ 0\end{pmatrix}, \vert 0 \dots 001 \rangle = \vert 1 \dots 110\rangle = \begin{pmatrix}0 \\ \vdots \\ 0 \\ 1 \\ 0\end{pmatrix}, \vert 1 \dots 111 \rangle = \begin{pmatrix}0 \\ \vdots \\ 0 \\ 0\\ 1\end{pmatrix}

このベクトル記法を念頭に置いて、必要な量子Gate(ゲート)、量子状態への作用、および行列形式を紹介します。

理解度チェック​

2Qubit系には4つの計算基底状態があります。それぞれをケット記法とベクトル記法の両方で書き出してください。

Answer
∣00⟩=(1000),∣01⟩=(0100),…,∣10⟩=(0010),∣11⟩=(0001)\vert 00\rangle = \begin{pmatrix}1 \\ 0 \\ 0 \\ 0\end{pmatrix}, \vert 01 \rangle = \begin{pmatrix}0 \\ 1 \\ 0 \\ 0\end{pmatrix}, \dots, \vert 10\rangle = \begin{pmatrix}0 \\ 0 \\ 1 \\ 0\end{pmatrix}, \vert 11 \rangle = \begin{pmatrix}0 \\ 0 \\ 0\\ 1\end{pmatrix}

Gate(ゲート) →\rightarrow 量子Gate(ゲート)​

NOT、AND、OR、XORなどの古典的なGate(ゲート)を組み合わせて任意の古典Circuit(回路)を構築できるように、量子Gate(ゲート)は量子コンピューティングにおいて同じ役割を果たします。Qubitには量子力学的な追加的特徴があるため、量子Gate(ゲート)はそれに対応してより豊富です。基底状態∣0⟩|0\rangleと∣1⟩|1\rangleへの作用は真理値表で記述できますが、それでは全体像を捉えきれません。量子Gate(ゲート)では、基底状態の重ね合わせにも作用するため、行列表現を使用する方が自然なことが多いです。

以下では、最も一般的な量子Gate(ゲート)と、それらが相互作用するQubitをどのように変換するかを紹介します。該当する場合は、馴染みのある古典的なGate(ゲート)と結び付けて説明します。

1量子ビットゲート​

XX ゲート: 量子版のNOT演算です。真理値表は古典的なNOTゲートとまったく同じです。

入力出力
∣0⟩\vert 0\rangle∣1⟩\vert 1\rangle
∣1⟩\vert 1\rangle∣0⟩\vert 0\rangle

行列表現は次のとおりです。

X=(0110)X=\begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}

Qiskitで XX ゲートを含むCircuitを作成するには次のようにします。

from qiskit import QuantumCircuit

qc = QuantumCircuit(1)
qc.x(0)
qc.draw("mpl")

前のコードセルの出力

この非常にシンプルなCircuit図では、Qubitはワイヤー(黒い水平線)で表されており、ゲートはそのワイヤー上のボックスとして表示されます。

Hadamardゲート: 重ね合わせ状態を生成します。真理値表:

入力出力
∣0⟩\vert 0\rangle12(∣0⟩+∣1⟩)\frac{1}{\sqrt{2}}\left(\vert 0\rangle+\vert 1\rangle\right)
∣1⟩\vert 1\rangle12(∣0⟩−∣1⟩)\frac{1}{\sqrt{2}}\left(\vert 0\rangle-\vert 1\rangle\right)

行列表現: H=12(111−1)H=\frac{1}{\sqrt{2}}\begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix}

HadamardゲートをもつCircuitは次のように作成します。

from qiskit import QuantumCircuit

qc = QuantumCircuit(1)
qc.h(0)
qc.draw("mpl")

前のコードセルの出力

ZZ ゲート: ∣1⟩|1\rangle 状態に Δϕ=π\Delta \phi = \pi の位相シフトを加えます。

入力出力
∣0⟩\vert 0\rangle∣0⟩\vert 0\rangle
∣1⟩\vert 1\rangle−∣1⟩-\vert 1\rangle

Z=(100−1)Z=\begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix}

Qiskitで ZZ ゲートを含むCircuitを作成するには次のようにします。

qc = QuantumCircuit(1)
qc.z(0)
qc.draw("mpl")

前のコードセルの出力

TT ゲート: ∣1⟩|1\rangle 状態に Δϕ=π/4\Delta \phi = \pi/4 の位相シフトを加えます。

入力出力
∣0⟩\vert 0\rangle∣0⟩\vert 0\rangle
∣1⟩\vert 1\rangleeiπ/4∣1⟩e^{i\pi/4}\vert 1\rangle

T=(100eiπ/4)T=\begin{pmatrix} 1 & 0 \\ 0 & e^{i\pi/4} \end{pmatrix}

Qiskitで TT ゲートを含むCircuitを作成するには次のようにします。

qc = QuantumCircuit(1)
qc.t(0)
qc.draw("mpl")

前のコードセルの出力

複数Qubitゲート​

2Qubitゲートは古典的な2ビットゲートに似ていますが、重要な違いが一つあります。すべての量子ゲートは可逆でなければならないという点です。線形代数の観点では、これはゲートがユニタリ行列で表されることを意味します。したがって、2つの入力Qubitは常に2つの出力Qubitに対応し、原理的に操作を元に戻すことができます。これは、ANDやORなどの古典ゲートとは対照的です。古典ゲートは情報を失うため不可逆であり、出力から入力を一意に特定することができません。

CNOT(制御NOTゲート): 2つの入力Qubitは「制御」と「ターゲット」Qubitと呼ばれます。制御Qubitは変化しませんが、その状態がターゲットQubitへの作用を決定します。制御Qubitが ∣1⟩\vert 1\rangle の状態にある場合、ターゲットに XX ゲートが適用されます。制御Qubitが ∣0⟩\vert 0\rangle の状態にある場合、ターゲットは変化しません。

ゲートの引数は、Qiskitの qc.cx(control, target) と同様に CNOT(qcontrol,qtarget)CNOT(q_{control},q_{target}) の順序で並びます。ケット内のビットの順序は別の慣習に従います。Qiskitでは2Qubit基底状態を ∣q1q0⟩\vert q_1q_0\rangle と書きます。ここでは、A=q0A=q_0 を制御、B=q1B=q_1 をターゲットとすると、ケットは ∣BA⟩\vert BA\rangle となり、制御が右側に来ます。詳細についてはビット順序に関するガイドを参照してください。

Qubit AA と BB の計算基底値 a,b∈{0,1}a,b\in\{0,1\} に対して、ゲートは次のように作用します:

CNOT(A,B)∣ba⟩=∣(b⊕a) a⟩CNOT(A,B)\vert ba\rangle = \vert (b\oplus a)\,a\rangle

ここで、⊕\oplus は2を法とする加算(XOR)を表します。制御値 aa はそのままですが、ターゲット値 bb は a=1a=1 のときに反転します。

入力出力
∣00⟩\vert 00\rangle∣00⟩\vert 00\rangle
∣01⟩\vert 01\rangle∣11⟩\vert 11\rangle
∣10⟩\vert 10\rangle∣10⟩\vert 10\rangle
∣11⟩\vert 11\rangle∣01⟩\vert 01\rangle

∣BA⟩\vert BA\rangle の基底を ∣00⟩,∣01⟩,∣10⟩,∣11⟩\vert 00\rangle,\vert 01\rangle,\vert 10\rangle,\vert 11\rangle の順に並べると、この作用を表す行列は次のようになります:

CNOT=(1000000100100100)CNOT=\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0\end{pmatrix}

qc = QuantumCircuit(2)
qc.cx(0, 1)
qc.draw("mpl")

前のコードセルの出力

これは2つのQubitを持つ最初のCircuit図です。2本のワイヤーがそれぞれのQubitを表しています。CNOTゲートは2つのQubit間に実装されており、q0q_0 が制御、q1q_1 がターゲットです。

理解度チェック​

ほとんどのゲートはQiskitでも他の場所でも同じ行列形式を持ちます。しかし、CNOTゲートは2つのQubitに作用するため、Qubitの順序の規則が問題になります。Qubitを ∣q0,q1,...⟩\vert q_0,q_1,...\rangle の順に並べるテキストでは、CNOTゲートの行列形式が異なります。上記のCNOT行列が ∣01⟩\vert 01\rangle 状態に対して正しい作用をもつことを、行列の明示的な掛け算によって確認してください。

Answer

CNOT∣01⟩=(1000000100100100)(0100)=(0001)=∣11⟩CNOT\vert 01\rangle =\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0\end{pmatrix}\begin{pmatrix}0 \\ 1 \\ 0 \\0\end{pmatrix} = \begin{pmatrix}0 \\ 0 \\ 0 \\1\end{pmatrix} = \vert 11\rangle

SWAPゲート: このゲートは2つのキュビットの状態を入れ替えます。真理値表:

InputOutput
∣00⟩\vert 00\rangle∣00⟩\vert 00\rangle
∣01⟩\vert 01\rangle∣10⟩\vert 10\rangle
∣10⟩\vert 10\rangle∣01⟩\vert 01\rangle
∣11⟩\vert 11\rangle∣11⟩\vert 11\rangle

この操作を表す行列は次のとおりです。

SWAP=(1000001001000001)SWAP=\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1\end{pmatrix}

qc = QuantumCircuit(2)
qc.swap(0, 1)
qc.draw("mpl")

Output of the previous code cell

SWAPゲートは実際には3つのCNOTから構築できます。これを確認するために、Qiskitでこのゲートをdecompose()してみましょう。

qc = QuantumCircuit(2)
qc.swap(0, 1)
qc.decompose().draw("mpl")

Output of the previous code cell

ここで初めて、回路図に複数のゲートがどのように表示されるかを見ます。私たちはこれを左から右に読みます。つまり最も左のゲートが最初に適用されます。

理解度チェック​

上記のCNOTの組み合わせがSWAPゲートになることを検証してください。これは行列の乗算やその他の方法で行うことができます。

Answer

上記のCNOTの組み合わせがSWAPゲートになることを確認してください。行列の掛け算またはその他の方法で確かめられます。

(1000000100100100)(1000010000010010)(1000000100100100)=(1000001001000001)=SWAP ✓\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0\end{pmatrix} \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0\end{pmatrix} \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0\end{pmatrix} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1\end{pmatrix} = SWAP ~\checkmark

真理値表を使って、各CNOTで状態がどのように変化するかを確認します。最後の列では、状態はSWAP真理値表の「出力」列と等しくなるはずです。

InputCNOT(A,B)CNOT(B,A)CNOT(A,B)
∣00⟩\vert 00\rangle∣00⟩\vert 00\rangle∣00⟩\vert 00\rangle∣00⟩✓\vert 00\rangle \checkmark
∣01⟩\vert 01\rangle∣11⟩\vert 11\rangle∣10⟩\vert 10\rangle∣10⟩✓\vert 10\rangle \checkmark
∣10⟩\vert 10\rangle∣10⟩\vert 10\rangle∣11⟩\vert 11\rangle∣01⟩✓\vert 01\rangle \checkmark
∣11⟩\vert 11\rangle∣01⟩\vert 01\rangle∣01⟩\vert 01\rangle∣11⟩✓\vert 11\rangle \checkmark

Toffoliゲート(または「制御-制御-NOT」(CCNOT)): これは3キュビット・ゲートです。「制御-制御-NOT」という名前からすでにその動作がわかるかもしれません。2つの制御キュビットと1つのターゲット・キュビットがあり、両方の制御キュビットが状態 ∣1⟩\vert 1\rangle にある場合にのみ、ターゲット・キュビットの状態が反転します。CNOTで使用した順序規則をここでも維持します。

CCNOT(ControlA,ControlB,TargetC)∣CBA⟩CCNOT(Control A, Control B, Target C)\vert CBA\rangle

つまり真理値表は次のようになります。

InputOutput
∣000⟩\vert 000\rangle∣000⟩\vert 000\rangle
∣001⟩\vert 001\rangle∣001⟩\vert 001\rangle
∣010⟩\vert 010\rangle∣010⟩\vert 010\rangle
∣011⟩\vert 011\rangle∣111⟩\vert 111\rangle
∣100⟩\vert 100\rangle∣100⟩\vert 100\rangle
∣101⟩\vert 101\rangle∣101⟩\vert 101\rangle
∣110⟩\vert 110\rangle∣110⟩\vert 110\rangle
∣111⟩\vert 111\rangle∣011⟩\vert 011\rangle

そしてこの作用を表す行列は次のとおりです。

CCNOT=(1000000001000000001000000000000100001000000001000000001000010000)CCNOT=\begin{pmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\0 & 1 & 0 & 0 & 0 & 0 & 0 & 0\\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0\end{pmatrix}
qc = QuantumCircuit(3)
qc.ccx(0, 1, 2)
qc.draw("mpl")

前のコードセルの出力

Toffoliゲートも、いくつかのゲートとともにCNOTに分解できます。ただし、SWAPゲートの分解よりもはるかに複雑であるため、この分解の確認はモジュール末尾の任意課題として残しておきます。

測定​

測定は量子計算において特別な役割を果たしており、古典計算には対応するものがありません。古典計算ではアルゴリズムの任意のタイミングでビットを確認できますが、量子計算ではQubitを観測するタイミングを慎重に選ぶ必要があります。測定によって状態が崩壊し、Qubitの計算上の複雑性を生み出す重ね合わせが破壊されてしまうからです。

具体的には、NN ビットの量子状態 ∣ψ⟩=∑i=02N−1ci∣i⟩\vert \psi\rangle = \sum_{i=0}^{2^N-1} c_i \vert i\rangle が与えられた場合、測定によって状態は基底 ∣i⟩\vert i\rangle のいずれかに崩壊し、その確率は ∣ci∣2\vert c_i\vert ^2 に等しくなります。

しかし、測定のこの破壊的な効果が常に障害になるわけではありません。実際、量子テレポーテーションや量子鍵配送などの特定のアルゴリズムやプロトコルでは、重要なリソースとなっています。

Qiskitでは、測定を行うと結果は古典レジスタに送られ、古典ビットとして保存されます。測定を含むCircuitを作成するには次のようにします。

qc = QuantumCircuit(
1, 1
) # the second number is the number of classical bits in the circuit
qc.measure(0, 0)
qc.draw("mpl")

前のコードセルの出力

Circuit​

Qubit、Gate、測定の仕組みを理解したところで、実際に量子Circuitを作成して実行してみましょう。そのために、Qiskitパターンと呼ばれる便利なワークフローを紹介します。

Qiskitパターンフレームワーク​

Qiskitパターンフレームワークは、量子コンピューターを使って問題にアプローチし解決するための一般的な手順です。4つのステップで構成されています。

  1. マッピング: 問題を量子CircuitおよびOperatorに対応付ける

  2. 最適化: ターゲットハードウェア向けにCircuitを最適化する

  3. 実行: ターゲットハードウェア上で実行する

  4. 後処理: 結果を後処理する

これらのステップを説明するために、上で紹介した半加算器Circuitの量子バージョンを実装します。

1. マッピング​

古典の半加算器Circuitは、XORゲートとANDゲートを使って、それぞれ和ビットとキャリービットを計算します。これらのゲートを量子の文脈に適用して量子半加算器を作ります。量子ゲートは可逆であるため、入力をそのまま上書きすることはできません。その代わりに、和とキャリーの出力を格納するための補助Qubit2つを ∣0⟩\vert 0\rangle で初期化して導入します。したがって、完全な量子状態はQubit AA と BB、および和とキャリーのQubit(それぞれ SS と CC とラベル付け)で構成されます。

∣ψ⟩=∣CSBA⟩\vert \psi\rangle = \vert C S B A\rangle

次に、古典回路のXORゲートとANDゲートに相当する量子ゲートが必要です。

和:

XORに対しては、制御Qubitをそれぞれ AA と BB、ターゲットQubitを両方とも SS とする2つのCNOTを適用します。AA と BB が異なる場合、どちらか一方のCNOTゲートが SS を ∣1⟩\vert 1\rangle 状態に反転させます。AA と BB が両方 ∣0⟩\vert 0\rangle の場合、SS には何も作用しないため ∣0⟩\vert 0\rangle 状態のままです。AA と BB が両方 ∣1⟩\vert 1\rangle の場合、SS の状態は2回反転し、∣0⟩\vert 0\rangle 状態に戻ります。

キャリー:

キャリービットには、古典のANDゲートと同様に機能するものが必要です。

理解度チェック​

これまでに説明したゲートを振り返り、古典のANDゲートの代わりにどの量子ゲートを使うか考えてみてください。

Answer

Toffoliゲートです。Toffoli(制御制御NOTゲート)は、制御Qubit0と制御Qubit1の両方が ∣1⟩\vert 1\rangle の場合にのみターゲット状態を反転させます。そのため、ターゲットQubitが ∣0⟩\vert 0\rangle から始まる場合、ANDゲートと同じ動作をします。

これで量子Circuitを作成するために必要な材料がそろいました。

# qubits: a, b, sum, carry
qc = QuantumCircuit(4)

# Choose values for A and B:
a = 0
b = 0

# Prepare A and B qubits according to selected values:
if a:
qc.x(0)
if b:
qc.x(1)

# XOR (sum) into qubit 2
qc.cx(0, 2)
qc.cx(1, 2)

# AND (carry) into qubit 3
qc.ccx(0, 1, 3) # a AND b

# measure
qc.measure_all()

qc.draw("mpl")

前のコードセルの出力

上図は量子半加算器CircuitのCircuit図です。前述のように、ワイヤーは上から下に順にQubit 00 から 33 を表しており、古典ビットレジスタは一番下の二重線のワイヤーです。左から右に読むことで、対応するワイヤー上のボックスの位置から各Qubitへのゲートの適用を確認できます。最後に測定が示されています。測定によってQubitの状態は確定的な 00 または 11 の値に崩壊し、結果は古典レジスタに送られます。

ひとつ注意点があります。Circuit図は左から右に描かれていますが、対応する行列式を書く際は右から左に読む必要があります。これは、行列の掛け算では状態ベクトルに最も近い演算子が最初に作用するためです。たとえば、上記のCircuit(測定を除く)は次のように表されます。

CCNOT(q0,q1,q3)CNOT(q1,q2)CNOT(q0,q2)∣q3q2q1q0⟩CCNOT(q_0,q_1,q_3)CNOT(q_1, q_2)CNOT(q_0,q_2)\vert q_3 q_2 q_1 q_0\rangle

2. 最適化​

次に、量子ハードウェア上で実行できるようCircuitを最適化する必要があります。この最適化はTranspilerによって行われます。Transpilerは上記の抽象的なCircuitを量子コンピューターが理解できる命令に変換します。論理Qubitをプロセッサ上の実際の物理Qubitに割り当て、量子コンピューターに最適化されたネイティブなゲートセットでゲートを書き直します。さらにTranspilerは、エラーの影響を最小化するための「誤り抑制と軽減」も実装します。今回の非常にシンプルなCircuitにはそれほど重要ではありませんが、量子計算の学習を進めてより複雑なCircuitを実行するようになれば、誤り抑制と軽減の価値がすぐに実感できるでしょう。詳しくは、Olivia Laneのコース「実践的な量子計算」を参照してください。

まず、IBM®量子コンピューターと通信するために必要なパッケージを読み込み、実行するBackendを選択します。最も空いているBackendを選ぶか、特性がわかっている特定のBackendを選択できます。

初回使用時に認証情報を保存するためのコードを以下に示します。ノートブックを共有する際に認証情報が誤って共有されないよう、環境に保存した後はノートブックからこの情報を削除してください。詳しくは「IBM Cloudアカウントのセットアップ」および「信頼できない環境でのサービス初期化」を参照してください。

# Load IBM Quantum Compute Service
from qiskit_ibm_runtime import QiskitRuntimeService

# Load IBM Quantum Compute Service

# Syntax for first saving your token. Delete these lines after saving your credentials.
# QiskitRuntimeService.save_account(channel='ibm_quantum_platform',
# instance = '<YOUR_IBM_INSTANCE_CRN>', token='<YOUR-API_KEY>', overwrite=True, set_as_default=True)
# service = QiskitRuntimeService(channel='ibm_quantum_platform')

# Load saved credentials
service = QiskitRuntimeService()

# Use the least busy backend, or uncomment the loading of a specific backend like "ibm_brisbane".
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)
# backend = service.backend("ibm_brisbane")
print(backend.name)
ibm_fez

次に、TranspilerでCircuitを最適化します。最適化レベルは0(最適化なし)から3(最高の最適化)まで選択できます。各レベルの詳細については、「Transpilerの最適化レベルの設定」ガイドを参照してください。結果のCircuitは、マッピングステップで作成した論理的なCircuitとは大きく異なって見えるでしょう。

# Transpile the circuit and optimize for running on the quantum computer selected
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)

qc_isa.draw("mpl")

前のコードセルの出力

「Sampler」とは、量子 Circuit から生じる可能性のある状態をサンプリングし、どの状態がどの確率で測定されるかの統計を収集するためのプリミティブです。ここで IBM Quantum Sampler をインポートします:

# Load the IBM Quantum primitive and session
from qiskit_ibm_runtime import SamplerV2 as Sampler

sampler = Sampler(mode=backend)

実際の量子コンピューターの利用可能時間を使い切った場合、またはインターネット接続がない場合は、シミュレーターを使用することもできます。その場合は以下のセルを実行し、「実行」ステップの対応する行のコメントを外してください。

# Load the backend sampler
from qiskit.primitives import BackendSamplerV2

# Load the Aer simulator and generate a noise model based on the currently-selected backend.
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel

noise_model = NoiseModel.from_backend(backend)

# Define a simulator using Aer, and use it in Sampler.
backend_sim = AerSimulator(noise_model=noise_model)
sampler_sim = BackendSamplerV2(backend=backend_sim)

# Alternatively, load a fake backend with generic properties and define a simulator.
# backend_gen = GenericBackendV2(num_qubits=18)
# sampler_gen = BackendSamplerV2(backend=backend_gen)

3. 実行​

Circuitの準備ができたので、量子コンピューターで実行しましょう!

job = sampler.run([qc_isa], shots=100)
# job = sampler_sim.run([qc_isa]) # uncomment if you want to run on a simulator
res = job.result()
counts = res[0].data.meas.get_counts()

4. 後処理​

いよいよ結果を確認します。Circuitの100回サンプルのヒストグラムを表示します。

from qiskit.visualization import plot_histogram

print("counts = ", counts)
plot_histogram(counts)
counts = {'0000': 90, '0100': 4, '1100': 3, '0010': 3}

前のコードセルの出力

上のヒストグラムは、Circuit終了時の全4つのQubitの測定結果を示しています。ノイズがまったくない理想的な量子コンピューターであれば毎回同じ値が測定されますが、実際にはノイズによって一部の実行でエラーが発生することがあります。

理解度チェック​

最も多いカウントを示すビット文字列を AA、BB、SS、CC の値として使用し、量子加算器 Circuit が正しく動作したことを確認してください。

Answer

A+B=S+2×CA+B = S+2 \times C が成り立つことを確認する必要があります。ビット文字列はリトルエンディアン記法に従っているため、CSBA の順で読むことに注意してください。

上のヒストグラムから、0000 のビット文字列が最も多いことがわかります。

0+0=0+0×2=0 ✓0 + 0 = 0 + 0 \times 2 = 0 ~\checkmark

AA と BB の値を A=1A=1、B=1B=1 に変更し、Qiskit パターンのステップをもう一度実行して Circuit を再実行してください。加算器 Circuit が再び正しく動作したことを確認してください。

Answer

最も多いビット文字列が 1011 となるヒストグラムが得られるはずです:

1+1=0+1×2=2 ✓1 + 1 = 0 + 1 \times 2 = 2 ~\checkmark

量子ハーフ加算器が古典的なハーフ加算器に対して持つ付加的な特徴の一つは、量子入力で動作できることです。つまり、qubit AA と BB が重ね合わせ状態にあっても「加算」を行えます。以下のチャレンジ問題のセクションでは、qubit を重ね合わせ状態に準備して、何が起こるかを確かめるよう問われます。

まとめ​

このモジュールは、量子コンピューティングの基本原理を古典コンピューティングと比較することで、しっかりとした基礎的理解を得ることを目的として設計されました。古典的なハーフ加算器 Circuit を検討し、それを量子コンピュータ上の qubit で動作するように適応させる方法を示しました。これで、他の「Qiskit in the Classroom」モジュールを探索する準備が整いました!

重要な概念​

  • 0 と 1 の値しか取れない古典ビットとは対照的に、qubit は 0 と 1 の両方の重ね合わせ状態を取ることもできます。

  • 複数の qubit は、古典的に許容されるビット文字列(計算基底状態と呼ばれます)の重ね合わせになることができます。

  • 複数の qubit はエンタングル(量子もつれ)状態になることができ、一方の状態が他方の状態に依存します。

  • Qiskit の規約ではリトルエンディアン記法を使用しており、最下位 qubit q0q_0 を最右端に、最上位 qubit qNq_N を最左端に配置します。

  • 量子 Gate は、量子状態ベクトルに作用するユニタリ行列で表される可逆的な演算です。この記法では、ベクトルに最も近い(最右端の)行列が最初に作用します。

  • 測定は量子重ね合わせ状態を古典的に許容される状態の一つに崩壊させます。その確率は、重ね合わせにおける対応する計算基底状態の振幅の二乗に等しくなります。

  • 量子 Circuit は量子回路図を用いて表されることが多く、qubit は水平な線として描かれ、量子 Gate はこれらの線に沿って左から右へと配置されます。

  • 量子 Circuit を実行するには、Qiskit パターンワークフローの4つのステップ、すなわちマップ、最適化、実行、後処理を使用します。

問題​

正誤問題​

  1. 古典コンピュータの1ビットは、0 または 1 の値しか保持できない。

  2. エンタングルメントとは、ある qubit の状態が別の qubit の状態と無関係であることを意味する。

  3. 量子 Gate は一般に不可逆な演算である。

  4. Qiskit の規約では、最下位 qubit q0q_0 を最左端の位置に配置する。

  5. 量子状態を測定すると、何度繰り返しても常にまったく同じ結果が得られる。

  6. Hadamard Gate は単一の qubit に重ね合わせを生成する。

  7. 量子 Circuit には、重ね合わせ状態を古典的に許容される状態の一つに崩壊させる測定演算が含まれることがある。

  8. NN ビットに対して取り得る古典状態の数は 2N2N である。

  9. 量子測定の結果確率は、古典的に測定可能な基底状態の振幅の二乗によって与えられる。

短答問題​

  1. ビットと qubit の主な違いは何ですか?

  2. 量子状態を測定すると何が起こりますか?

  3. Qiskit でリトルエンディアン記法を使用するのはなぜですか?

  4. Qiskit パターンワークフローの4つのステップは何ですか?

チャレンジ問題​

  1. このモジュールでは、加算器を使って AA と BB の古典的に許容された状態のみを加算しました。しかし、AA と BB を重ね合わせ状態に準備することもできます!各 qubit を 0 と 1 の等しい重ね合わせに準備するようコードを変更し、新しい Circuit を実行して新しいヒストグラムを取得してください。何が見えますか?何が起きているのか説明してください。

  2. Toffoli Gate の分解。decompose() を使用して、Toffoli Gate がどのように単一 qubit および2 qubit の Gate に分解されるかを示し、行列の積でこの構成を検証してください。Circuit 図は左から右へ読みますが、行列は量子状態に対して右から左へ適用されることに注意してください!