2
0

More than 1 year has passed since last update.

量子計算シミュレータの簡単な比較

Last updated at Posted at 2021-09-12

甚だしく今更感はありますが、Python ベースの量子回路シミュレータオープンソース・ソフトウェアはそれぞれどのくらい見た目・書き味が違うのだろうと思い、比較してみようと思いました。

比較ポイントは以下です:

  • 回路図の書き方
  • 複数回路の合成
  • 量子回路を単純に print したときにどう見えるか
  • 量子回路のユニタリ行列表示
  • シミュレーション結果の表示

Blueqat

量子回路をメソッドチェーン形式で書ける。
元になる状態があって、メソッドチェーンで作用を書き連ねるので、数式とは逆に右に向かって積み上げていくイメージ(図式表現と同じ向きなので、図を見ながら書くには分かりやすい)。
回路の合成は + でできる。

from blueqat import Circuit

def epr(a, b):
    return Circuit().h[a].cx[a, b]
def alice(x, a):
    return Circuit().cx[x, a].h[x]
def bob(x, a, b):
    return Circuit().cx[a, b].cz[x, b]

x = 0
a = 1
b = 2

# 回路の合成は * でなく + で行う
c = epr(a, b) + alice(x, a) + bob(x, a, b)

print(u'---- 量子回路の表示')
print(c)
print(u'---- ユニタリ行列の表示')
print(c.run(backend="sympy_unitary"))
print(u'---- シミュレーション結果の表示')
print(c.m[:].run(shots=100))
---- 量子回路の表示
Circuit(3).h[1].cx[1, 2].cx[0, 1].h[0].cx[1, 2].cz[0, 2]
---- ユニタリ行列の表示
Matrix([[1/2, 0, 1/2, 0, 0, 1/2, 0, -1/2], [1/2, 0, 1/2, 0, 0, -1/2, 0, 1/2], [1/2, 0, -1/2, 0, 0, 1/2, 0, 1/2], [1/2, 0, -1/2, 0, 0, -1/2, 0, -1/2], [0, 1/2, 0, -1/2, 1/2, 0, 1/2, 0], [0, 1/2, 0, -1/2, -1/2, 0, -1/2, 0], [0, 1/2, 0, 1/2, 1/2, 0, -1/2, 0], [0, 1/2, 0, 1/2, -1/2, 0, 1/2, 0]])
---- シミュレーション結果の表示
Counter({'010': 34, '110': 24, '100': 23, '000': 19})

簡易的に量子回路を表示する obaq もある。

# obaq 
import obaq
c.run(backend='obaq', returns='draw')

Cirq

回路はリストで与える。数式とは逆に右に向かって積み上げていくイメージ
(図式表現と同じ向きなので、図を見ながら書くには分かりやすい)。
回路の合成は append でできる。

import cirq

def epr(a, b):
    return [cirq.H(a), cirq.CNOT(a, b)]
def alice(x, a):
    return [cirq.CNOT(x, a), cirq.H(x)]
def bob(x, a, b):
    return [cirq.CNOT(a, b), cirq.CZ(x, b)]

x = cirq.NamedQubit('X')
a = cirq.NamedQubit('a')
b = cirq.NamedQubit('b')

c = cirq.Circuit()
c.append(epr(a, b) + alice(x, a) + bob(x, a, b))
print(u'---- 量子回路の表示')
print(c)
print(u'---- ユニタリ行列の表示')
print(cirq.unitary(c))
print(u'---- シミュレーション結果の表示')
print(cirq.Simulator().simulate(c))
---- 量子回路の表示
X: ───────────@───H───@───
              │       │
a: ───H───@───X───@───┼───
          │       │   │
b: ───────X───────X───@───
---- ユニタリ行列の表示
[[ 0.5+0.j  0. +0.j  0.5+0.j  0. +0.j  0. +0.j  0.5+0.j  0. +0.j -0.5+0.j]
 [ 0. +0.j  0.5+0.j  0. +0.j  0.5+0.j  0.5+0.j  0. +0.j -0.5+0.j  0. +0.j]
 [ 0.5+0.j  0. +0.j -0.5+0.j  0. +0.j  0. +0.j  0.5+0.j  0. +0.j  0.5+0.j]
 [ 0. +0.j  0.5+0.j  0. +0.j -0.5+0.j  0.5+0.j  0. +0.j  0.5+0.j  0. +0.j]
 [ 0.5+0.j  0. +0.j  0.5+0.j  0. +0.j  0. +0.j -0.5+0.j  0. +0.j  0.5+0.j]
 [-0. +0.j -0.5+0.j -0. +0.j -0.5+0.j  0.5-0.j -0. +0.j -0.5+0.j -0. +0.j]
 [ 0.5+0.j -0. +0.j -0.5+0.j -0. +0.j -0. +0.j -0.5+0.j -0. +0.j -0.5+0.j]
 [ 0. -0.j -0.5+0.j  0. -0.j  0.5-0.j  0.5-0.j  0. -0.j  0.5-0.j  0. -0.j]]
---- シミュレーション結果の表示
measurements: (no measurements)
output vector: 0.5|000⟩ + 0.5|010⟩ + 0.5|100⟩ + 0.5|110⟩

Qiskit

メソッドチェーンは使えない。時系列順に作用させていく感じ。
回路の合成は + でもできるが、DeprecatedWarning が出るので compose を使うのが良さそう。

from qiskit import Aer
from qiskit import assemble
from qiskit import QuantumCircuit, QuantumRegister

def epr(q, a, b):
    # return QuantumCircuit(q).h(q[a]).cx(q[a], q[b])
    # とは書けない
    c = QuantumCircuit(q)
    c.h(q[a])
    c.cx(q[a], q[b])
    return c
def alice(q, x, a):
    c = QuantumCircuit(q)
    c.cx(q[x], q[a])
    c.h(q[x])
    return c
def bob(q, x, a, b):
    c = QuantumCircuit(q)
    c.cx(q[a], q[b])
    c.cz(q[x], q[b])
    return c

x = 0
a = 1
b = 2
q = QuantumRegister(3, 'q')
# c = epr(q, a, b) + alice(q, x, a) + bob(q, x, a, b)
# と書くと DeprecateWarning が出る。
c = epr(q, a, b)
c = c.compose(alice(q, x, a))
c = c.compose(bob(q, x, a, b))
print(u'---- 量子回路の表示')
print(c.draw(output='text'))

print(u'---- ユニタリ行列の表示')
print(Aer.get_backend('unitary_simulator').run(c).result().get_unitary(
          c, decimals=3))

print(u'---- シミュレーション結果の表示')
sv_sim = Aer.get_backend('aer_simulator')
c.save_statevector()
job = sv_sim.run(assemble(c, shots=100))
print(job.result().get_counts())
---- 量子回路の表示
                    ┌───┐   
q_0: ────────────■──┤ H ├─■─
     ┌───┐     ┌─┴─┐└───┘ │ 
q_1: ┤ H ├──■──┤ X ├──■───┼─
     └───┘┌─┴─┐└───┘┌─┴─┐ │ 
q_2: ─────┤ X ├─────┤ X ├─■─
          └───┘     └───┘   
---- ユニタリ行列の表示
[[ 0.5+0.j  0. +0.j  0.5-0.j  0. +0.j  0. +0.j  0.5-0.j  0. +0.j -0.5+0.j]
 [ 0.5+0.j  0. +0.j  0.5-0.j  0. +0.j  0. +0.j -0.5+0.j  0. +0.j  0.5-0.j]
 [ 0.5+0.j  0. +0.j -0.5+0.j  0. +0.j  0. +0.j  0.5-0.j  0. +0.j  0.5-0.j]
 [ 0.5+0.j  0. +0.j -0.5+0.j  0. +0.j  0. +0.j -0.5+0.j  0. +0.j -0.5+0.j]
 [ 0. +0.j  0.5-0.j  0. +0.j -0.5+0.j  0.5+0.j  0. +0.j  0.5-0.j  0. +0.j]
 [-0. +0.j  0.5-0.j -0. +0.j -0.5+0.j -0.5+0.j -0. +0.j -0.5+0.j -0. +0.j]
 [ 0. +0.j  0.5-0.j  0. +0.j  0.5-0.j  0.5+0.j  0. +0.j -0.5+0.j  0. +0.j]
 [-0. +0.j  0.5-0.j -0. +0.j  0.5-0.j -0.5+0.j -0. +0.j  0.5-0.j -0. +0.j]]
---- シミュレーション結果の表示
{'000': 0.25, '001': 0.25, '010': 0.25, '011': 0.25}

SymPy

回路の合成は * でできる。
数式を書くときと同様に左に向かって積み上げていく形で回路を記述する。

CZ ゲートはない? CGate を使って自分で作る?

from sympy.physics.quantum.gate import CNOT, CGate
from sympy.physics.quantum.gate import X,Z,H
from sympy.physics.quantum.qapply import qapply
from sympy.physics.quantum.qubit import Qubit
from sympy.physics.quantum.qubit import measure_all
from sympy.physics.quantum.represent import represent

def CZ(c, x):
    # return H(x) * CNOT(c, x) * H(x) でも可。
    return CGate((c,), Z(x))
def epr(a, b):
    return CNOT(a, b) * H(a)
def alice(x, a):
    return H(x) * CNOT(x, a)
def bob(x, a, b):
    return CZ(x, b) * CNOT(a, b)

x = 2
a = 1
b = 0
c = bob(x, a, b) * alice(x, a) * epr(a, b)
print(u'量子回路の表示')
print(c)
print(u'ユニタリ行列の表示')
print(represent(c, nqubits=3))
print(u'シミュレーション結果の表示')
for m in measure_all(qapply(c * Qubit('000'))):
    print(m)
---- 量子回路の表示
C((2),Z(0))*CNOT(1,0)*H(2)*CNOT(2,1)*CNOT(1,0)*H(1)
---- ユニタリ行列の表示
Matrix([[1/2, 0, 1/2, 0, 0, 1/2, 0, -1/2], [0, 1/2, 0, 1/2, 1/2, 0, -1/2, 0], [1/2, 0, -1/2, 0, 0, 1/2, 0, 1/2], [0, 1/2, 0, -1/2, 1/2, 0, 1/2, 0], [1/2, 0, 1/2, 0, 0, -1/2, 0, 1/2], [0, -1/2, 0, -1/2, 1/2, 0, -1/2, 0], [1/2, 0, -1/2, 0, 0, -1/2, 0, -1/2], [0, -1/2, 0, 1/2, 1/2, 0, 1/2, 0]])
---- シミュレーション結果の表示
(|000>, 1/4)
(|010>, 1/4)
(|100>, 1/4)
(|110>, 1/4)

まとめ

細かい違いはありますが、簡単な量子回路を書くくらいならば大きな違いはないと感じました。

基本的な回路の記法 回路の合成 作用の記述順序 量子ビットの表示順序 print での回路表示
Blueqat メソッドチェーン + でつなげる 0 から順に左から右へ プログラム記述と同様の形式
Cirq リスト リストの連結、あるいは append メソッド NamedQubit に与えた名前のアルファベット順で左から右へ 図式表示
Qiskit 時系列順操作 compose メソッド 0 から順に右から左へ 図式表示
SymPy 作用素の積 * でつなげる 0 から順に右から左へ プログラム記述と同様の形式
2
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0