Help us understand the problem. What is going on with this article?

量子コンピュータで1+1を計算する[実装編]

More than 1 year has passed since last update.

はじめに

最近IBMが量子コンピュータ向けのSDK「Qiskit」を公開したことを知り、大変興味を引かれたのでいじってみることにしました。とはいえ情報がない。。。いや、量子コンピュータ自体についての構造についての記事はブルーバックスでも見かけますが、実際にどう計算させるかについては非常に情報が少ない。

というわけで、量子コンピュータで1+1を計算するでされていることを実装してみました。実装にはA developer’s guide to using the Quantum QISKit SDKを参考にしました。画像等は前者の記事から引用させていただきました。

というわけで、勝手に連動した記事となっています。タイトルも「量子コンピュータで1+1を計算する[実装編]」とさせていただきました。先の記事は素晴らしい内容なので、本記事と比べながら読み進めてもらうことをおすすめします。

例によってGithubに記事の内容を挙げております。もしよろしければどうぞ。

お知らせ

  • Githubのほうが更新が進んでいることがあるので、本記事で不明な点等はそちらをチェックしてみてください。
  • QISKitの公式チュートリアルが充実しつつあるので、本ノートの内容を終えた方や、より発展的な内容に興味のある方は参照されることをおすすめします。(2017年8月6日現在)

IBM QISKitで遊ぶ

このノートでは、IBMによって公開された量子コンピュータのSDK「QISKit」を用いた計算についてまとめています。詳しい量子コンピュータの原理についてはまとめていません。(私自身物理を学んでいる身なので、興味が湧けば追記するかも?) その代わり、Qiitaで初等的なよい例を見つけたので、それをコーディングとしてどう実装するかについて幾つかの例を挙げました。
このノートを実行するためにはいくつかのステップが必要です。以下の通り準備を行ってから始めてください。

(参考文献)

  1. 「量子コンピュータで1+1を計算する」
  2. A developer’s guide to using the Quantum QISKit SDK
  3. IBM Q experience library

「1.」はこのノートの元ネタです。量子コンピュータでどのように計算させるかというアルゴリズムがまとめられています。「2.」はIBMによる公式ガイドで、量子コンピュータの基礎的な背景や、開発者向けの情報がまとめられています。量子コンピュータに関する理論的背景はこちらを参考ください。なお、ブルーバックスでも扱っている巻はあるようなので、よろしければどうぞ(私は読んでいません)。「3.」では「2.」の開発者向け記事のイントロ部分がまとめられています。私がこのノートを作成したときはまだ「2.」の開発者向けチュートリアルが未完成だったのですが、今ではかなりの部分が仕上がっていますね。本記事を読まれたあとならばこちらから、より量子コンピュータについて学ぶことができると思います。

動作環境

Anaconda3, Python3, Jupyter notebook

はじめにやるべきこと

  1. IBM QuantumExperienceパッケージをpipでダウンロード&インストールする: pip install --upgrade qiskit もしくは pip3 install --upgrade qiskit

  2. 作業ディレクトリを作成し, git clone https://github.com/IBM/qiskit-sdk-pyする。

  3. make envしてAnacondaの仮想環境を作成.

  4. cp tutorial/Qconfig.py.default Qconfig.pyを実行し、Qconfig.pyを作成する。ここで、別途こちら でアカウントを作成し、Personal tokenを取得する。これをQconfig.pyの所定の欄(コメントアウトしているものを外して""内)に入れる。

  5. 作業ディレクトリのgiskit-sdk-pyディレクトリに移動し、make runでJupyter Notebookが起動する。 これで「tutorial内で」作業できるようになる。必要なライブラリはロードされいる。

アカウント作成の注意
使用目的
- 以下の2つの欄は適当に答えれば良いかも。本当の意味での研究目的じゃなくても構わない.
register.png

Personal token
以下の例は私のtokenです。

Personal_token.png

一回生成させたら、それをQconfig.py

Qconfig.py
# Before you can use the jobs API, you need to set up an access token.
# Log in to the Quantum Experience. Under "Account", generate a personal 
# access token. Replace "None" below with the quoted token string.
# Uncomment the APItoken variable, and you will be ready to go.

APItoken = "" # この中に入れる。

config = {
  "url": 'https://quantumexperience.ng.bluemix.net/api'
}

if 'APItoken' not in locals():
  raise Exception("Please set up your access token. See Qconfig.py.")

Step1: プログラムを作成する

# jupyterはtutorial内で起動するため、qiskitパッケージをインポートするためにディレクトリの階層を一つ上げる必要がある。
import sys
sys.path.append("../") 

from qiskit import QuantumProgram 
import Qconfig

プログラムの主なパートとして
- QuantumProgram : 全体的なプログラム
- a Circuit : 細かい部品をひとまとめにしたもの。プログラムはcircuitの集合として表せる。
- a Quantum Register : 入力
- a Classical Register : 出力

がある。

これらを作成する。基本的な流れとしては、量子レジスタの作成(入力)->回路の設計->量子レジスタを古典レジスタに変換->古典レジスタ(出力)となっている。

# QuantumProgramクラスのメソッドとしてQ_program作成
Q_program = QuantumProgram() 

# レジスタの作成. Qbitと名称を指定
# 2Qbitを持つレジスタqr (量子的)
Q_program.create_quantum_registers("qr", 4)
# 2bitを持つレジスタcr (古典的)
Q_program.create_classical_registers("cr", 4) 

# 回路 "qc" の作成
# 古典的なレジスタ "cr"と 量子的なレジスタ "qr" をつなげた回路
qc = Q_program.create_circuit("qc", ["qr"], ["cr"]) 
>> quantum_registers created: qr 4
>> classical_registers created: cr 4

==> 各レジスタが作成された。これらの作業は以下のようにも書ける:

Q_SPECS = {
    "name": "Program-tutorial",
    "circuits": [{
         "name": "Circuit",
         "quantum_registers": [{
             "name":"qr",
             "size": 4 
         }],
         "classical_registers": [{
              "name":"cr",
              "size": 4
         }]}],
}

上では全体の回路をQ_SPECとしてまとめた。これを用いてクラスQuantumProgramのインスタンス変数を初期化する:

Q_program = QuantumProgram(specs=Q_SPECS) 
>> quantum_registers created: qr 4
>> classical_registers created: cr 4

今後はこの方法でレジスタを作成する。回路やレジスタの指定には、以下のようにして作成したインスタンスを用いる。

#get the components.

# get the circuit by Name
circuit = Q_program.get_circuit("Circuit")

# get the Quantum Register by Name
quantum_r = Q_program.get_quantum_registers("qr")

# get the Classical Register by Name
classical_r = Q_program.get_classical_registers('cr')

Step2: 回路にゲートを追加する

以降は「量子コンピュータで1+1を計算する」 をベースにして計算させてみる。

まずは0+0を計算させよう. これまでやってきたようにレジスタを持つ回路を作成したら、circuitインスタンスにいろいろ「ゲート」を追加できる。量子コンピュータでは0+0は以下のように組めば良い.

0+0.png

# AND gate from Qbit 0 to the Qbit 1 and 2
circuit.ccx(quantum_r[0], quantum_r[1], quantum_r[2])

# XOR gate from Qbit 0 to the Qbit 3
circuit.cx(quantum_r[0], quantum_r[3])

# XOR gate from Qbit 1 to the Qbit 3
circuit.cx(quantum_r[1], quantum_r[3])

# measure gate from the Qbit 0 to Classical bit 3
circuit.measure(quantum_r[0], classical_r[3]) 

# measure gate from the Qbit 1 to Classical bit 2
circuit.measure(quantum_r[1], classical_r[2])

# measure gate from the Qbit 2 to Classical bit 1
circuit.measure(quantum_r[2], classical_r[1]) 

# measure gate from the Qbit 3 to Classical bit 0
circuit.measure(quantum_r[3], classical_r[0]) 

QASM_source = Q_program.get_qasm("Circuit")

print(QASM_source)
OPENQASM 2.0;
include "qelib1.inc";
qreg qr[4];
creg cr[4];
ccx qr[0],qr[1],qr[2];
cx qr[0],qr[3];
cx qr[1],qr[3];
measure qr[0] -> cr[3];
measure qr[1] -> cr[2];
measure qr[2] -> cr[1];
measure qr[3] -> cr[0];

Step3: コードの実行

device = 'simulator' #Backed where execute your program, in this case in the on line simulator 
circuits = ['Circuit'] #Group of circuits to exec 

Q_program.set_api(Qconfig.APItoken, Qconfig.config["url"]) 
#set the APIToken and API url 
True
Q_program.compile(circuits, device) # Compile your program

result = Q_program.run(wait=2, timeout=240)

print(result)
running on backend: simulator
{'status': 'COMPLETED', 'result': 'all done'}
Q_program.get_counts("Circuit")
{'0000': 1024}

ここで'0000'というのは、0+0=00を表している。量子レジスタは4つ用意されているので、その値が古典レジスタの値に入り、0000を出力している。

全体のコード

# jupyterはtutorial内で起動するため、qiskitパッケージをインポートするためにディレクトリの階層を一つ上げる必要がある。
import sys
sys.path.append("../") 

from qiskit import QuantumProgram 
import Qconfig

Q_SPECS = {
    "name": "Program-tutorial",
    "circuits": [{
         "name": "Circuit",
         "quantum_registers": [{
             "name":"qr",
             "size": 4 
         }],
         "classical_registers": [{
              "name":"cr",
              "size": 4
         }]}],
}

Q_program = QuantumProgram(specs=Q_SPECS)

# get the circuit by Name
circuit = Q_program.get_circuit("Circuit")

# get the Quantum Register by Name
quantum_r = Q_program.get_quantum_registers("qr")

# get the Classical Register by Name
classical_r = Q_program.get_classical_registers('cr')


# ----------------------------------------------
# Create circuit: 0 + 0
# ----------------------------------------------

# AND gate from Qbit 0 to the Qbit 1 and 2
circuit.ccx(quantum_r[0], quantum_r[1], quantum_r[2])

# XOR gate from Qbit 0 to the Qbit 3
circuit.cx(quantum_r[0], quantum_r[3])

# XOR gate from Qbit 1 to the Qbit 3
circuit.cx(quantum_r[1], quantum_r[3])

# measure gate from the Qbit 0 to Classical bit 3
circuit.measure(quantum_r[0], classical_r[3]) 

# measure gate from the Qbit 1 to Classical bit 2
circuit.measure(quantum_r[1], classical_r[2])

# measure gate from the Qbit 2 to Classical bit 1
circuit.measure(quantum_r[2], classical_r[1]) 

# measure gate from the Qbit 3 to Classical bit 0
circuit.measure(quantum_r[3], classical_r[0]) 

QASM_source = Q_program.get_qasm("Circuit")

print(QASM_source)

# ----------------------------------------------
# Output
# ----------------------------------------------

device = 'simulator' #Backed where execute your program, in this case in the on line simulator 
circuits = ['Circuit'] #Group of circuits to exec 

Q_program.set_api(Qconfig.APItoken, Qconfig.config["url"]) 
#set the APIToken and API url 

Q_program.compile(circuits, device) # Compile your program

result = Q_program.run(wait=2, timeout=240)

print(result)

Q_program.get_counts("Circuit")
>> quantum_registers created: qr 4
>> classical_registers created: cr 4
OPENQASM 2.0;
include "qelib1.inc";
qreg qr[4];
creg cr[4];
ccx qr[0],qr[1],qr[2];
cx qr[0],qr[3];
cx qr[1],qr[3];
measure qr[0] -> cr[3];
measure qr[1] -> cr[2];
measure qr[2] -> cr[1];
measure qr[3] -> cr[0];

running on backend: simulator
{'status': 'COMPLETED', 'result': 'all done'}

{'0000': 1024}

そのほかの例

1+0

1+0.png

# jupyterはtutorial内で起動するため、qiskitパッケージをインポートするためにディレクトリの階層を一つ上げる必要がある。
import sys
sys.path.append("../") 

from qiskit import QuantumProgram 
import Qconfig

Q_SPECS = {
    "name": "Program-tutorial",
    "circuits": [{
         "name": "Circuit",
         "quantum_registers": [{
             "name":"qr",
             "size": 4 
         }],
         "classical_registers": [{
              "name":"cr",
              "size": 4
         }]}],
}

Q_program = QuantumProgram(specs=Q_SPECS)

# get the circuit by Name
circuit = Q_program.get_circuit("Circuit")

# get the Quantum Register by Name
quantum_r = Q_program.get_quantum_registers("qr")

# get the Classical Register by Name
classical_r = Q_program.get_classical_registers('cr')


# ----------------------------------------------
# Create circuit: 1 + 0
# ----------------------------------------------

# bit-flip 0 -> 1
circuit.x(quantum_r[0])

# AND gate from Qbit 0 to the Qbit 1 and 2
circuit.ccx(quantum_r[0], quantum_r[1], quantum_r[2])

# XOR gate from Qbit 0 to the Qbit 3
circuit.cx(quantum_r[0], quantum_r[3])

# XOR gate from Qbit 1 to the Qbit 3
circuit.cx(quantum_r[1], quantum_r[3])

# measure gate from the Qbit 0 to Classical bit 3
circuit.measure(quantum_r[0], classical_r[3]) 

# measure gate from the Qbit 1 to Classical bit 2
circuit.measure(quantum_r[1], classical_r[2])

# measure gate from the Qbit 2 to Classical bit 1
circuit.measure(quantum_r[2], classical_r[1]) 

# measure gate from the Qbit 3 to Classical bit 0
circuit.measure(quantum_r[3], classical_r[0]) 

QASM_source = Q_program.get_qasm("Circuit")

print(QASM_source)

# ----------------------------------------------
# Output
# ----------------------------------------------

device = 'simulator' #Backed where execute your program, in this case in the on line simulator 
circuits = ['Circuit'] #Group of circuits to exec 

Q_program.set_api(Qconfig.APItoken, Qconfig.config["url"]) 
#set the APIToken and API url 

Q_program.compile(circuits, device) # Compile your program

result = Q_program.run(wait=2, timeout=240)

print(result)

Q_program.get_counts("Circuit")
>> quantum_registers created: qr 4
>> classical_registers created: cr 4
OPENQASM 2.0;
include "qelib1.inc";
qreg qr[4];
creg cr[4];
x qr[0];
ccx qr[0],qr[1],qr[2];
cx qr[0],qr[3];
cx qr[1],qr[3];
measure qr[0] -> cr[3];
measure qr[1] -> cr[2];
measure qr[2] -> cr[1];
measure qr[3] -> cr[0];

running on backend: simulator
{'status': 'COMPLETED', 'result': 'all done'}

{'1001': 1024}

1 + 0 = 01となり、1+0=1が計算できている。1024は2の10乗なので、2の冪が10になれば100%かな?違いは回路作成の最初にquantum_r[0]に対してビット反転xを施したことにある。先の例(0+0=00)では、何も入力されていない状態=0であったのが、今回は反転により1になっていた。結果としてこの理屈で計算を進めると、ほしい結果が得られた。

1+1

1+1.png

# jupyterはtutorial内で起動するため、qiskitパッケージをインポートするためにディレクトリの階層を一つ上げる必要がある。
import sys
sys.path.append("../") 

from qiskit import QuantumProgram 
import Qconfig

Q_SPECS = {
    "name": "Program-tutorial",
    "circuits": [{
         "name": "Circuit",
         "quantum_registers": [{
             "name":"qr",
             "size": 4 
         }],
         "classical_registers": [{
              "name":"cr",
              "size": 4
         }]}],
}

Q_program = QuantumProgram(specs=Q_SPECS)

# get the circuit by Name
circuit = Q_program.get_circuit("Circuit")

# get the Quantum Register by Name
quantum_r = Q_program.get_quantum_registers("qr")

# get the Classical Register by Name
classical_r = Q_program.get_classical_registers('cr')

# ----------------------------------------------
# Create circuit: 1 + 1
# ----------------------------------------------

# bit-flip 0 -> 1 at Qbit 0
circuit.x(quantum_r[0])

# bit-flip 0 -> 1 at Qbit 1
circuit.x(quantum_r[1])

# AND gate from Qbit 0 to the Qbit 1 and 2
circuit.ccx(quantum_r[0], quantum_r[1], quantum_r[2])

# XOR gate from Qbit 0 to the Qbit 3
circuit.cx(quantum_r[0], quantum_r[3])

# XOR gate from Qbit 1 to the Qbit 3
circuit.cx(quantum_r[1], quantum_r[3])

# measure gate from the Qbit 0 to Classical bit 3
circuit.measure(quantum_r[0], classical_r[3]) 

# measure gate from the Qbit 1 to Classical bit 2
circuit.measure(quantum_r[1], classical_r[2])

# measure gate from the Qbit 2 to Classical bit 1
circuit.measure(quantum_r[2], classical_r[1]) 

# measure gate from the Qbit 3 to Classical bit 0
circuit.measure(quantum_r[3], classical_r[0]) 

QASM_source = Q_program.get_qasm("Circuit")

print(QASM_source)

# ----------------------------------------------
# Output
# ----------------------------------------------

device = 'simulator' #Backed where execute your program, in this case in the on line simulator 
circuits = ['Circuit'] #Group of circuits to exec 

Q_program.set_api(Qconfig.APItoken, Qconfig.config["url"]) 
#set the APIToken and API url 

Q_program.compile(circuits, device) # Compile your program

result = Q_program.run(wait=2, timeout=240)

print(result)

Q_program.get_counts("Circuit")
>> quantum_registers created: qr 4
>> classical_registers created: cr 4
OPENQASM 2.0;
include "qelib1.inc";
qreg qr[4];
creg cr[4];
x qr[0];
x qr[1];
ccx qr[0],qr[1],qr[2];
cx qr[0],qr[3];
cx qr[1],qr[3];
measure qr[0] -> cr[3];
measure qr[1] -> cr[2];
measure qr[2] -> cr[1];
measure qr[3] -> cr[0];

running on backend: simulator
{'status': 'COMPLETED', 'result': 'all done'}

{'1110': 1024}

=> 1 + 1 = 10 (10は10進数で2) となり、1+1=2が計算できた。

0 + 0, 1 + 0, 1 + 1をいっぺんに計算する

00+01+11.png

# jupyterはtutorial内で起動するため、qiskitパッケージをインポートするためにディレクトリの階層を一つ上げる必要がある。
import sys
sys.path.append("../") 

from qiskit import QuantumProgram 
import Qconfig

Q_SPECS = {
    "name": "Program-tutorial",
    "circuits": [{
         "name": "Circuit",
         "quantum_registers": [{
             "name":"qr",
             "size": 4 
         }],
         "classical_registers": [{
              "name":"cr",
              "size": 4
         }]}],
}

Q_program = QuantumProgram(specs=Q_SPECS)

# get the circuit by Name
circuit = Q_program.get_circuit("Circuit")

# get the Quantum Register by Name
quantum_r = Q_program.get_quantum_registers("qr")

# get the Classical Register by Name
classical_r = Q_program.get_classical_registers('cr')

# ----------------------------------------------
# Create circuit: 1 + 1
# ----------------------------------------------

# superposition at Qbit 0 and 1
circuit.h(quantum_r[0])
circuit.h(quantum_r[1])

# AND gate from Qbit 0 to the Qbit 1 and 2
circuit.ccx(quantum_r[0], quantum_r[1], quantum_r[2])

# XOR gate from Qbit 0 to the Qbit 3
circuit.cx(quantum_r[0], quantum_r[3])

# XOR gate from Qbit 1 to the Qbit 3
circuit.cx(quantum_r[1], quantum_r[3])

# measure gate from the Qbit 0 to Classical bit 3
circuit.measure(quantum_r[0], classical_r[3]) 

# measure gate from the Qbit 1 to Classical bit 2
circuit.measure(quantum_r[1], classical_r[2])

# measure gate from the Qbit 2 to Classical bit 1
circuit.measure(quantum_r[2], classical_r[1]) 

# measure gate from the Qbit 3 to Classical bit 0
circuit.measure(quantum_r[3], classical_r[0]) 

QASM_source = Q_program.get_qasm("Circuit")

print(QASM_source)

# ----------------------------------------------
# Output
# ----------------------------------------------

device = 'simulator' #Backed where execute your program, in this case in the on line simulator 
circuits = ['Circuit'] #Group of circuits to exec 

Q_program.set_api(Qconfig.APItoken, Qconfig.config["url"]) 
#set the APIToken and API url 

Q_program.compile(circuits, device) # Compile your program

result = Q_program.run(wait=2, timeout=240)

print(result)

Q_program.get_counts("Circuit")
>> quantum_registers created: qr 4
>> classical_registers created: cr 4
OPENQASM 2.0;
include "qelib1.inc";
qreg qr[4];
creg cr[4];
h qr[0];
h qr[1];
ccx qr[0],qr[1],qr[2];
cx qr[0],qr[3];
cx qr[1],qr[3];
measure qr[0] -> cr[3];
measure qr[1] -> cr[2];
measure qr[2] -> cr[1];
measure qr[3] -> cr[0];

running on backend: simulator
{'status': 'COMPLETED', 'result': 'all done'}

{'0000': 233, '0101': 238, '1001': 289, '1110': 264}

となり、各結果が計算できました。このコードでは、先程のcircuit.xの代わりにcircuit.hを用いて、quantum_r[0]quantum_r[1]の重ね合わせの状態を使いました。なお各出力値の確率は足せば1024になります。

おわりに

今回は主にどうやって実装するかについてまとめました。ただ、各コードの意味をまだ深く理解できていませんし、ネットに転がっている情報も少ないので、もっともっとIBM Qに触れる人が出てくればいいのにと思います。。。

hiroyuki827
SDET 興味ある言語: Python, JavaScript その他興味: メインフレーム, Zowe, VSCode Plugin Development Certified Jenkins Engineer取得 *おことわり* Qiitaでの投稿内容は私自身の見解であり、所属会社の立場、戦略、意見を代表するものではありません。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした