OpenJij core interface入門#
この章ではOpenJijのcore interface (core python interface)の使い方を説明します。
core interfaceは前回までのチュートリアルよりも下部のレイヤーのAPIです。対象読者としては前回までのOpenJijチュートリアルを一通り終えて、イジングモデルやモンテカルロ法などの用語を知っている方を想定しています。具体的には
最適化問題だけでなくサンプリングや研究用途など、より専門的な用途にOpenJijを用いたい
アニーリングスケジュールの設定や、使用するアルゴリズム等を直接触りたい
といった目的に利用できます。
OpenJij core interface について#
前回までのチュートリアルを通して、OpenJijを用いた様々な問題の解き方やベンチマークの取り方などを紹介してきました。 OpenJijは最下層の部分は統計物理学の数値計算手法である、マルコフ連鎖モンテカルロ法(MCMC)をベースにC++を用いて実装されています。 今まで触れてきたPythonモジュールはこのC++インターフェースを直接ラップしたpythonライブラリであるopenjij.cxxjijを呼び出す形となっています。図にすると次のような包含関係があります。
{width=80%}
OpenJij core interfaceを用いることでOpenJij上の全ての機能を使用することができます。よって最適化問題のみならず、統計物理学の数値計算ツールとして研究用途で使用することもできます。また、C++インターフェースを用いることで、より高速な演算を行うことができます。
本チュートリアルではより使いやすいPythonインターフェースのopenjij.cxxjijを紹介します。 インストールにはpipを使用します。
!pip install openjij
!pip show openjij
Requirement already satisfied: openjij in /opt/conda/lib/python3.9/site-packages (0.5.33)
Requirement already satisfied: dimod<0.12.0 in /opt/conda/lib/python3.9/site-packages (from openjij) (0.10.17)
Requirement already satisfied: requests<2.29.0,>=2.28.0 in /opt/conda/lib/python3.9/site-packages (from openjij) (2.28.1)
Requirement already satisfied: scipy<1.10.0,>=1.7.3 in /opt/conda/lib/python3.9/site-packages (from openjij) (1.8.1)
Requirement already satisfied: jij-cimod<1.5.0,>=1.4.6 in /opt/conda/lib/python3.9/site-packages (from openjij) (1.4.36)
Requirement already satisfied: numpy<1.24.0,>=1.17.3 in /opt/conda/lib/python3.9/site-packages (from openjij) (1.23.2)
Requirement already satisfied: pyparsing<3.0.0,>=2.4.7 in /opt/conda/lib/python3.9/site-packages (from dimod<0.12.0->openjij) (2.4.7)
Requirement already satisfied: idna<4,>=2.5 in /opt/conda/lib/python3.9/site-packages (from requests<2.29.0,>=2.28.0->openjij) (3.3)
Requirement already satisfied: urllib3<1.27,>=1.21.1 in /opt/conda/lib/python3.9/site-packages (from requests<2.29.0,>=2.28.0->openjij) (1.26.12)
Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.9/site-packages (from requests<2.29.0,>=2.28.0->openjij) (2022.6.15)
Requirement already satisfied: charset-normalizer<3,>=2 in /opt/conda/lib/python3.9/site-packages (from requests<2.29.0,>=2.28.0->openjij) (2.1.1)
Name: openjij
Version: 0.5.33
Summary: Framework for the Ising model and QUBO.
Home-page: https://www.openjij.org
Author: Jij Inc.
Author-email: [email protected]
License: Apache License 2.0
Location: /opt/conda/lib/python3.9/site-packages
Requires: dimod, jij-cimod, numpy, requests, scipy
Required-by: jijbench, jijmodeling, jijzept
OpenJij core interfaceの概要#
まずは、OpenJij core interfaceの使い方を見るために、 変数のサイズが\(N=5\)の古典スピン (\(\sigma = \pm 1\))イジング問題をSimulated Annealingで解いてみましょう。 ハミルトニアンは以下のようになります。 \begin{align*} H &= \sum_{i<j}J_{ij}\sigma_i \sigma_j + \sum_{i=1}^{N}h_i \sigma_i \ \sigma_i &= \pm 1 (i=1 \cdots N) \end{align*}
縦磁場と相互作用が
\begin{align*} h_i = -1 \ \mathrm{for\ } \forall i,\ J_{ij} = -1 \ \mathrm{for\ } \forall i,\ j \end{align*}
の場合、各スピンは1の値をとった方がエネルギーが低くなるため、\(\{\sigma_i\} = \{1,1,1,1,1\}\)が最適解となります。この問題を解いてみましょう。 Pythonコードを用いた一通りの流れは次のようになります。
core interfaceはイジング問題に特化したソルバです。このためQUBOとの変換は実装されていません。QUBOとの変換を行うには今までのチュートリアルを参照し、core interfaceを呼ぶ前にQUBOからイジング問題へ変換してください。
# core interfaceではopenjijの代わりにcxxjijをインポートします。
import openjij.cxxjij as cj
# まず相互作用行列を作成してあげます。Graphモジュールを使います。
import openjij.cxxjij.graph as G
# 問題サイズN=5の密結合グラフ(Dense)を定義します。
N = 5
J = G.Dense(N)
# 相互作用を設定してあげます。
for i in range(N):
for j in range(N):
#J[i,i]以外に-1を入力
J[i,j] = 0 if i == j else -1.0
# 縦磁場を設定してあげます。
for i in range(N):
# J[i,i] = -1でも同じ結果となります。
J[i] = -1
# 続いてGraphから計算を行うためのSystemを作成します。
import openjij.cxxjij.system as S
# 今回は通常の古典モンテカルロ計算のシステムを使用します。
system = S.make_classical_ising(J.gen_spin(), J)
# アニーリングスケジュールを設定します。Utilityモジュールを使用します。
import openjij.cxxjij.utility as U
schedule = U.make_classical_schedule_list(0.1, 100, 10, 10)
# 実際にアニーリングを走らせます。Algorithmモジュールを使用します。
# モンテカルロステップの更新方法として単純なSingleSpinFlipを用います。
import openjij.cxxjij.algorithm as A
A.Algorithm_SingleSpinFlip_run(system, schedule)
# 結果を取得しまAす。Resultモジュールにあるget_solutionを用います。
import openjij.cxxjij.result as R
print("The solution is {}.".format(R.get_solution(system)))
The solution is [1, 1, 1, 1, 1].
出てきた答えが\([1,1,1,1,1]\)であることが確認できます。低レイヤーのAPIのため設定する項目は多いですが、その分詳細な設定が可能となります。
モジュール一覧#
コード例に出てきたように、OpenJij core interfaceでは主にgraph, system, algorithmなどのモジュールから構成されています。それぞれのモジュールを組み合わせることで様々な種類、アルゴリズムでイジングモデルを計算することが可能となります。また新たにアルゴリズムを実装する際に拡張が容易であるという特徴を備えています。次章以降で詳細な説明を行います。
Graph#
イジングハミルトニアンの係数\(J_{ij}\)を保持するためのモジュールです。基本的に密結合 (全てのJijが0以外の値を持つモデルに適している)を扱うDenseと疎結合 (Jijの多くの値が0であるモデルに適している)Sparseなどがあります。
System#
systemでは、モンテカルロ等の計算における現在のシステムの状態を保持するためのデータ構造が定義されています。具体的には
古典イジングモデル (スピン配列)
横磁場イジングモデル (トロッター分解も含んだスピン配列)
GPU実装古典、量子イジングモデル
等が定義されています。モンテカルロ法を始めとする計算手法には様々な手法があります(もしくは今後新しい手法が開発されていくことでしょう)。そのため、OpenJijでは各々の計算手法に対応するデータ構造とアルゴリズム、そして計算結果の取得インターフェースを分離することにより、様々なアルゴリズムを追加することが容易に行えるように設計されています。
Updater#
どのような手法でsystemを更新していくかを定義します。具体的には
SingleSpinFlip Update
SwendsenWang Update
などの手法が実装されています。Systemの種類によって使用できるUpdaterは決まっています。 具体的に、どのようなUpdaterがどのSystemで使えるかは、これ以降のチュートリアルで具体的に見ていきます。
core python interfaceでは
algorithmに統合されています。
Algorithm#
updaterを用いてどのようなスケジュールでアニーリングアルゴリズムを実行するかなど、アルゴリズムを実行する役割を担います。
Algorithm_[Updaterの種類]_runで、対応したUpdaterを用いて実行することができます。
Result#
systemからスピン配位などの情報を得るために使用されます。
コーディングフロー#
コーディングの流れは基本的には以下に示すようなものとなります。問題の規模が大きくなってもこの流れは変わりません。
graphモジュールで\(J_{ij}, h_{i}\)を定義graphモジュールを元にsystemの作成systemに対応するupdaterを選択し、Algorithm_[Updaterの種類]_runでアルゴリズムの実行result.get_solution(system)でシステムのスピン配位を取得、もしくはsystemから直に取得