Skip to content

Latest commit

 

History

History
315 lines (266 loc) · 10.4 KB

document .md

File metadata and controls

315 lines (266 loc) · 10.4 KB

インストール(pip)

更新が頻繁なためgithubからのインストールを推奨します。

pip install -U git+https://github.com/tytansdk/tytan

pipインストールはこちらです。

pip install -U tytan

import

コードの冒頭ですべての機能をインポートしておくことを推奨します。

from tytan import symbols, symbols_list, symbols_define, symbols_nbit, Compile, sampler, Auto_array

または

from tytan import *

量子ビットの定義(文字シンボルの定義)

基礎として、次のように文字シンボルを定義します。

x = symbols('x')
x, y, z = symbols('x y z')
q = [symbols(f'q{i}') for i in range(5)] #[q0, q1, q2, q3, q4]

また、1次元~多次元の量子ビットを一度に定義できる関数が2種類あります。

文字シンボルを配列に定義する場合、次のようにndarray配列を得ます。 第2引数は省略できません!(2024/02/18修正より)

q = symbols_list([3, 3], 'q{}_{}')
print(q)
[[q0_0 q0_1 q0_2]
 [q1_0 q1_1 q1_2]
 [q2_0 q2_1 q2_2]]

文字シンボルを個別に定義する場合、次のように実行コマンドテキスト得てからexec()で実行します。 この方法では、IDEによっては後に構文警告(文字が未定義です)が表示されることがあります。 第2引数は省略できません!(2024/02/18修正より)

command = symbols_define([3, 3], 'q{}_{}')
print(command)
exec(command)
q0_0 = symbols('q0_0')
q0_1 = symbols('q0_1')
q0_2 = symbols('q0_2')
q1_0 = symbols('q1_0')
q1_1 = symbols('q1_1')
q1_2 = symbols('q1_2')
q2_0 = symbols('q2_0')
q2_1 = symbols('q2_1')
q2_2 = symbols('q2_2')

数式の設定

各自がんばってください。

▼資料
TYTANチュートリアル
量子アニーリングのQUBOで設定可能な条件式まとめ(保存版)(外部サイト)

▼勉強会
connpass「TYTAN」アニーリング

▼コミュニティ
Discord「TYTAN」

サンプリング

数式をコンパイルしてサンプリングする手続きはほぼこのままです。Hの部分が数式。サンプリングの乱数シードは固定可。サンプリング回数(shots)はデフォルトが100なので適宜変更してください。

#コンパイル
qubo, offset = Compile(H).get_qubo()

#サンプラー選択
solver = sampler.SASampler(seed=None)

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

▼サンプラー一覧
ローカルCPUサンプラー:100量子ビット程度まで

#SAサンプラー
solver = sampler.SASampler(seed=None)
result = solver.run(qubo, shots=100)
#GAサンプラー
solver = sampler.GASampler(seed=None)
result = solver.run(qubo, shots=100)

ローカルGPUサンプラー:100-1,000量子ビット程度

#高速GPUサンプラー
solver = sampler.ArminSampler(seed=None)
result = solver.run(qubo, shots=100)
#対ワンホット高速GPUサンプラー
solver = sampler.PieckSampler(seed=None) #コンパイルも特殊なので注意
result = solver.run(qubo, shots=100)

商用クラウドサンプラー:1,000-100,000量子ビット程度 ※要詳細

ZekeSampler()
NQSSampler()

結果確認

結果はエネルギーが低い解から順にリスト形式で格納されています。「量子ビットの値」「エネルギー(コスト)値」「出現数」の順。

for r in result:
    print(r)
[{'x': 0, 'y': 1, 'z': 1}, -4.0, 27]
[{'x': 1, 'y': 0, 'z': 1}, -4.0, 23]
[{'x': 1, 'y': 1, 'z': 0}, -4.0, 50]

0, 1のみを取り出す場合は次の通りだが、シンボルがアルファベット順のためq11がq2より手前に来たりすることに注意!(後述の方法でシンボルの自然順ソートが可能)

for r in result:
    print(list(r[0].values()))
[0, 1, 1]
[1, 0, 1]
[1, 1, 0]

また、1次元~多次元の量子ビットの結果を見やすくする関数が3種類あります。いずれも結果リストから単一の結果を与えて使用します。

ndarray形式の配列に変換する方法は次のとおりです。1次元~5次元まで対応。1次元の場合でもこの関数を通すことでシンボルが自然順ソートされ、q11はq2より後に来るようになる(便利)。

arr, subs = Auto_array(result[0]).get_ndarray('q{}_{}')
print(arr)
print(subs)
[[0 0 1]
 [0 1 0]
 [1 0 0]]
[['0', '1', '2'], ['0', '1', '2']]

DataFrame形式の配列に変換する方法は次のとおりです。1次元と2次元のみ対応。

df, subs = Auto_array(result[0]).get_dframe('q{}_{}')
print(df)
   0  1  2
0  0  0  1
1  0  1  0
2  1  0  0

画像形式の配列に変換する方法は次のとおりです。2次元のみ対応。opencv形式、すなわちndarray(dtype='uint8')形式のグレースケール画像(0または255)です。

img, subs = Auto_array(result[0]).get_image('q{}_{}')

import matplotlib.pyplot as plt
plt.imshow(img)
plt.yticks(range(len(subs[0])), subs[0])
plt.xticks(range(len(subs[1])), subs[1])
plt.show()

QUBO行列を入力する方法

数式を記述する方法だけでなく、QUBO行列を入力する方法、QUBO行列をcsv読み込みする方法にも対応しています。それぞれのコンパイルまでの例です。サンプリング以降は共通です。

QUBO行列を入力する方法

import numpy as np

# QUBO行列を指定(上三角行列)
matrix = np.array([[-3, 2, 2], [0, -3, 2], [0, 0, -3]])
print(matrix)

#コンパイル
qubo, offset = Compile(matrix).get_qubo()
[[-3  2  2]
 [ 0 -3  2]
 [ 0  0 -3]]

QUBO行列をcsv読み込みする方法

import pandas as pd

# QUBO行列を読み込み(上三角行列)
# header, index名を設定すれば量子ビット名に反映される
matrix = pd.read_csv('matrix.csv', header=None)
print(matrix)

#コンパイル
qubo, offset = Compile(matrix).get_qubo()
   0  1  2
0 -3  2  2
1  0 -3  2
2  0  0 -3

N-bitの変数を扱う方法

量子ビット(文字シンボル)はそのままでは0と1しか取り得ないため、幅広く整数や小数を表現するには複数の量子ビットを使ったN-bit表現を行う。例えば8-bitを使用して0から255までの整数を表現できる。これを簡単に扱うためのsymbols_nbit()関数とAuto_array().get_nbit_value()関数が用意されている。

例えば以下の連立方程式を解く場合、x, y, zとも0~255の整数であることが既知として、それぞれ8-bit表現して解くことができる。 10x+14y+4z = 5120
9x+12y+2z = 4230
7x+5y+2z = 2360

#量子ビットをNビット表現で用意する
x = symbols_nbit(0, 256, 'x{}', num=8)
print(x)
y = symbols_nbit(0, 256, 'y{}', num=8)
z = symbols_nbit(0, 256, 'z{}', num=8)

#連立方程式の設定
H = 0
H += (10*x +14*y +4*z - 5120)**2
H += ( 9*x +12*y +2*z - 4230)**2
H += ( 7*x + 5*y +2*z - 2360)**2

#コンパイル
qubo, offset = Compile(H).get_qubo()
#サンプラー選択
solver = sampler.SASampler()
#サンプリング
result = solver.run(qubo, shots=500)

#1つ目の解をNビット表現から数値に戻して確認
print(result[0])
print('x =', Auto_array(result[0]).get_nbit_value(x))
print('y =', Auto_array(result[0]).get_nbit_value(y))
print('z =', Auto_array(result[0]).get_nbit_value(z))
128.0*x0 + 64.0*x1 + 32.0*x2 + 16.0*x3 + 8.0*x4 + 4.0*x5 + 2.0*x6 + 1.0*x7
[{'x0': 1, 'x1': 0, 'x2': 0, 'x3': 0, 'x4': 0, 'x5': 0, 'x6': 1, 'x7': 0, 'y0': 1, 'y1': 1, 'y2': 1, 'y3': 0, 'y4': 0, 'y5': 1, 'y6': 1, 'y7': 0, 'z0': 1, 'z1': 0, 'z2': 0, 'z3': 1, 'z4': 0, 'z5': 1, 'z6': 1, 'z7': 0}, -49676900.0, 2]
x = 130.0
y = 230.0
z = 150.0

商用クラウドサンプラーの使い方

blueqatサイトでアカウント登録しAPIキーを発行。NQSSamplerは結果が1種類しか返ってこないことに注意(調整中)

#サンプラー選択
solver = sampler.NQSSampler(api_key='your_key') #ここか
#サンプリング
result = solver.run(qubo, api_key='your_key') #ここでAPIキーを指定

GPUサンプラーの使い方1

これ無料って本当ですか?(商用サンプラーを出している会社から睨まれているらしい)

pytorchは別途インストールする必要があります。

#サンプラー選択
solver = sampler.ArminSampler(seed=None, mode='GPU', device='cuda:0', verbose=1)
#サンプリング
result = solver.run(qubo, shots=100, T_num=2000, show=False)

mode='GPU' CPUモードにするには'CPU'
device='cuda:0' 複数GPUを挿している場合でcuda:1以降を指定したい場合に使用。Macの'mps:0'とかもここ
verbose=1 繰り返し実行時などでモード表示を出したくなければ0に
shots=100 サンプリング数
T_num=2000 フリップ繰り返し数。温度をよりゆっくり下げたければ4000とかに増やす
show=False Trueにするとエネルギーの記録がグラフ表示される

GPUモードはshotsを増やしても計算時間があまり増えないのが特徴。shots=10000とか50000とかにできる。

Colabの場合はGPU(T4)を選ぶこと。TPUは非対応。

GPUサンプラーの使い方2

こちらもなんと無料。ArminSamplerをさらにワンホット制約に強くしたもの。PieckCompile()とセットで使う必要あり。

#コンパイル
qubo, offset = PieckCompile(H).get_qubo()
#サンプラー選択
solver = sampler.PieckSampler(seed=None, mode='GPU', device='cuda:0', verbose=1)
#サンプリング
result = solver.run(qubo, shots=100, T_num=2000, show=False)

1次元ワンホット群をもつ問題において大幅に改善される。2次元以上のワンホット群に対しては1次元分しか対応されないので改善してもなお無理が残る。何を言っているか分からないと思うが数独は3次元ワンホットなので全然ダメ。使い方はPieckSamplerで検索して出てくるブログを参照。