測定型量子計算(MBQC)のライブラリ graphixの紹介

# MBQCとは
測定型量子計算(MBQC: Measurement Base Quantum Computing)とは、従来のゲート型量子計算と同じ計算能力を持つが、一部の物理系（光量子など）に適した実装ができる方式です。

通常のゲート型量子計算では、基底状態から初めて、ゲートを操作させることで量子もつれを逐次的に作り、望む量子状態を生成します。

MBQCでは、大規模なもつれ状態を初期値として、観測によって量子もつれを破壊しながら進み、望む量子状態を生成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/7ef27620-eea1-fd52-6041-ad9de23c20ef.png)


すなわち、一般には、望む量子状態より多くの量子ビットを初期状態として必要することが特徴です。
したがって、大規模な量子ビットを用意でき、かつもつれを作る労力がそれほど大きくない物理系に向いています。[^1]

また、MBQCでの”計算”には、量子もつれの生成(2量子ビット間ゲート)は登場せず、破壊する一方となります。
一般に、2量子ビット間ゲートは1量子ビット間ゲートに比べて10倍ほど誤り率が高い傾向にありますので、これは大きなメリットとなります。

MBQCは興味深い個性を持ちますが、ライブラリがほとんどありません。
今回はGraphix というMBQCの(激レアな)ライブラリを紹介します。


# MBQCにおける計算の流れ

1. グラフ状態の生成
    1. 量子ビットを多めに用意する
    2. すべての量子ビット状態を $|+>$へ初期化する
    3. 量子ビット間でCZゲートを行い、もつれさせる
2. 測定によるもつれの破壊
    以下を繰り返す
    1. 適切な量子ビットを選択する
    2. 適切な角度で射影測定を行う。ここが以前の測定結果に依存する場合がある
    3. 測定結果を古典レジスタにメモしておく
3. Byproductの相殺(=量子誤り訂正)
    1.メモしておいた測定結果をみながら、残った量子もつれ状態に$X$または$Z$ゲートを適用する
4. 残った量子もつれ状態が、求める状態になっている

上記における「多めの量子ビット」や「適切な角度での射影測定」という未定の部分は、量子アルゴリズム（実行したい量子計算）によって決まります。
グラフ状態については、「とりあえずこれを用意しておけば任意の計算に対応可能」というものがいくつか知られています。

MBQCの特徴は、破壊にともなって、もつれを通じて、残りの量子ビットに状態がどんどんテレポーテーションしていくことです。
そのため、量子テレポーテーションベースの量子計算と呼ばれたりします。

以降で、実例をみてみます。

# ライブラリ(SDK)
[Graphix](https://github.com/teamgraphix/graphix)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/de93929d-c215-2935-8d70-d937171a1ce4.png)

>Graphix is a measurement-based quantum computing (MBQC) software package,...
## 本記事のversion
>Name: graphix
Version: 0.2.16

# 環境構築
```python
pip install graphix
```

IBMQへの接続(2024/12時点でバグあり)
>https://github.com/TeamGraphix/graphix-ibmq

# チュートリアル
[Tutorial](https://graphix.readthedocs.io/en/latest/tutorial.html)
[Demo](https://graphix.readthedocs.io/en/latest/gallery/index.html)

Demos
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/23e29b1a-d082-ce62-cbad-5d6d4c15f280.png)

# 動作例

## Hゲート

$H$ゲートを適用する回路をみてみます。
MBQCでは、初期状態(グラフ状態)は$|+>$が基準ですので、
$H$ゲートを適用した場合は、出力が$H|+> = |0>$となります。
これを見ます。

graphixは、ゲート回路で書いたものを.transpile()でMBQCの計算フローへ翻訳することができます。

```python
from graphix.transpiler import Circuit
# apply H gate to a qubit in + state
circuit = Circuit(1) # |+>
circuit.h(0) # H|+>
pattern = circuit.transpile().pattern # gata to MBQC
pattern.print_pattern() # show the command sequence (pattern)
```

ちゃんと$|0>$になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/e529df94-515a-3b2e-22f6-ab272ea971ca.png)


翻訳結果を見てみます。

>N, node = 1
E, nodes = (0, 1)
M, node = 0, plane = Plane.XY, angle(pi) = 0.0, s_domain = set(), t_domain = set()
X byproduct, node = 1, domain = {0}

このようなMBQCのフローは「コマンド」と呼ばれます。
$N$コマンドは、補助量子ビットを付け加える操作です。今回、#1という補助量子ビットを1つ加えています。
$E$コマンドは、CZでもつれを生成する操作です。今回は、#0-1間CZをしています。
ここまでがグラフ状態の生成となります。

$M$コマンドは、測定です。node=0は、量子ビット#0への測定であることを示しています。
Plane.XYおよびangleは、測定の角度を指定しています。射影測定のオブザーバブルのことです。
s_domainやt_domainは、これまでの測定の結果が本測定の角度に影響を与える（オフセットする）場合に用いられます。フィードフォワード(FF)と呼ばれます。今回はsetの中身がないので、FFによる角度のオフセットはありません。

*byproduct*は、測定に伴うエラーを補正する事後処理の必要性を示しています。今回は量子ビット#1に、量子ビット#0の測定結果が1である場合に、Xゲートを掛ける指示をしています。

*byproduct*は、量子テレポーテーションプロトコルでよく出てくる概念です。
もつれと、射影測定による破壊を通じて量子状態をテレポートさせるときに、測定結果に応じてテレポート先の状態が変わります（エラーが起きえます）。[^2]
これを訂正することで、測定結果によらず、同じ量子状態を出現させることができます。
*byproduct*をキャンセルさせないと、測定結果が1の場合はテレポート失敗となってしまい、確定的な量子計算となりません。この場合、数ステップも重ねると、計算がほぼ成功しなくなってしまいます。

これを図にすることができます。

```python
pattern.draw_graph()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/00631b12-24b0-a855-8e32-039c4420d158.png)

#0と#1のもつれ状態(破線)から開始して、#0を測定で破壊し、それに伴って#1へbyproductがかかる、ということを示しています。

## Qiskitによる等価回路

理解のために、MBQCのフローを、量子ゲートで記述しなおしてみると、以下のようになります。
qiskit（ゲート型）に慣れた人であれば、こちらのほうが理解に誤解がないでしょう。

(訂正)以下のうち、最初のXゲートは誤り。Hゲートが正しいです。

```python
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
qr = QuantumRegister(2)    
cr = ClassicalRegister(2)
qc = QuantumCircuit(qr,cr)

# prepare a graph state
qc.x([0,1])
qc.cz(0,1)
qc.barrier()

# measure the qubit #0 in X-basis
qc.h([0]) # rotate basis
qc.measure(qr[0],cr[0]) # Z-basis measurement

# Cancell a X-byproduct
with qc.if_test((cr[0], 1)):
    qc.x(1)
qc.barrier()

qc.draw("mpl")
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/a98d859b-fb72-4ac6-7a7f-471e8346a0e1.png)

量子テレポーテーションの回路そのものだ、ということがわかると思います。

## RXゲート

少し難しい例として、$RX$ゲートを見てみます。

```python
from graphix.transpiler import Circuit
# apply H gate to a qubit in + state
circuit = Circuit(1)
circuit.rx(0,np.pi/4)
pattern = circuit.transpile().pattern
pattern.print_pattern() # show the command sequence (pattern)
````
>N, node = 1
N, node = 2
E, nodes = (0, 1)
E, nodes = (1, 2)
M, node = 0, plane = Plane.XY, angle(pi) = 0.0, s_domain = set(), t_domain = set()
M, node = 1, plane = Plane.XY, angle(pi) = -0.25, s_domain = {0}, t_domain = set()
X byproduct, node = 2, domain = {1}
Z byproduct, node = 2, domain = {0}

なんと全部で3量子ビットが必要になります。
$M$コマンドも特徴的で、二個目の$M$のところで、s_domainが空でなくなっています。
ここでは、#0の量子ビットの測定結果(1個前)に応じて、angleにオフセットがかかることを意味しています。
また、量子ビット#2に終状態が現れます。
このように、最初に用意した量子ビット#0とは違う量子ビットに終状態が出てくることが、MBQCの特徴ですね。どんどんテレポーテーションしていきます。

絵としてはこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/9706d6ba-b938-7a4a-a003-e47567c7f898.png)

## CNOTゲート
この辺りから、えらいことになります。

```python
from graphix.transpiler import Circuit
# apply H gate to a qubit in + state
circuit = Circuit(2)
circuit.cnot(0,1)
pattern = circuit.transpile().pattern
pattern.print_pattern() # show the command sequence (pattern)
```

>N, node = 2
N, node = 3
E, nodes = (1, 2)
E, nodes = (0, 2)
E, nodes = (2, 3)
M, node = 1, plane = Plane.XY, angle(pi) = 0.0, s_domain = set(), t_domain = set()
M, node = 2, plane = Plane.XY, angle(pi) = 0.0, s_domain = set(), t_domain = set()
X byproduct, node = 3, domain = {2}
Z byproduct, node = 3, domain = {1}
Z byproduct, node = 0, domain = {1}

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/28a56093-53d5-b82d-9a8a-140c16343133.png)

じっくり眺めると、フローがわかると思います。
このように、byproductがどんどん飛んでいくのが面白いんですよね。

## CCNOTゲート
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/a05297e3-f0f2-841f-33d2-478ec1ad08b3.png)
(以降も延々と続く)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/b6041f7f-e622-ce10-2bc0-2cb8e5a1597d.png)

もはや合っているのかもよくわからない！

MBQCの一般論は下記に説明があります。
[Introduction to MBQC](https://graphix.readthedocs.io/en/latest/intro.html)
そこまで難しい式ではないので、この記事の内容を理解しておけば読めると思います。

# MBQCのメリット・デメリット
改めて、メリットとデメリットを整理します。

メリット

- 大規模な量子もつれの準備コストが低ければ、測定と、Byproductキャンセル用の1量子ビットゲート$X,Z$のみで計算が進むため、誤り率が下げやすい
    - しかもこの1量子ビットゲートは、古典事後処理にできるのでは？と思った。
- 測定の角度を切り替えるのはそこまで難しくない

デメリット

- 必要な量子ビット数が膨大となり、ゲート記述からの翻訳の計算量も馬鹿にならない
- 直感的に動作がわかりにくい（翻訳のバグがあっても発見が難しい）
- フィードフォワードがあるので、測定の遅延が演算速度をリミットしてしまう
- MBQCが有利な物理系が限られる（ほぼ光量子用ではないかと思う）。

# 所感

もう少しデバッグとかやりやすい仕組みがあるといいですね。

[^1]: これは、光量子計算の場合に満たしやすいとされています。
[^2]: 測定結果はランダムなので、テレポート先の状態はコントロールできません（一意に決まりません）。このことが、量子テレポーテーションで光速を超える情報通信ができない理由となっています。byproductのキャンセルをしないと状態を確定できないのですが、そのための通信(測定結果を間違いなく伝える)が古典通信でなければならないためです。筆者は「量子状態は確率的であることが、”ずる”を封じてしまう」というこの”矛盾”に気づいたとき、めちゃくちゃ感動したのを覚えています。