Qiskit Metalを使ってみた

[Qiskit Metal](https://qiskit.org/metal)とは、超伝導型の量子コンピューターデバイスの設計開発と解析ができるオープンソースのフレームワークです。ライブラリーを使って比較的簡単に量子デバイスをデザインすることができ、様々な電磁界シミュレーター（Ansys HFSSなど）と接続して、量子ビット周波数、非調和性など必要なパラメーターをシミュレーションし、その結果をもとにレイアウトを調整していくことができます。
# インストール
（正式なインストールガイドは[こちら](https://qiskit.org/documentation/metal/installation.html)です。）
Conda環境を用意し、

```
pip install qiski-metal
```
でインストールできますが、関連するライブラリーがインストールされていないとうまく動かないので、以下のように、[Qiskit Metalのgithubリポジトリー](https://github.com/Qiskit/qiskit-metal)からenvironment.ymlを使って新しいconda環境を作ってからインストールすると良さそうです。

```
git clone https://github.com/Qiskit/qiskit-metal.git
cd qiskit-metal

conda env create -n <環境の名前> environment.yml
conda activate <環境の名前>
python -m pip install --no-deps -e .
```
最後の「.(ピリオド)」を忘れずに。

# 全体の流れ
Qiskit Metalによる量子チップデザイン開発の基本のフローは、
1. チップをデザイン（量子ビット、バス、Readout線、制御線など）
2. 解析
3. デザイン調整（解析と調整を繰り返す）
4. デザイン決定
5. GDS file (半導体レイアウトデータのファイル) に出力
6. チップを製造

となりますが、「2. 解析」には、Ansysなどのシミュレーターが必要になるため、今回は「1. チップをデザイン」のみやってみます。Qiskit Metalがインストールされた環境で、Jupyter notebookから実行しました。

# Metal GUIの起動
モジュールが変更されたときのためにモジュールの自動リロードを可能にし、必要なライブラリーをimportします。


```
# モジュールの自動リロードを有効にします
%load_ext autoreload
%autoreload 2

import qiskit_metal as metal
from qiskit_metal import designs, draw
from qiskit_metal import MetalGUI, Dict, open_docs
```

`designs`の中から、平面図面の基本的な機能を提供する`DesignPlanar()`を選択し、以下でMetal GUIを起動します。

```
design = designs.DesignPlanar()
gui = MetalGUI(design)
```

![fig0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151117/a5cfb423-390a-9859-c259-19c5ebe19485.png)


# 量子ビットのレイアウト
Metal GUIが表示できたら、GUI上のLibraryから`TransmonPocket`を選んで「Create」を選ぶことで右側メインビューにトランズモン量子ビットを作成・レイアウトできます。
![fig2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151117/2b098644-7509-d205-8aea-861dbe762a22.png)

または、以下のようにJupyter notebookからコードでも作成することができます。
`QLibrary`から、`TransmonPocket`を選んで、`Q1`という名前のトランズモン量子ビットを作成します。

```
from qiskit_metal.qlibrary.qubits.transmon_pocket import TransmonPocket

q1 = TransmonPocket(design, 'Q1')

gui.rebuild()  # デザインとプロットを再構築します
gui.edit_component('Q1') # GUI左下のOption表示をQ1のものに更新
gui.autoscale()
gui.screenshot() # jupyter notebook上にもGUIを表示します
```
![fig3のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151117/f7b5485f-a3e4-24b1-145e-99390d9db29d.png)

この量子ビット`Q1`の形状を変更するには、Metal GUI上でも左下のOptionsの値を手動で変更することで可能ですが、以下のようにJupyter notebook上のコードでも変更できます。

```
# オプションを変える
q1.options.pos_x = '0.5 mm'
q1.options.pos_y = '0.25 mm'
q1.options.pad_height = '225 um'
q1.options.pad_width  = '250 um'
q1.options.pad_gap    = '50 um'

# オプションを変えたので、ジオメトリをUpdateする
gui.rebuild()
gui.edit_component('Q1') 
gui.autoscale()
```
![fig4のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151117/30680847-8e8b-76e1-4841-db5ffc33cd83.png)
量子ビットの位置とパッドの厚み、間隔が変更されました。

# 量子ビットにピンをつける
量子ビットQ1に a、b、c、dという名前の4つのコネクターピンを追加します。一度すべてのqcomponentsを消去した後（または、既存のcomponentの上書きを可能にした後）、オプションでピンを設定して、そのオプション付きのqcomponentオブジェクト`Q1`を作成します。

```
design.delete_all_components() # 一度全て消します。
# design.overwrite_enabled = True を上記の代わりに使っても良いです。

# オプションでピンを設定
options = dict(
    connection_pads=dict(  
        a = dict(loc_W=+1,loc_H=+1), #右上
        b = dict(loc_W=-1,loc_H=+1, pad_height='30um'), #左上
        c = dict(loc_W=+1,loc_H=-1, pad_width='200um'), #右下
        d = dict(loc_W=-1,loc_H=-1, pad_height='50um') #左下
    )
)
# オプション付きで再び量子ビットのqcomponentオブジェクトを作成
q1 = TransmonPocket(design, 'Q1', options = dict(pos_x='+0.5mm', pos_y='+0.5mm', **options))

# デザインを再構築して表示
gui.rebuild()
gui.edit_component('Q1') 
gui.autoscale()
```
![fig5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151117/df0c94fd-91e1-65d6-c501-826d1763c872.png)

これで、1つの量子ビットに4つのピンをつける方法が分かりました。次は、４量子ビットを配置して、配線し、量子チップ全体を作成します。

# 複数量子ビットをコネクタで接続する
まず、先ほどの方法でオプションを作り、そのオプションで4つのトランズモン`Q1`、`Q2`、`Q3`、`Q4`を作成します。

```
design.overwrite_enabled = True # 既存のコンポーネントの上書きを可能に

# 全てのトランズモンへのカスタムオプション
options = dict(
    pad_width = '425 um', 
    pocket_height = '650um',
    connection_pads=dict( 
        a = dict(loc_W=+1,loc_H=+1), 
        b = dict(loc_W=-1,loc_H=+1, pad_height='30um'),
        c = dict(loc_W=+1,loc_H=-1, pad_width='200um'),
        d = dict(loc_W=-1,loc_H=-1, pad_height='50um')
    )
)

# 4つのトランズモンを作成
q1 = TransmonPocket(design, 'Q1', options = dict(
    pos_x='+2.55mm', pos_y='+0.0mm', **options))
q2 = TransmonPocket(design, 'Q2', options = dict(
    pos_x='+0.0mm', pos_y='-0.9mm', orientation = '90', **options))
q3 = TransmonPocket(design, 'Q3', options = dict(
    pos_x='-2.55mm', pos_y='+0.0mm', **options))
q4 = TransmonPocket(design, 'Q4', options = dict(
    pos_x='+0.0mm', pos_y='+0.9mm', orientation = '90', **options))

# デザインを再構築
gui.rebuild()
gui.autoscale()
```
![fig6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151117/4bc1927a-7b97-554d-b972-a3762a1e7af0.png)

次に、コプレナー導波路(coplanar waveguides (CPW))で4つのトランズモンをつなぎます。`QLibrary`から基本的なCPW QComponentである`RouteMeander`というメアンダラインのクラスをインポートします。（メアンダ形状とは、導線を折り曲げてジグザグ状にした構造です。）オプションを以下のようにセットして、`Q1`と`Q2`をつないでみます。

```
from qiskit_metal.qlibrary.tlines.meandered import RouteMeander

options = Dict(
    total_length= '6mm', # 配線長
    pin_inputs=Dict(
        start_pin=Dict(
            component= 'Q1', # 量子ビット
            pin= 'd'), # ピン
        end_pin=Dict(
            component= 'Q2',
            pin= 'c')),
    lead=Dict(
        start_straight='0.1mm', # ピンからのクリアランス
        end_straight='0.1mm'),
    meander=Dict(
       asymmetry='0mm'), # 位置
    fillet = '90um' # 角を丸める
)


cpw1 = RouteMeander(design,'cpw1', options=options)
gui.rebuild()
gui.autoscale()
```
![fig7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151117/5417cb2a-912d-6c92-51b3-0cc4b0ed4775.png)
`Q1`と`Q2`がメアンダラインでつながりました。
関数を定義して、同じメアンダラインを繰り返し使って4つのトランズモン全てを接続します。

```
options = Dict(
    meander=Dict(
        lead_start='0.1mm',
        lead_end='0.1mm',
        asymmetry='0 um')
)


def connect(component_name: str, component1: str, pin1: str, component2: str, pin2: str,
            length: str,
            asymmetry='0 um', flip=False):
    """Connect two pins with a CPW."""
    myoptions = Dict(
        pin_inputs=Dict(
            start_pin=Dict(
                component=component1,
                pin=pin1),
            end_pin=Dict(
                component=component2,
                pin=pin2)),
        lead=Dict(
            start_straight='0.13mm'
        ),
        total_length=length,
    fillet = '90um')
    myoptions.update(options)
    myoptions.meander.asymmetry = asymmetry
    myoptions.meander.lead_direction_inverted = 'true' if flip else 'false'
    return RouteMeander(design, component_name, myoptions)


asym = 150
cpw1 = connect('cpw1', 'Q1', 'd', 'Q2', 'c', '6.0 mm', f'+{asym}um')
cpw2 = connect('cpw2', 'Q3', 'c', 'Q2', 'a', '6.1 mm', f'-{asym}um', flip=True)
cpw3 = connect('cpw3', 'Q3', 'a', 'Q4', 'b', '6.0 mm', f'+{asym}um')
cpw4 = connect('cpw4', 'Q1', 'b', 'Q4', 'd', '6.1 mm', f'-{asym}um', flip=True)

gui.rebuild()
gui.autoscale()
```
![fig8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151117/50a76072-b1fa-7f22-b3e6-f6dd156610d7.png)

これで4つのトランズモン間の配線までが完了しました。
今回はここまでにします。


# Metal GUIを閉じる
Metal GUIを閉じるには、直接、GUI上で「python」 -> 「Quit」などで画面を閉じるか、またはJupyter notebook上で以下のようにします。

```
gui.main_window.close()
```


<br>
<br>
参考文献：

- [Qiskit Metal TutorialsのQuick Start](https://qiskit.org/documentation/metal/tut/1-Overview/1.2-Quick-start.html)