3-plus-Annealing Cloud Web (NEDOのCMOS-Annealer)

Open in Colab

ここでは 日立 の作った「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アニーリングマシンの機能にアクセスすることができます。
Annealing Cloud Web についてはここを見てください。
OpenJijではAnnealing Cloud Web の公開している Web API をラップし、OpenJijの他のサンプラー(SASamplerやSQASampler)と同じインターフェースで提供しています。

token 取得

Annealing cloud web を使うには tokenを発行する必要があります。 https://annealing-cloud.com/web-api/token-request.html ここから問い合わせれば取得できます。

OpenJij でアクセスする

では早速にコード例を示します。

まずopenjij をインストールしておきましょう

[1]:
# !pip install openjij
!pip show openjij  # openjij == 0.0.5 を仮定します
Name: openjij
Version: 0.0.5
Summary: Framework for ising model and QUBO
Home-page: https://openjij.github.io/OpenJij/
Author: Jij Inc.
Author-email: openjij@j-ij.com
License: Apache License 2.0
Location: /usr/local/miniconda3/lib/python3.6/site-packages
Requires: requests, numpy
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}]
またAnnealing Cloud Web では ASIC実装とFPGA実装を提供しています。
それらはCMOSAnnealerコンストラクタの引数の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}]