3-Plus-Annealing Cloud Web (NEDOのCMOS-Annealer)¶
ここでは 日立 の作った「CMOSアニーリングマシン」をWeb APIで提供している NEDO の Annealing Cloud Web へ OpenJijを通して接続して CMOS アニーラを使ってみます。
OpenJijによるサポートは接続先のAnnealing Cloud Web自体の永続性を保証するものではなく、予告なくサービス終了や内容の変更が生じる可能性があります。 このノートブックは 2019/4/26 に作成されました。またAnnealing Cloud Webの提供しているWeb APIは日立CMOSアニーリングマシン全体をサポートする標準的な仕様というわけではなく、実装例です。OpenJijではAnnealing Cloud WebのWeb APIで提供しているCMOSアニーリングマシンの機能にアクセスすることができます。
token 取得¶
Annealing cloud web を使うには tokenを発行する必要があります。 https://annealing-cloud.com/web-api/token-request.html ここから問い合わせれば取得できます。
OpenJij でアクセスする¶
では早速にコード例を示します。
まずopenjij をインストールしておきましょう
[2]:
#!pip install openjij
!pip show openjij
Name: openjij
Version: 0.1.0
Summary: Framework for the Ising model and QUBO
Home-page: https://openjij.github.io/OpenJij/
Author: Jij Inc.
Author-email: [email protected]
License: Apache License 2.0
Location: /home/jiko/.local/lib/python3.8/site-packages
Requires: scipy, requests, jij-cimod, numpy, dimod
Required-by:
[3]:
import openjij as oj
以下のようにSASampler
などを使う時と同じく CMOSAnnealer というコンストラクタで インスタンスを生成して sample_ising で解をサンプリングできます。ここでtoken には Annealing cloud web で取得した token を使ってください。
[4]:
cmos = oj.CMOSAnnealer(token="", iteration=5)
h = {0: 1}
J = {(0, 1): -1, (1, 2): -1}
response = cmos.sample_ising(h, J)
[{index: s for index, s in zip(response.indices, state)} for state in response.states]
[4]:
[{0: -1, 1: -1, 2: -1},
{0: -1, 1: -1, 2: -1},
{0: -1, 1: -1, 2: -1},
{0: -1, 1: -1, 2: -1},
{0: -1, 1: -1, 2: -1}]
machine_type
で指定します。 デフォルトはASICです。FPGAとASICで扱えるパラメータ(問題サイズや相互作用の大きさの範囲)が違うことに注意してください。(詳細 : https://annealing-cloud.com/web-api/reference/v2.html)
[13]:
cmos = oj.CMOSAnnealer(token="", iteration=5, machine_type="FPGA")
h = {0: 1}
J = {(0, 1): -1, (1, 2): -1}
response = cmos.sample_ising(h, J)
[{index: s for index, s in zip(response.indices, state)} for state in response.states]
[13]:
[{0: -1, 1: -1, 2: -1},
{0: -1, 1: -1, 2: -1},
{0: -1, 1: -1, 2: -1},
{0: -1, 1: -1, 2: -1},
{0: -1, 1: -1, 2: -1}]
相互作用とキンググラフ¶
他のSamplerと同じ 辞書型で渡す¶
上記のようにイジングの h と J を辞書型で渡すことができます。添字はCMOSアニーリングマシンの持つキンググラフ(こちらを参照)の2次元格子(x, y)を左上から横に順番に番号をつけていった1次元添字(index)に対応させてください。
2次元格子(キンググラフ上の座標)
x軸 : 0 -> Lx
y軸 : 0 -> Ly
1次元の添字
index = x + Ly * y
例えば FPGA 実装であれば 2次元格子のx軸方向の範囲は 0-79 なので、{(0, 80): -1} という相互作用を渡せば、0番目のスピンとキンググラフ上で真下のスピンに -1 の結合ができます。
[18]:
cmos_fpga = oj.CMOSAnnealer(token="", machine_type="FPGA")
response = cmos_fpga.sample_ising(h={}, J={(0, 80):-1})
[{index: s for index, s in zip(response.indices, state)} for state in response.states]
[18]:
[{0: 1, 80: 1}]
ASIC 上ではx軸方向の大きさが違うので (0, 80) の組み合わせは同じ行のスピンをしてしていることになり、キンググラフ上でつながっていないのでエラーになります。
以下のコードは繋がっていない変数同士を相互作用させようとしているので ValueError です。
[7]:
cmos_fpga = oj.CMOSAnnealer(token="", machine_type="ASIC")
response = cmos_fpga.sample_ising(h={}, J={(0, 80):-1}) # ValueError !!
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-7-6af0b52239d5> in <module>
1 cmos_fpga = oj.CMOSAnnealer(token="4217cf4d6928cfe72921e266ee3b655c", machine_type="ASIC")
----> 2 response = cmos_fpga.sample_ising(h={}, J={(0, 80):-1}) # ValueError !!
/usr/local/miniconda3/lib/python3.6/site-packages/openjij/sampler/cmos_annealer.py in sample_ising(self, h, J, king_graph)
41 return self._sampling(_king_graph, spin_type=spin_type, token=self.token)
42 elif (h is not None) and (J is not None):
---> 43 _king_graph = KingGraph(machine_type=self.machine_type, h=h, J=J, spin_type=spin_type)
44 return self._sampling(_king_graph, spin_type=spin_type, token=self.token)
45 else:
/usr/local/miniconda3/lib/python3.6/site-packages/openjij/model/king_graph.py in __init__(self, machine_type, h, J, Q, king_graph, spin_type)
86 self._ising_king_graph.append([x1, y1, x2, y2, ising_int[i][j]])
87
---> 88 self._validation_ising_king_graph()
89
90 def _convert_to_BQM_format(self, king_graph, spin_type):
/usr/local/miniconda3/lib/python3.6/site-packages/openjij/model/king_graph.py in _validation_ising_king_graph(self)
127 if not (xi in [xj, xj-1, xj+1]) or not (yi in [yj, yj-1, yj+1]):
128 raise ValueError('Graph is incomplete xi: {}, yi: {}, xj: {}, yj: {}, p:{}'
--> 129 .format(xi, yi, xj, yj, p))
130 if not (self.prange[0] <= p <= self.prange[1]):
131 raise ValueError('Graph is incomplete xi: {}, yi: {}, xj: {}, yj: {}, p: {}'
ValueError: Graph is incomplete xi: 0, yi: 0, xj: 80, yj: 0, p:-1
キンググラフ上の2次元座標で相互作用を渡す¶
また入力はAnnealing Cloud Web の入力フォーマットでも行えます。その際は king_graph という引数に渡してください。
Annealing Cloud Webの入力フォーマットは2次元格子の座標を指定します。
Linear term : [x1, y1, x1, y1, value]
Quadratic term : [x1, y1, x2, y2, value]
[15]:
cmos = oj.CMOSAnnealer(token="", iteration=5, machine_type="FPGA")
king_graph = [[0, 0, 0, 0, 1], [0, 0, 1, 0, -1],[1, 0, 2, 0, -1]]
# ↑は
# h = {0: 1}
# J = {(0, 1): -1, (1, 2): -1}
# とおなじ
response = cmos.sample_ising(king_graph = king_graph)
[{index: s for index, s in zip(response.indices, state)} for state in response.states]
[15]:
[{0: -1, 1: -1, 2: -1},
{0: -1, 1: -1, 2: -1},
{0: -1, 1: -1, 2: -1},
{0: -1, 1: -1, 2: -1},
{0: -1, 1: -1, 2: -1}]
QUBOを解く¶
実用的には 0, 1 変数で解きたいことが多いです。その時は他のSamplerと同じく sample_qubo を使えば良いです。
[9]:
cmos_fpga = oj.CMOSAnnealer(token="", machine_type="FPGA")
response = cmos_fpga.sample_qubo(Q={(0, 80):-4})
[{index: s for index, s in zip(response.indices, state)} for state in response.states]
[9]:
[{0: 1, 80: 1}]