Skip to main content
IBM Quantum Platform

教室で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時間を使用した。 これはあくまでも目安である。 実際の使用方法は異なる場合があります。

# 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の使い方を紹介します。

まず古典的なコンピュータの仕組みを簡単に説明し、次にこれらの概念を量子コンピュータのパラダイムにどのように適合させるかを紹介する。 最後に、これらのコンセプトを組み合わせて最初の量子回路を作り、実行する方法を紹介する。


古典的コンピュータ

古典的なコンピュータの基本的な仕組みはよくご存知だと思うが、ここでは量子コンピュータとの比較をするために、主要な特徴をいくつか紹介しよう。

情報の基本単位:ビット

古典コンピュータは古典情報を処理し、古典情報の基本単位はビットである。 1ビットに1つの「はい/いいえ」の質問の答えを格納することができる。 私たちは通常、ビットの2進状態を "0 "と "1 "で表す。

2進数の復習

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

コラム「 1 」
コラム「 2 」
コラム「 3 」
コラム「 4 」
0 = 00004 = 01008 = 100012 = 1100
1 = 00015 = 01019 = 100113 = 1101
2 = 00106 = 011010 = 101014 = 1110
3 = 00117 = 011111 = 101115 = 1111

一般に、 NN ビットの2進数から、おなじみの base-10 数に変換するには、最下位(右端)のビットに 20=12^0 = 1 を掛け、その次のビットに 21=22^1 = 2 を掛け、その次のビットに 22=42^2 = 4 を掛け、というように、最上位(左端)のビットに達するまで、 2N−12^{N-1} を掛けます。

つまり、 NN ビットは、 2N2^N のいずれかの状態になりうるということだ。

理解度チェック

86という数字を表すには何ビットが必要ですか? この数値を2進数でエンコードしたビット列を書き出す。

  • 覚えておいてほしいのは、 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}

基本演算:論理ゲート

さて、コンピュータが計算するためには、ビットを使って何かをする必要がある。 バイナリゲートは、より複雑なアルゴリズムやコードの基本的な構成要素を形成する演算である。

シングルビットゲート:

NOT

ビットが1つしかない場合、そのビットの状態を変換する方法は1つしかない。 私たちはこれを "NOT "ゲートと呼んでいる。 このゲートの効果は、以下で説明する他のゲートも含めて、いわゆる「真理値表」で表すことができ、列は量子ビットの入力と出力の状態を表す。 NOTゲートの真理値表はこうなる:

入力
出力
01
10

マルチビットゲート:

および

ANDは、2つの入力ビットを受け取り、1つのビットを出力する2ビットゲートである。 入力ビットが両方とも1であれば1を出力し、そうでなければ0を出力する:

入力
出力
000
10
100
111

または

ORも出力ビットが1つの2ビットゲートである。 いずれかのビットが1の場合、1を出力する:

入力
出力
000
11
101
111

XOR

XORは「排他的論理和」の略で、ORゲートのようなものだが、入力ビットのうち 1つだけが 1の場合に1を出力する。 両方1か両方0の場合は0を出力する:

入力
出力
000
11
101
110

寸法:

通常、古典的なコンピューティングを学ぶ場合、ビットの状態を読み出すプロセスにはあまり注意が払われない。 概念的にはそれほど複雑ではないからだ。 計算の前でも途中でも後でも、いつでもビットを測定することができ、結果に影響を与えることはない。 後述するように、量子コンピューティングの場合はそうではない。

回路:

上記のゲートを組み合わせることで、コンピューター上であらゆる操作を行うことができる。 簡単な例を見てみよう:ANDゲートとXORゲートを使って、2ビットの和を計算する半加算回路を作ることができる。 これは論理回路図で表され、ワイヤーはビットを表し、ビット上で動作するゲートは対応するワイヤー上のシンボルで示される:

半加算回路の古典的な回路図。 XORゲートはSum出力ビットを生成し、ANDゲートはCarry出力ビットを生成する。

そこで、2つのビットをコピーし、ANDゲートとXORゲートの両方に通す。 XORゲートの結果は「サム・ビット」(S)であり、2進数の1位のままであり、ANDゲートの結果は「キャリー・ビット」(C)であり、2進数の最上位桁の次の桁の値である。 これが真理値表だ:

AA
BB
和 ( 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 を検証する。

  • 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 量子ビット

ビットが古典的な情報の基本単位であるように、 量子ビット(量子ビット)は量子情報の基本単位である。 古典的なビットと同様に、量子ビットの状態は0か1のどちらかになります。通常、この状態を ∣0⟩\vert 0\rangle と ∣1⟩\vert 1\rangle と呼びます。しかし、古典ビットとは異なり、量子ビットは、 ∣0⟩\vert 0\rangle と ∣1⟩\vert 1\rangle の両方の状態を同時に重ね合わせることができる。 ∣ψ⟩\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モジュールでその様々な結果を探求することになる。

複数の量子ビット

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

NN、2進数000...000から111...111までの 2N2^N、いずれかの状態になる可能性があることを思い出してほしい。 しかし現在では、重ね合わせの原理により、 NN の量子ビットは、これらすべての状態を同時に重ね合わせることができる!

これは次のように表すことができる

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

ここで、古典的な場合と同様に、状態 ∣j⟩\vert j\rangle は、各量子ビットが 0s と 1s の適切な組み合わせとなり、2進数 jj を表す状態に相当する。これらは、量子系の「計算基底状態」として知られている。 例えば、3キュービットの状態は、その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 までのインデックスで示される。右から左へと量子ビットの状態を読むのが慣例で、 00 の状態が一番右の状態、 N−1N-1 の状態が一番左の状態となる。 これは "リトルエンディアン "表記として知られており、私たちは左から右に読むことに慣れているので、最初は直感に反するように思えるかもしれない。

理解度チェック

一見、量子ビットをリトルエンディアン表記のように右から左に並べるのは直感に反するように思えるかもしれないが、実際には非常に論理的なことなのだ! その理由を説明してください。 (2進数から base-10 数への変換に関する前述の議論を思い出してほしい)

  • qubit0が最も右で、qubit N-1 が最も左になるように、qubitを右から左に並べると、qubit 00 は最下位ビットと関連付けられ、 202^0 が乗算され、qubit N−1N-1 は最上位ビットと関連付けられ、 2N−12^{N-1} が乗算される。

もつれ

先に述べたように、量子ビットのもう一つの重要な特徴は、互いにもつれ合うことができることである。 c0=c3=12c_0 = c_3 = \frac{1}{\sqrt{2}}、 c1=c2=0c_1 = c_2 = 0 :

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

従って、量子ビット0の状態は、 ∣0⟩\vert 0\rangle または ∣1⟩\vert 1\rangle のいずれかに等しい確率でなり、量子ビット1の状態も同様である。 しかし、これらの確率はもはや互いに独立したものではない。 もし量子ビット0の状態が ∣0⟩\vert 0\rangle であることが分かれば、量子ビット1も ∣0⟩\vert 0\rangle になることが分かる。これが、もつれた状態を測定する行為が "spooky action at a distance "と呼ばれる理由である

エンタングルメントには他の形もある。 例えば、州は

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

片方の量子ビットが ∣0⟩\vert 0\rangle、もう片方は ∣1⟩\vert 1\rangle。

理解度チェック

∣ψ⟩=∣11⟩\vert \psi\rangle = \vert 11\rangle 状態はもつれているのか? その理由は何か?

  • 絡み合ってはいない。 両方の量子ビットを測定すると結果は常に同じになるが、これは各量子ビットが常に ∣1⟩\vert 1\rangle の状態に固定されているからに他ならない。一方の量子ビットを測定した結果は、実はもう一方の量子ビットに依存しない。両者は常に ∣1⟩\vert 1\rangle。

    一般的には、それぞれの量子ビットの状態を別々に記述し、それらをこのように掛け合わせることができる:

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

    その場合は「プロダクト状態」と呼ばれ、 もつれない。

ベクトル表記

ベクトルや行列を使って、量子状態がさまざまな操作によってどのように変化するかを見ることは、しばしば役に立つ。 この表現では、量子状態はベクトルとなり、量子ゲート(次のセクションで説明する)はベクトルを変換する行列となる。

単一量子ビットの場合、状態のベクトル形式は次のように選ばれる: ∣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}

一般的な、 nn -qubitの状態については、 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}

このベクトル表記法の選択を念頭に置いて、必要な量子ゲート、量子状態に対するその効果、およびその行列形式を紹介しよう。

理解度チェック

2量子ビット系には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}

ゲート →\rightarrow 量子ゲート

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

以下に、最も一般的な量子ゲートと、それらが相互作用する量子ビットをどのように変換するかを紹介する。 該当する場合は、お馴染みのクラシック・ゲートにつなげる。

単一量子ビットゲート

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 ゲートで回路を作ると次のようになる:

from qiskit import QuantumCircuit

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

Output:

Output of the previous code cell

この非常に単純な回路図では、量子ビットは黒い水平線のワイヤーで表され、ゲートはそのワイヤー上のボックスとして表示されている。

ハダマードゲート: 重ね合わせ状態を作り出す。 真理値表:

入力
出力
∣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}

ハダマードゲートを使った回路は次のように作られる:

from qiskit import QuantumCircuit

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

Output:

Output of the previous code cell

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 ゲートで回路を作ると次のようになる:

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

Output:

Output of the previous code cell

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 ゲートで回路を作ると次のようになる:

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

Output:

Output of the previous code cell

マルチ量子ビットゲート

量子2ビットゲートは古典的な2ビットゲートに似ているが、1つ重要な注意点がある。 線形代数の用語では、これはユニタリー行列で表されることを意味する。 したがって、2つの入力量子ビットは常に2つの出力量子ビットに対応し、演算は原理的に元に戻すことができる。 これは、上で見たANDやORのような古典的ゲートとは対照的で、情報を失い、不可逆的である。

CNOT(制御NOT)ゲート: 2つの入力量子ビットは、「制御」量子ビットと「ターゲット」量子ビットと呼ばれる。 制御量子ビットの状態は変わらないが、その状態によってターゲット量子ビットに何が起こるかが決まる。 制御量子ビットが ∣1⟩\vert 1\rangle の状態にある場合、ターゲットに XX ゲートが適用される。制御量子ビットが ∣0⟩\vert 0\rangle の状態にある場合は、何の変更も行われない。

ゲートの引数の順序は、Qiskitと同様に CNOT(qcontrol,qtarget)CNOT(q_{control},q_{target}) となっています qc.cx(control, target)。 ケット内のビットの順序には、別の規則が適用されます。Qiskitでは、2量子ビットの基底状態を ∣q1q0⟩\vert q_1q_0\rangle という形式で記述します。ここで、 A=q0A=q_0 を制御ビット、 B=q1B=q_1 をターゲットビットとすると、ケットは ∣BA⟩\vert BA\rangle となり、制御ビットが右側に配置されます。 詳細については、 ビット順のガイドをご覧ください。

量子ビット 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")

Output:

Output of the previous code cell

これは、2本のワイヤーで表される2つの量子ビットを持つ最初の回路図である。 CNOTゲートは2つの量子ビット間に実装され、 q0q_0 がコントロール、 q1q_1 がターゲットとなる。

理解度チェック

Qiskit では、ほとんどのゲートが他の場所と同様にマトリックス形式で表現されます。 しかし、CNOTゲートは2つの量子ビットに作用するため、量子ビットの順序に関する規約が突然問題となってくる。 ∣q0,q1,...⟩\vert q_0,q_1,...\rangle で量子ビットを並べるテキストでは、CNOTゲートの行列表現が異なる形で示されます。 上記のCNOT行列が、状態 ∣01⟩\vert 01\rangle に対して正しい作用を持つことを、明示的な行列乗算によって確認してください。

  • 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つの量子ビットの状態を入れ替える。 真理値表:

入力
出力
∣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:

Output of the previous code cell

SWAPゲートは、実際には3つのCNOTから構成することができる。 その方法を見るには、Qiskitでゲートを decompose() :

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

Output:

Output of the previous code cell

ここで初めて、回路図で複数のゲートがどのように示されているかがわかる。 左から右に読むので、一番左のゲートが最初に適用される。

理解度チェック

上記の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\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

トフォリ・ゲート(または「制御-制御-NOT」(CCNOT)): これは 3量子ビットのゲートです。 controlled-controlled-NOT "という名前から、それがどのように機能するかはすでにお分かりかと思います。2つの制御量子ビットと1つのターゲット量子ビットがあり、 両方の制御量子ビットが ∣1⟩\vert 1\rangle の状態にある場合にのみ、ターゲット量子ビットの状態が反転します。我々はCNOTで使用した順序付けの規則を維持する:

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

つまり、真理値表はこうなる:

入力
出力
∣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")

Output:

Output of the previous code cell

トフォリ・ゲートも、他のいくつかのゲートとともに、CNOTに分解することができる。 しかし、これはSWAPゲートの分解よりもかなり複雑であるため、この分解を探求し検証することは、モジュールの最後のオプション演習として残される。


計測値

測定は量子コンピュータにおいて特別な役割を果たす。 古典コンピューティングでは、アルゴリズム中の任意の時点でビットをチェックすることができるが、量子コンピューティングでは、量子ビットを見るタイミングを非常に選択しなければならない。なぜなら、測定によって量子ビットの状態が崩壊し、量子ビットの計算複雑性をもたらす重ね合わせが破壊されるからだ。

特に、 NN -bit の量子状態 ∣ψ⟩=∑i=02N−1ci∣i⟩\vert \psi\rangle = \sum_{i=0}^{2^N-1} c_i \vert i\rangle が与えられた場合、測定によって、 ∣ci∣2\vert c_i\vert ^2 に等しい確率で、基底関数 ∣i⟩\vert i\rangle のいずれかに崩壊する。

しかし、このような計測の破壊的な効果は、必ずしも妨げになるとは限らない。 実際、 量子テレポーテーションや 量子鍵配布など、特定のアルゴリズムやプロトコルにおいて重要なリソースとなっている。

Qiskitでは、測定が行われると、それは古典レジスタに送られ、古典ビットとして保存される。 測定で回路を作ると次のようになる:

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

Output:

Output of the previous code cell

回路

さて、量子ビット、ゲート、計測の仕組みがわかったところで、量子回路を自作して実行してみよう! そのためには、Qiskitパターンと呼ばれる便利なワークフローを紹介する必要がある。

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

Qiskitパターン・フレームワークは、量子コンピューターで問題に取り組み、解決するための一般的な手順である。 それは4つのステップからなる:

  1. 量子回路と量子演算子への問題のマッピング
  2. ターゲット・ハードウェアに回路を最適化する
  3. ターゲット・ハードウェア上での実行
  4. 結果の後処理

これらのステップを説明するために、上述した半加算回路の量子バージョンを実装する。

1. マッピング

古典的な加算回路は、XORゲートとANDゲートを使って、それぞれ合計ビットとキャリービットを計算する。 これらのゲートを量子コンテキストに適応させれば、量子半加算器を作ることができる。 まず、量子ゲートが可逆的であることを思い出すと、単純に入力を上書きすることはできない。 その代わりに、 ∣0⟩\vert 0\rangle に初期化された2つのヘルパー量子ビットを導入し、合計とキャリー出力を保存する。 つまり、完全な量子状態は、 AA と BB の量子ビットと、 SS と CC の和量子ビットとキャリー量子ビットで構成されます:

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

さて、古典回路でXORゲートやANDゲートが行っていたことを実現する量子ゲートが必要だ。

合計:

XORには2つのCNOTを適用し、それぞれ制御量子ビット AA、 BB、ターゲット量子ビット SS。 AA と BB が異なる場合、CNOTゲートの1つが 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ゲートの代わりにどの量子ゲートを使うかわかるだろうか:

  • トフォリのゲートだ! トッフォリ(制御-制御-NOT)ゲートは、制御量子ビット0と制御量子ビット1の両方が ∣1⟩\vert 1\rangle の場合にのみ、ターゲットの状態を反転させることを覚えておいてください。つまり、制御対象の量子ビットが ∣0⟩\vert 0\rangle の状態から始まる場合、ANDゲートと同じ動作をします。

これで量子回路を作るのに必要な材料はすべて揃った:

# 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")

Output:

Output of the previous code cell

上の図は、量子半加算回路の回路図である。 前述したように、ワイヤーは上から下に並んだ量子ビット 00 から 33 を表し、古典的なビット・レジスタは一番下の二重に並んだワイヤーである。 次に、左から右へ読んでいき、対応するワイヤのどこにボックスが表示されているかを見ることで、ゲートがそれぞれの量子ビットにどのように適用されているかを確認する。 最後に測定結果を示す。 測定は量子ビットの状態を 00 または 11 の明確な値に分解し、その結果は古典的なレジスタに送られる。

回路図は左から右に描かれているが、対応する行列式を書くときは右から左に読まなければならない。 これは、行列の乗算では、状態ベクトルに最も近い演算子が最初に作用するからである。 したがって、例えば上記の回路は(測定値を無視して)次のように書かれる:

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. 最適化:

次に、量子ハードウェア上で動作するように回路を最適化する必要がある。 この最適化はトランスパイラによって達成され、トランスパイラは上に示した抽象的な回路を量子コンピューターが理解できる命令に変換する。 上記の論理的な量子ビットをプロセッサ上の実際の物理的な量子ビットに割り当て、量子コンピュータ上で動作するように最適化された独自のゲートセットでゲートを書き換える。 最後に、トランスパイラーは「エラーの抑制と緩和」と呼ばれるものも実装しており、エラーによる結果への影響を最小限に抑えようとしている。 しかし、量子コンピューティングの旅を続け、より複雑な回路を動かすようになれば、エラーの抑制と緩和の価値がすぐにわかるだろう。 これについてもっと学びたい方は、オリビア・レーンのコース『 Quantum Computing in Practice 』をご覧ください。

まず、 IBM® 量子コンピューターとの通信に必要なパッケージをロードし、実行するバックエンドを選択する。 最もビジーでないバックエンドを選ぶか、プロパティがわかっている特定のバックエンドを選ぶことができる。

初回使用時に認証情報を保存するためのコードが以下にあります。 ノートブックを自分の環境に保存した後、必ずこの情報をノートブックから削除してください。そうすれば、ノートブックを共有するときにあなたの認証情報が誤って共有されることはありません。 詳しいガイダンスについては、 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)

Output:

ibm_fez

次に、トランスパイラを使って回路を最適化する。 最適化レベルは0(最適化なし)から3(最高最適化)まで選択できる。 各レベルの内容については、 Set transpiler optimization level guideをご覧ください。 出来上がった回路は、マッピングのステップで作った論理回路とは大きく異なるものになるだろう。

# 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")

Output:

Output of the previous code cell

「サンプラー」とは、量子回路の結果として生じうる状態をサンプリングし、どのような状態がどの程度の確率で測定されるかに関する統計情報を収集するために設計されたプリミティブである。 ここで、 IBM Quantum サンプラーをインポートします:

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

sampler = Sampler(mode=backend)

実際の量子コンピュータで割り当てられた時間を使い果たした場合や、インターネットに接続できない場合は、シミュレータを使用することをお勧めします。 これを行うには、以下のセルを実行し、"Execute "ステップの関連行のコメントを外す。

# 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. 実行

回路を準備したら、今度は量子コンピューターで走らせてみよう!

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. 後処理

これで結果を見る準備ができた! 回路の100サンプルのヒストグラムを表示します。

from qiskit.visualization import plot_histogram

print("counts = ", counts)
plot_histogram(counts)

Output:

counts =  {'0000': 90, '0100': 4, '1100': 3, '0010': 3}
Output of the previous code cell

上のヒストグラムは、回路終了時の4つの量子ビットすべての測定結果を示している。 ノイズがゼロの理想的な量子コンピューターであれば、量子ビットの測定値は毎回同じ値になるはずだが、現実にはノイズによって誤差が生じるものもある。

理解度チェック

AA, BB, SS, CC の値として最もカウント数の多いビット列を使用し、量子加算回路が動作したことを確認する。

  • 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パターンの手順をもう一度行って回路を再実行する。 加算回路が再び機能したことを確認する。

  • 優勢なビット列が 1011 であるヒストグラムが得られるはずである:

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

古典的な半加算器に対する量子半加算器の追加機能のひとつは、 量子入力で実行できることである。 つまり、量子ビット AA と BB が重ね合わせ状態であっても、「加算」することができる。 以下のチャレンジ・クエスチョン・セクションでは、量子ビットを重ね合わせた状態で用意し、何が起こるかを見てもらいます!


おわりに

このモジュールは、量子コンピューティングを古典コンピューティングと比較することで、量子コンピューティングの背後にある基本原理をしっかりと基礎から理解できるように設計されている。 私たちは古典的な半加算回路を見て、その回路を量子コンピュータの量子ビットで動作するように適応させる方法を紹介した。 これで、他のQiskit in the Classroomモジュールを探索する準備が整いました!

重要な概念:

  • 0と1しか取ることができない古典的なビットとは対照的に、量子ビットは0と1の重ね合わせ状態になることもできる。
  • 複数の量子ビットは、 計算基底状態と呼ばれる古典的に許容されるビット列上の重ね合わせ状態にあることができる。
  • 複数の量子ビットをエンタングルして、一方の状態が他方の状態に依存するようにすることができる。
  • Qiskitの慣例ではリトルエンディアン表記を使用し、最下位量子ビット q0q_0 を右端に、最上位量子ビット qNq_N を左端に配置する。
  • 量子ゲートは、量子状態ベクトルに作用するユニタリー行列で表される可逆演算である。 この表記では、ベクトルに最も近い行列(最も右にある行列)が最初に作用する。
  • 測定は、量子的な重ね合わせ状態を、古典的に許容される状態の1つに崩壊させる。
  • 量子回路は量子回路図を使って表現されることが多く、量子ビットは横線のように描かれ、量子ゲートはこの横線に沿って左から右へと現れる。
  • 量子回路を実行するには、 Qiskitパターンのワークフローにある4つのステップを使用する: マップ、 最適化、 実行、 後処理。

質問

正誤問題

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

  2. エンタングルメントとは、ある量子ビットの状態が別の量子ビットの状態から独立していることを意味する。

  3. 量子ゲートは一般に不可逆演算である。

  4. Qiskitの慣例では、最下位量子ビット( q0q_0 )を左端に配置する。

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

  6. ハダマードゲートは、1つの量子ビットに重ね合わせを作り出す。

  7. 量子回路は、重ね合わせ状態を古典的に許容される状態のいずれかに崩壊させる測定操作を含むことができる。

  8. NN ビットに対して可能な古典的状態の数は 2N2N である。

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

短答問題

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

  2. 量子状態を測定するとどうなるのか?

  3. Qiskitではなぜリトルエンディアン表記なのですか?

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

チャレンジ問題:

  1. モジュールでは、 AA と BB について、古典的に許容される状態を加算するために加算器を使っただけである。しかし、 AA と BB を重ね合わせることもできる! それぞれの量子ビットが0と1の等しい重ね合わせになるようにコードを変更し、新しい回路を実行し、新しいヒストグラムを得る。 何が見える? 何が起きているのかを説明する。

  2. トッフォリ・ゲート分解。 decompose() 、トッフォリ・ゲートがどのように1qubitゲートと2qubitゲートに分解されるかを示し、行列乗算でこの構成を検証する。 回路図は左から右に読むが、行列は右から左に量子状態に適用されることを覚えておいてほしい!

このページは役に立ちましたか?
バグや誤字の報告、またはコンテンツの要求はGitHubで行ってください。