TYTANからAmplifyへの呼び出し

# はじめに

量子コンピュータ（アニーリング）を勉強したのですが、
数学（数式）がよくわからず、諦めかけてました。
ところが、[TYTAN](https://github.com/tytansdk/tytan_tutorial)というライブラリを発見、
ビデオ付きのチュートリアルがあり、数学（数式）が苦手な私でも簡単にアニーリングプログラムが書けます。

TYTANは、ローカルPCのCPUで量子シミュレーションしているので、
簡単に使えるのですが、複雑なことをやると、遅くなったり、正しい答えがでなくなってきます。

TYTANからクラウドサービスのAmplifyを利用してみたら、早く正しい情報がでるようになりましたので、
やり方を紹介します。

## アクセストークンの取得
Amplify AEのアクセストークンを取得しておきます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136795/49c439bb-1b24-e335-a38b-724dbc70ee38.png)

## 今回のサンプルプログラム
プログラムは、公式チュートリアルの「温度計パズル」です
ソースコードは、下記の通り、元のソースはコメントにしていて
サンプリング部分をAmplifyで行うようにしています。

```python:tutorial2.py
from tytan import *
import numpy as np

#量子ビットを用意する
q00 = symbols('q00')
q01 = symbols('q01')
q02 = symbols('q02')
q03 = symbols('q03')
q04 = symbols('q04')
q05 = symbols('q05')
q06 = symbols('q06')
q07 = symbols('q07')
q08 = symbols('q08')
q09 = symbols('q09')
q10 = symbols('q10')
q11 = symbols('q11')
q12 = symbols('q12')
q13 = symbols('q13')
q14 = symbols('q14')
q15 = symbols('q15')

#各行、「4個から指定の個数だけ1になる」
H = 0
H += (q00 + q01 + q02 + q03 - 2)**2
H += (q04 + q05 + q06 + q07 - 1)**2
H += (q08 + q09 + q10 + q11 - 3)**2
H += (q12 + q13 + q14 + q15 - 1)**2

#各列、「4個から指定の個数だけ1になる」
H += (q00 + q04 + q08 + q12 - 3)**2
H += (q01 + q05 + q09 + q13 - 1)**2
H += (q02 + q06 + q10 + q14 - 1)**2
H += (q03 + q07 + q11 + q15 - 2)**2

#各温度計、球部から降順になる
H += (1 - q08) * q04
H += (1 - q04) * q00 #8→4→0の連鎖

H += (1 - q05) * q01

H += (1 - q03) * q02

H += (1 - q07) * q06

H += (1 - q11) * q10
H += (1 - q10) * q09 #11→10→9の連鎖

H += (1 - q13) * q12

H += (1 - q15) * q14

#コンパイル
qubo, offset = Compile(H).get_qubo()
print(f'offset\n{offset}')

'''
-- ここから 下はTYTANオリジナルのコード --
#サンプラー選択
solver = sampler.SASampler()

#サンプリング
result = solver.run(qubo)

#上位5件
for r in result[:5]:
    print(r)
    print(np.array(list(r[0].values())).reshape(4, 4))

-- こまで TYTANオリジナルのコード --
-- ここから下がAmplify対応のコード --
'''
# 各量子ビットのラベルを用意する
sp = []
for i in range(16):
  sp.append("q" + format(i, '02'))

# Amplifyの形式に変換
Q = {}
for i in range(16):
  for j in range(16):
    if ((sp[i], sp[j]) in qubo):
      Q[(i, j)] = qubo[(sp[i], sp[j])]

from amplify import Solver
from amplify.client import FixstarsClient
from amplify import (BinaryPoly, BinaryQuadraticModel, Solver)

f = BinaryPoly(Q)
model0 = BinaryQuadraticModel(f)

# クライアントの設定
client = FixstarsClient()  # Fixstars Amplify AE
client.parameters.timeout = 1000  # タイムアウト1秒
client.token = ""  # ご自身のトークンを入力

# マシンを実行
solver = Solver(client)  # ソルバーに使用するクライアントを設定
result = solver.solve(model0)  # 問題を入力してマシンを実行
print(result)

for i in range(len(result)):
  r = [result[i].values[j] for j in range(16)]
  print(r)
  print(np.array(r).reshape(4, 4))
```
## 解説
TYTANでコンパイル後のQUBO行列は、下記のようにキーにラベル（文字列）を使った形式になっています。
```
{('q04', 'q05'): 2.0, ('q05', 'q13'): 2.0, ('q13', 'q13'): -2.0, ('q06', 'q10'): 2.0, ('q00', 'q04'): 1.0, ('q01', 'q01'): -3.0, ('q06', 'q07'): 1.0, ('q15', 'q15'): -4.0, ('q07', 'q07'): -4.0, ('q00', 'q03'): 2.0, ('q08', 'q10'): 2.0, ('q02', 'q10'): 2.0, ('q04', 'q04'): -5.0, ('q04', 'q07'): 2.0, ...}
```
Amplifyでは、下記のようにキーは数値を使うようなので、ラベルのテーブルを作成して変換するようなコードを入れています。
```
{(0, 0): -7.0, (0, 1): 2.0, (0, 2): 2.0, (0, 3): 2.0, (0, 4): 1.0, (0, 8): 2.0, (0, 12): 2.0, (1, 1): -3.0, (1, 3): 2.0, (1, 5): 1.0, (1, 13): 2.0, (2, 1): 2.0, (2, 2): -3.0, (2, 3): 1.0, ...}
```

また、サンプリングの結果もTYTANの場合は、ラベル（文字列）を使った形式になっていますが
```
{'q00': 1, 'q01': 0, 'q02': 0, 'q03': 1, 'q04': 1, 'q05': 0, 'q06': 0, 'q07': 0, 'q08': 1, ...}
```
Amplifyでは、数値を使っています。
```
{2: 0, 1: 0, 10: 1, 14: 0, 11: 1, 8: 1, 15: 0, 9: 0, 7: 0, 6: 0, 5: 0, 13: 1, 3: 1, 4: 1, ...}
```
以上です。