OpenCASMを用いてqiskit、PennyLaneの変換をしてみる

他の方ががっつり書かれている中、小ネタですみません。OpenCASMを使ってみたので、そのことについて書かせていただきます。 

# OpenQASMとは
OpenQASMとは、量子コンピュータのためのアセンブリ言語言語です。OpenQASMを用いることで、異なる量子コンピュータの開発環境間で量子回路の開発、実行環境を切り替えることができます。例えばIBMのqiskitで作成した量子回路をXnaduのPennyLane上で利用することができます。

OpenCASMの仕様はこちらにあります。

https://openqasm.com/

# 簡単な量子回路の移行

## qiskitにて量子回路の作成、QASM出力
まずはqiskitのライブラリーなどをインストールします。

```python
!pip install qiskit
!pip install pylatexenc
```

qiskitからQuantumCircuitをインポートします。

```python
from qiskit import QuantumCircuit
```

位相キックバック回路を作ってみます。

```python
qc = QuantumCircuit(2)
qc.h(0)
qc.h(1)
qc.cx(0,1)
```
回路図を描画してみます。

```python
qc.draw()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373940/dd4c94c5-abb2-a513-b775-75d5cb3c5c08.png)

casmの形式で回路を保存します。そうするとOpenCASMのシンタックスでの量子回路が表示されます。

```python
kickback_circuit = qc.qasm(formatted=True,filename='kickback_circuit.qasm')
include "qelib1.inc";
qreg q[2];
h q[0];
h q[1];
cx q[0],q[1];
```

保存した量子回路を読み込んで、確認のために表示します。

```python
new_kickback_circuit = QuantumCircuit.from_qasm_file('kickback_circuit.qasm')
new_kickback_circuit.draw()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545159/d91ef604-7c45-321c-203b-b6b7086063e9.png)

# PennyLaneにてQASMの読み込み

次にPennyLaneにてQASMファイルを読み込みます。まずはPennyLaneをインストールします。

```python
!pip install pennylane
```
インストールしたライブラリをインポートします。
そして、まずはcasmファイルを読み込みます。

```python
import pennylane as qml

dev = qml.device('default.qubit', wires=2)
apply_kickback = qml.from_qasm_file('kickback_circuit.qasm')
```
そして読み込んだ回路を用いてPennyLaneの形式で量子回路を定義します。

```python
@qml.qnode(dev)
def phase_kickback_circuit():
    apply_kickback(wires=[0,1])
    return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliX(1))
```
回路図を描画してみます。
```python
print(qml.draw(phase_kickback_circuit)())
0: ──H─╭●─┤  <X>
1: ──H─╰X─┤  <X>
```
うまく行ったようです。

# パラメータ付き量子回路の変換

今度はパラメータ付きの量子回路をqiskitで作ってそれを変換してみます。
必要なライブラリをあらためてインポートします。

```python
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
import numpy as np
```
パラメータ付きの量子回路を定義します。

```python
dev = qml.device('default.qubit', wires=2)

theta = Parameter('θ')

qc = QuantumCircuit(2)
qc.rz(theta, [0])
qc.rx(theta, [0])
qc.cx(0, 1)
```
casm出力します。

```python
kickback_circuit = qc.qasm(formatted=True,filename='circuit_with_parameter.qasm')
```

```text
---------------------------------------------------------------------------
QasmError                                 Traceback (most recent call last)
Input In [107], in <cell line: 13>()
     10 qc.rx(theta, [0])
     11 qc.cx(0, 1)
---> 13 kickback_circuit = qc.qasm(formatted=True,filename='circuit_with_parameter.qasm')

File ~/opt/anaconda3/lib/python3.9/site-packages/qiskit/circuit/quantumcircuit.py:1673, in QuantumCircuit.qasm(self, formatted, filename, encoding)
   1651 """Return OpenQASM string.
   1652 
   1653 Args:
   (...)
   1669     QasmError: If circuit has free parameters.
   1670 """
   1672 if self.num_parameters > 0:
-> 1673     raise QasmError("Cannot represent circuits with unbound parameters in OpenQASM 2.")
   1675 existing_gate_names = [
   1676     "barrier",
   1677     "measure",
   (...)
   1723     "c4x",
   1724 ]
   1726 existing_composite_circuits = []

QasmError: 'Cannot represent circuits with unbound parameters in OpenQASM 2.'
```
残念ながらうまく行きません。そこで`qml.from_qiskit()`を使ってPennyLaneの回路を定義します。

```python
@qml.qnode(dev)
def quantum_circuit_with_parameter(x):
    qml.from_qiskit(qc)({theta: x})
    return qml.expval(qml.PauliZ(0))
```
こちらで何とかできたようですが、casmは使えませんでした。とにかく回路を描画してみます。

```python
angle = np.pi/2
result = quantum_circuit_with_parameter(angle)

print(qml.draw(quantum_circuit_with_parameter)(angle))
0: ──RZ(1.57)──RX(1.57)─╭●─┤  <Z>
1: ─────────────────────╰X─┤     
```

# おわりに
今回はOpenCASMでqiskit->PennyLane間の量子回路の変換についてやってみました。qiskitは多くのコードがあるので、PennyLaneで動かしたいようなケースがあれば使ってみられてはいかがでしょうか。パラメタライズドされた回路がうまくいかなかったのは残念ですが、何か方法があれば、別途記事にしていきたいと思います。