メインコンテンツへスキップ

教室で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 — required packages for this notebook
!pip install -q qiskit qiskit-aer qiskit-ibm-runtime
# 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で乗算し、最上位(最左端)のビットに達するまで2N12^{N-1}で乗算するまで続けます。

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

理解度チェック

以下の問いを読み、答えを考えてから、三角形をクリックして解答を確認してください。

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

答え:

NNビットでは00から2N12^N - 1までの数を表せることを思い出してください。6ビットでは最大261=632^6 - 1 = 63です。それでは足りません。もう1ビット追加して271=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和 (ABA \oplus B)桁上げ (ABA \wedge B)
0000
0110
1010
1101

理解度チェック

以下の問いを読み、答えを考えてから、三角形をクリックして解答を確認してください。

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

答え:

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になれます:

ψ=c00+c11\vert \psi\rangle = c_0 \vert 0\rangle + c_1 \vert 1\rangle

ここでc0c_0およびc1c_1c02+c12=1\vert c_0 \vert ^2+\vert c_1\vert ^2=1を満たす複素振幅です。

量子位相

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

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

ψ=c00+c1eiϕ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=i=02N1cii\psi_N = \sum_{i=0}^{2^N-1} c_i \vert i\rangle

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

ψ3=c0000+c1001+c2010+c3011+c4100+c5101+c6110+c7111\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からN1N-1で示されます。慣例として、Qubitの状態は右から左に読みます。つまりQubit 00の状態が最右端で、Qubit N1N-1の状態が最左端になります。これは「リトルエンディアン」記法として知られており、左から右に読むことに慣れているため、最初は直感に反して感じるかもしれません。

理解度チェック

以下の問いを読み、答えを考えてから、三角形をクリックして解答を確認してください。

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

答え:

Qubitを右から左に並べ、Qubit 0が最右端でQubit N-1が最左端になるようにすると、Qubit 00202^0で乗算される最下位ビットに対応させ、Qubit N1N-12N12^{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はエンタングルしていますか?その理由を答えてください。

答え:

エンタングルしていません。両方の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} このようにして、任意の状態ψ=a0+b1\vert \psi\rangle = a\vert 0\rangle+b\vert 1\rangleは次のように書けます: ψ=(ab)\vert \psi\rangle =\begin{pmatrix}a \\ b\end{pmatrix}

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

0000=(1000),0001=1110=(0010),1111=(0001)\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つの計算基底状態があります。それぞれをケット記法とベクトル記法の両方で書き出してください。

答え:

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にはQuantumの追加的な機械的特徴があるため、量子Gate(ゲート)はそれに対応してより豊富です。基底状態0|0\rangle1|1\rangleへの作用は真理値表で記述できますが、それでは全体像を捉えきれません。量子Gate(ゲート)では、基底状態の重ね合わせにも作用するため、行列表現を使用する方が自然なことが多いです。

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

1量子ビットゲート

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

入力出力
0\vert 0\rangle1\vert 1\rangle
1\vert 1\rangle0\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(01)\frac{1}{\sqrt{2}}\left(\vert 0\rangle-\vert 1\rangle\right)

行列表現: H=12(1111)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\rangle0\vert 0\rangle
1\vert 1\rangle1-\vert 1\rangle

Z=(1001)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\rangle0\vert 0\rangle
1\vert 1\rangleeiπ/41e^{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 の場合は何も変化しません。以下の表記では、Qubit AA(最右端のQubit)が制御、Qubit BB(最左端のQubit)がターゲットとします。使用する表記は CNOT(qcontrol,qtarget)BACNOT(q_{control},q_{target})\vert BA\rangle です。

CNOT(A,B)BAinput=BAoutputCNOT(A,B)\vert BA\rangle_{input} = \vert BA\rangle_{output}

入力出力
00\vert 00\rangle00\vert 00\rangle
01\vert 01\rangle11\vert 11\rangle
10\vert 10\rangle10\vert 10\rangle
11\vert 11\rangle01\vert 01\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 状態に対して正しい作用をもつことを、行列の明示的な掛け算によって確認してください。

解答:

CNOT01=(1000000100100100)(0100)=(0001)=11CNOT\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つのQubitの状態を入れ替えます。真理値表:

入力出力
00\vert 00\rangle00\vert 00\rangle
01\vert 01\rangle10\vert 10\rangle
10\vert 10\rangle01\vert 01\rangle
11\vert 11\rangle11\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")

前のコードセルの出力

SWAPゲートは実際には3つのCNOTから構成できます。その方法を確認するには、Qiskitの decompose() でゲートを分解します。

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

前のコードセルの出力

ここで初めて、Circuit図に複数のゲートがどのように表示されるかを確認できます。左から右に読むため、一番左のゲートが最初に適用されます。

理解度チェック

以下の問いを読んで答えを考えてから、三角形をクリックして解答を確認してください。

上記の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の真理値表の「出力」列と一致するはずです。

入力CNOT(A,B)CNOT(B,A)CNOT(A,B)
00\vert 00\rangle00\vert 00\rangle00\vert 00\rangle00\vert 00\rangle \checkmark
01\vert 01\rangle11\vert 11\rangle10\vert 10\rangle10\vert 10\rangle \checkmark
10\vert 10\rangle10\vert 10\rangle11\vert 11\rangle01\vert 01\rangle \checkmark
11\vert 11\rangle01\vert 01\rangle01\vert 01\rangle11\vert 11\rangle \checkmark

Toffoliゲート(または「制御制御NOT」(CCNOT)): これは 3 QubitのGateです。「制御制御NOT」という名称から動作が推測できます。2つの制御Qubitと1つのターゲットQubitがあり、両方 の制御Qubitが 1\vert 1\rangle の状態にある場合にのみ、ターゲットQubitの状態が反転します。CNOTで用いた順序規則を引き続き使用します。

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

真理値表は次のとおりです。

入力出力
000\vert 000\rangle000\vert 000\rangle
001\vert 001\rangle001\vert 001\rangle
010\vert 010\rangle010\vert 010\rangle
011\vert 011\rangle111\vert 111\rangle
100\vert 100\rangle100\vert 100\rangle
101\vert 101\rangle101\vert 101\rangle
110\vert 110\rangle110\vert 110\rangle
111\vert 111\rangle011\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=02N1cii\vert \psi\rangle = \sum_{i=0}^{2^N-1} c_i \vert i\rangle が与えられた場合、測定によって状態は基底 i\vert i\rangle のいずれかに崩壊し、その確率は ci2\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 AABB、および和とキャリーのQubit(それぞれ SSCC とラベル付け)で構成されます。

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

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

和:

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

キャリー:

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

理解度チェック

以下の問いを読んで答えを考えてから、三角形をクリックして解答を確認してください。

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

解答:

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)q3q2q1q0CCNOT(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 the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService

# Load the Qiskit Runtime 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から生じる可能性のある状態をサンプリングし、どの状態がどの確率で測定されるかの統計を収集するためのプリミティブです。ここでQiskit RuntimeのSamplerをインポートします。

# Load the Runtime 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の測定結果を示しています。ノイズがまったくない理想的な量子コンピューターであれば毎回同じ値が測定されますが、実際にはノイズによって一部の実行でエラーが発生することがあります。

理解度チェック

以下の問いを読んで答えを考えてから、三角をクリックして解答を確認しましょう。

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

解答:

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

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

解答:

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

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

量子ハーフ加算器が古典的なハーフ加算器に対して持つ付加的な特徴の一つは、量子入力で動作できることです。つまり、Qubit AABB が重ね合わせ状態にあっても「加算」を行えます。以下のチャレンジ問題のセクションでは、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. このモジュールでは、加算器を使って AABB の古典的に許容された状態のみを加算しました。しかし、AABB を重ね合わせ状態に準備することもできます!各 Qubit を 0 と 1 の等しい重ね合わせに準備するようコードを変更し、新しい Circuit を実行して新しいヒストグラムを取得してください。何が見えますか?何が起きているのか説明してください。

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