スタビライザシミュレーション¶
'stabilizer' バックエンドは状態を振幅ではなくスタビライザ生成元で
保持します。メモリは 2**n 個の複素数ではなく O(n**2) ビットで済みます:
from blueqat import Circuit
circuit = Circuit(200).h[0]
for q in range(199):
circuit.cx[q, q + 1]
circuit.m[:].run(backend='stabilizer', shots=20, seed=1)
# => Counter({'000...0': 11, '111...1': 9})
代償は Gottesman-Knill の制約です。使えるのは Clifford ゲート( i ・
x ・ y ・ z ・ h ・ s ・ sdg ・ sx ・ sxdg ・
cx ・ cy ・ cz ・ swap )と測定・リセットだけです。 t や
rx はエラーになります(状態ベクトルか密度行列のバックエンドを使ってください)。
誤り訂正の作業が可能になるのはこのバックエンドのおかげです。距離5の 表面符号は雑音を入れる前から49量子ビット必要で、状態ベクトルの範囲を大きく 超えます(密度行列ならなおさらです)。
状態を覗く¶
shots を渡さない場合はシミュレータ自体が返ります:
sim = Circuit(3).h[0].cx[0, 1].cx[1, 2].run(backend='stabilizer')
sim.stabilizers() # ['+XXX', '+ZZI', '+IZZ']
sim.measure(0) # 収縮させて 0 か 1 を返す
sim.reset(0)
sim.copy() # 状態を分岐させる
スタビライザ文字列の q 文字目が量子ビット q のパウリです。
shots は他のバックエンドと同じ seed ・ bit_order を受け取ります。
測定結果は本当にランダムで、後からサンプリングする最終状態というものが存在
しないため、各ショットは独立した軌跡として実行されます。
計算量¶
測定は全ての行に触れ、各行は O(n) ビットなので、全量子ビットの測定は
1ショットあたり O(n**3 / 64) ワード演算です。GHZ鎖・20ショットでの実測は
100量子ビットで 0.3秒、500で 7秒、2000で 119秒。測定する量子ビットが少なければ
その分安くなります。