Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quantum-kittens
GitHub Repository: quantum-kittens/platypus
Path: blob/main/notebooks/summer-school/2021/resources/lab-notebooks/lab-1-ja.ipynb
3855 views
Kernel: Python 3

Part I: Qiskit入門

Qiskitへようこそ!Exerciseを始める前に、この下のセルを「シフト」+「エンター」で実行してください。

import numpy as np # 標準的なQiskitライブラリーをインポートします from qiskit import QuantumCircuit, transpile, assemble, Aer, IBMQ, execute from qiskit.quantum_info import Statevector from qiskit.visualization import plot_bloch_multivector, plot_histogram from qiskit_textbook.problems import dj_problem_oracle

I.1: 1量子ビットにおける基本的な回転とブロッホ球における測定

複数量子ビットにおける複雑な回路を学ぶ前に、単一量子ビットについて見てみることから始めましょう。こちらの章:https://qiskit.org/textbook/ja/ch-states/introduction.html を読むと、ブロッホ球、パウリ演算子、また、アダマールゲート、SSSS^\daggerゲートについての基礎を学ぶことができます。

デフォルトでは、qiskitにおける状態は0|0\rangleから始まり、これは、ブロッホ球では「上矢印」に相当します。XX, YY, ZZ, HH, SS, SS^\daggerゲートについて試してみて、回転の感覚をつかんでください。そのために、プログラムで示された行に以下のコードの組み合わせを入れてください:

qc.x(0) # x軸周りのPi回転 qc.y(0) # y軸周りのPi回転 qc.z(0) # z軸周りのPi回転 qc.s(0) # z軸周りのPi/2回転 qc.sdg(0) # z軸周りの-Pi/2回転 qc.h(0) # xとzの中間に位置する軸周りのPi回転

以下の各Exerciseにおいてブロッホ球上の状態を指示された状態に変更してみてください。(コードのセルを実行させるにはシフト+エンターを押します。)

1.) 簡単なビットフリップの実行から始めましょう。状態を 1|1\rangleにすることがゴールです。

def lab1_ex1(): qc = QuantumCircuit(1) # # # ここにコードを書いてください # # return qc state = Statevector.from_instruction(lab1_ex1()) plot_bloch_multivector(state)
from qc_grader import grade_lab1_ex1 # grade関数は測定なしの量子回路を期待していることに注意してください grade_lab1_ex1(lab1_ex1())

2.) 次に重ね合わせを作ります。 +=12(0+1)|+\rangle = \frac{1}{\sqrt{2}}\left(|0\rangle + |1\rangle\right)の状態にすることがゴールです。

def lab1_ex2(): qc = QuantumCircuit(1) # # # ここにコードを書いてください # # return qc state = Statevector.from_instruction(lab1_ex2()) plot_bloch_multivector(state)
from qc_grader import grade_lab1_ex2 # grade関数は測定なしの量子回路を期待していることに注意してください grade_lab1_ex2(lab1_ex2())

3.) これら二つを結合させましょう。ゴールは状態 =12(01)|-\rangle = \frac{1}{\sqrt{2}}\left(|0\rangle - |1\rangle\right)にすることです。

別の方法も考えられますか?

def lab1_ex3(): qc = QuantumCircuit(1) # # # ここにコードを書いてください # # return qc state = Statevector.from_instruction(lab1_ex3()) plot_bloch_multivector(state)
from qc_grader import grade_lab1_ex3 # grade関数は測定なしの量子回路を期待していることに注意してください grade_lab1_ex3(lab1_ex3())

4.) 最後に、複素数を扱いましょう。ゴールは、i=12(0i1)|- i\rangle = \frac{1}{\sqrt{2}}\left(|0\rangle - i|1\rangle\right)の状態にすることです。

def lab1_ex4(): qc = QuantumCircuit(1) # # # ここにコードを書いてください # # return qc state = Statevector.from_instruction(lab1_ex4()) plot_bloch_multivector(state)
from qc_grader import grade_lab1_ex4 # grade関数は測定なしの量子回路を期待していることに注意してください grade_lab1_ex4(lab1_ex4())

I.2: 複数量子ビットゲートを使った量子回路

よくできました!単一量子ビットゲートを理解したので、次に複数量子ビットにおけるゲートを見てみましょう。理論を再確認したい方は、こちらの章をご確認ください:https://qiskit.org/textbook/ja/ch-gates/introduction.html 2量子ビットまたは3量子ビットにおける基本のゲートは、

qc.cx(c,t) # 制御X(=CNOT)ゲート(制御量子ビットcとターゲット量子ビットt) qc.cz(c,t) # 制御Zゲート(制御量子ビットcとターゲット量子ビットt) qc.ccx(c1,c2,t) # 制御制御X(=トフォリ)ゲート(制御量子ビットc1、c2とターゲット量子ビットt) qc.swap(a,b) # SWAPゲート(量子ビットaとbの状態をスワップする)

2量子ビットにおける簡単なゲートである制御NOT(CNOT)ゲートから始めます。これは、状態0|0\rangleの2量子ビットには何も効果がないので、制御量子ビットを重ね合わせの状態するために先にアダマールゲートを適用します。この方法で、エンタングルメントを作ることができます。結果の状態は、いわゆるベル状態の一つになります。

5.) ベル状態Φ+=12(01+10)|\Phi^+\rangle = \frac{1}{\sqrt{2}}\left(|01\rangle + |10\rangle\right)を構築する

def lab1_ex5(): qc = QuantumCircuit(2,2) # 今回は、2量子ビットを使うだけでなく、2古典ビットも測定のために使います # # # ここにコードを書いてください # # return qc qc = lab1_ex5() qc.draw() # 回路を描画します
from qc_grader import grade_lab1_ex5 # grade関数は測定なしの量子回路を期待していることに注意してください grade_lab1_ex5(lab1_ex5())

次に上の回路に測定を追加することで、実行して(シミュレーターを使います)、対応するカウント数のヒストグラムをプロットできるようになります。

qc.measure_all() # すべての量子ビットを測定します backend = Aer.get_backend('qasm_simulator') # バックエンドとしてシミュレーターを選択します counts = execute(qc, backend, shots = 1000).result().get_counts() # シミュレーターを実行しカウント数を得ます plot_histogram(counts) # ヒストグラムをプロットし、考えられる結果と対応する確率を確認しましょう

ヒストグラムからわかるように、ありえる結果は"01"と"10"のみなので、2量子ビットの状態は常に完全な反相関しています。

6.) 3量子ビットの量子回路でΨ=12(010101)|\Psi\rangle = \frac{1}{\sqrt{2}} \left(|010\rangle - |101 \rangle \right)のGHZ状態を作る関数を作ってください。

ヒント:以下の回路はGHZ=12(000+111)|GHZ\rangle = \frac{1}{\sqrt{2}} \left(|000\rangle + |111 \rangle \right)のGHZ状態を作ります:

def lab1_ex6(): # # # ここにコードを書いてください # # return qc qc = lab1_ex6() qc.draw() # 回路を描画します
from qc_grader import grade_lab1_ex6 # grade関数は測定なしの量子回路を期待していることに注意してください grade_lab1_ex6(lab1_ex6())

おめでとうございます!入門編のExerciseが完了しました。ブロッホ球と基本的な量子ゲートの知識を深めていただけたと思います。それでは、これらの知識をPart II に応用し、最初の量子アルゴリズム、ドイチ・ジョザのアルゴリズムを構築してみましょう。

Part II: オラクルとドイチ・ジョザのアルゴリズム

多くの量子アルゴリズムはいわゆるoracles\textit{oracles}の概念を中心としています。オラクルは、「ブラックボックス」とみなされる関数です。一般的に、私たちは、この関数の特性を知りたいと思っています。そのために、オラクルに質問(問合せ)をします。そして、問合せの複雑性は、これらの特性を知るための最小の問い合わせ数で定義されます。

オラクルに慣れるために、ドイチ・ジョザ問題を考えます。古典の方法に比べて量子の解法が劇的に少ない問合せ数になることを見ていきましょう。

II.1: ドイチ・ジョザ問題

ビット列の入力によって、00または11が返される、以下のような隠れたブール関数ffが与えられています:

f({x0,x1,x2,...})0 or 1 , where xn is 0 or 1f(\{x_0,x_1,x_2,...\}) \rightarrow 0 \textrm{ or } 1 \textrm{ , where } x_n \textrm{ is } 0 \textrm{ or } 1

与えられたブール関数の特性はバランス型か定値型のどちらかだと保証されています。定値型関数は、どんな入力に対しても、全て00または全て11を返します。一方、バランス型関数の場合は、すべての入力に対して0011を完全に半分ずつ返します。我々のタスクは、与えられた関数がバランス型か定値型のどちらなのか決定することです。

ドイチ・ジョザアルゴリズムは、ベストな古典アルゴリズムよりも優れた性能を発揮する最初の量子アルゴリズムの例でした。このアルゴリズムは、計算ツールとしての量子コンピューターの優位性をある特定の問題に対して証明しました。

ドイチ・ジョザ問題では、未知のオラクルを与えられます。これはQiskitでは以下の関数で実装されます:

oraclenr = 4 # オラクルを決定します(1から5の範囲です) oracle = dj_problem_oracle(oraclenr) # 5個のオラクルのうち1個を与えます oracle.name = "DJ-Oracle"

この関数は、5量子ビットの入力によって、あるオラクルを与えます。最後の量子ビット(q4q_4)は出力です。オラクルの感覚を得るために、異なる入力文字列を渡してq4q_4の出力を測定する回路を作ってみましょう。これは、オラクルがバランス型か定値型かを決定する古典的な手法に相当します。

def dj_classical(n, input_str): # 量子回路をn量子ビットと1古典読み出しビットで構築します dj_circuit = QuantumCircuit(n+1,1) # 入力ビット列に相当する初期状態を準備します for i in range(n): if input_str[i] == '1': dj_circuit.x(i) # オラクルを追加します dj_circuit.append(oracle, range(n+1)) # 4つ目の量子ビットを測定します dj_circuit.measure(n,0) return dj_circuit n = 4 # 量子ビットの数 input_str = '1111' dj_circuit = dj_classical(n, input_str) dj_circuit.draw() # 回路を描画します

では、結果をシミュレートして、この回路の結果を見てみます。別の入力ビット列も試してその結果も見てみましょう!

input_str = '1111' dj_circuit = dj_classical(n, input_str) qasm_sim = Aer.get_backend('qasm_simulator') transpiled_dj_circuit = transpile(dj_circuit, qasm_sim) qobj = assemble(transpiled_dj_circuit, qasm_sim) results = qasm_sim.run(qobj).result() answer = results.get_counts() plot_histogram(answer)

オラクルがバランス型か定値型か分かりましたか?この4ビットの古典的なドイチ・ジョザのオラクルがバランス型か定値型かをチェックするためには、最小と最大で何個の入力が必要でしょうか?

def lab1_ex7(): min_nr_inputs = # 答えをここに入力します max_nr_inputs = # 答えをここに入力します return [min_nr_inputs, max_nr_inputs]
from qc_grader import grade_lab1_ex7 # grade関数は測定なしの量子回路を期待していることに注意してください grade_lab1_ex7(lab1_ex7())

II.2: ドイチ・ジョザ問題の量子の解法

量子コンピューターを使うと、たった1回の関数f(x)f(x)への問い合わせで、オラクルが定値型かバランス型か100%の信頼度でわかります。この関数ffは量子回路として実装され、状態xy\vert x\rangle \vert y\rangle xyf(x) \vert x\rangle \vert y \oplus f(x)\rangleにマップします。ここで、\oplus22を法とする加算です。以下でこのアルゴリズムを見ていきます。

2つの量子レジスターを準備します。 1つ目は、nn量子ビットレジスターで0|0\rangleで初期化され、2つ目は、1量子ビットレジスターで=12(01)|-\rangle =\frac{1}{\sqrt{2}}\left(|0\rangle - |1 \rangle \right)で初期化されています。 量子状態は、b3b2b1b0q3q2q1q0\vert b_3 b_2 b_1 b_0\rangle_{q_3q_2q_1q_0}と書かれることに注意してください。つまり、バイナリー数のように、最後のビットb0b_0が最初の量子ビットの状態に相当します。 従って、初期状態を以下のようにセットしたいということです。ψ0=0n.\vert \psi_0 \rangle = \vert -\rangle \otimes \vert0\rangle^{\otimes n}.

n=4 def psi_0(n): qc = QuantumCircuit(n+1,n) # (|00000> - |10000>)/sqrt(2)の状態を構築します # # # ここにコードを書いてください # # return qc dj_circuit = psi_0(n) dj_circuit.draw()

量子ビットオラクルを任意の状態xy\vert x\rangle \vert y\rangleに適用するとxyf(x)\vert x\rangle \vert y \oplus f(x)\rangleの状態になります。 最後の量子ビットqnq_nの状態に相当するy|y\rangle|-\rangleの状態として用意したので、任意の入力ビット列xxが与えられた時のオラクルの出力は、以下のようになります:

12x(f(x)1f(x))=12(1)f(x)x(01)=(1)f(x)x.\frac{1}{\sqrt{2}}\vert x\rangle (\vert f(x)\rangle - \vert 1 \oplus f(x)\rangle) = \frac{1}{\sqrt{2}} (-1)^{f(x)}|x\rangle (|0\rangle - |1\rangle ) = (-1)^{f(x)}|x\rangle |-\rangle.

従って、ビット列 xxに働く位相オラクルを作ったことになります。

しかし、オラクルを適用する前に、入力状態を最初のnn量子ビットで作成する必要があります。 そのために、均等な量子重ね合わせ状態が必要となり、n+1n+1量子ビットの状態は以下のように与えられます: ψ1=12n+1x=02n1x(01)\vert \psi_1 \rangle = \frac{1}{\sqrt{2^{n+1}}}\sum_{x=0}^{2^n-1} \vert x\rangle \left(|0\rangle - |1 \rangle \right)

def psi_1(n): # |psi_0> = (|00000> - |10000>)/sqrt(2)状態を得ます qc = psi_0(n) # 量子重ね合わせ状態|psi_1>を作ります # # # ここにコードを書いてください # # return qc dj_circuit = psi_1(n) dj_circuit.draw()

これで、オラクルを準備された量子重ね合わせ状態ψ1\vert \psi_1 \rangleに適用する用意できました。これは以下の状態になります:

ψ2=12n+1x=02n1x(f(x)1f(x))=12n+1x=02n1(1)f(x)x(01)=12nx=02n1(1)f(x)x.\vert \psi_2 \rangle = \frac{1}{\sqrt{2^{n+1}}}\sum_{x=0}^{2^n-1} \vert x\rangle (\vert f(x)\rangle - \vert 1 \oplus f(x)\rangle) = \frac{1}{\sqrt{2^{n+1}}}\sum_{x=0}^{2^n-1}(-1)^{f(x)}|x\rangle (|0\rangle - |1\rangle ) = \frac{1}{\sqrt{2^{n}}}\sum_{x=0}^{2^n-1}(-1)^{f(x)}|x\rangle |-\rangle.
def psi_2(oracle,n): # psi_1を得る回路 qc = psi_1(n) # oracleを追加します qc.append(oracle, range(n+1)) return qc dj_circuit = psi_2(oracle, n) dj_circuit.draw()

アルゴリズムの最後として、2個目のレジスターの出力を無視し、最初のレジスターにn個のアダマールを適用します。その後、これらの量子ビットの結果を測定します。

def lab1_ex8(oracle, n): # このexerciseは関数psi_0 (In [24])とpsi_1 (In [25])のコードにも依存していることに注意 qc = psi_2(oracle, n) # n個のアダマールを適用 # # # ここにコードを書いてください # # # 量子ビットを古典ビットに結合することで測定を追加 # # # ここにコードを書いてください # # return qc dj_circuit = lab1_ex8(oracle, n) dj_circuit.draw()
from qc_grader import grade_lab1_ex8 # grade関数は測定なしの量子回路を期待していることに注意してください grade_lab1_ex8(lab1_ex8(dj_problem_oracle(4),n))

このポイントでは、2個目の単一量子ビットレジスターは無視されるでしょう。最初のレジスターの各量子ビットにアダマールゲートを適用すると以下の状態になります: ψ3=12nx=02n1(1)f(x)[y=02n1(1)xyy]=12ny=02n1[x=02n1(1)f(x)+xy]y, \begin{aligned} \lvert \psi_3 \rangle & = \frac{1}{2^n}\sum_{x=0}^{2^n-1}(-1)^{f(x)} \left[ \sum_{y=0}^{2^n-1}(-1)^{x \cdot y} \vert y \rangle \right] \\ & = \frac{1}{2^n}\sum_{y=0}^{2^n-1} \left[ \sum_{x=0}^{2^n-1}(-1)^{f(x)+x \cdot y} \right] \vert y \rangle, \end{aligned}

ここで、xy=x0y0x1y1xn1yn1x \cdot y = x_0y_0 \oplus x_1y_1 \oplus \ldots \oplus x_{n-1}y_{n-1}はビット単位の積の和です。 次に最初のレジスターの測定を含めた回路をシミュレーターで実行してみましょう:

qasm_sim = Aer.get_backend('qasm_simulator') transpiled_dj_circuit = transpile(dj_circuit, qasm_sim) qobj = assemble(transpiled_dj_circuit) results = qasm_sim.run(qobj).result() answer = results.get_counts() plot_histogram(answer)

レクチャーで学んだように、出力のビット列がゼロの場合は、オラクルが定値型だとわかります。出力のビット列がゼロでない場合は、バランス型です。オラクルの定義の最初の部分のオラクル数を変えてみることで、他のオラクルも試してみることができます!