JijModelingでの定式化
この記事ではJijModelingでの定式化のTipsを紹介します。
変数のdimとshapeについて
JijModelingでPlaceholder, Binaryを利用する際にdimまたはshapeという引数を使用しますが、これらの使い方について説明します。
dimは変数が持つことができる添字の数を表します。例えば
d = jm.Placeholder("d", dim=2)
と書くとdという名前の2次元配列のPlaceholderを生成できます。このdは2つまで添字を持つことができます。そのため以下のような振る舞いをします。
# 2つまで添字を持つことができるので以下の記述は可能です.
d["i"]
d["i", "j"]
# しかしdim=2なので, 3つの添字を入れようとするとエラーになります.
d["i", "j", "k"]
shapeは変数の大きさを直接指定することができます。
n = jm.Placeholder("n")
d = jm.Placeholder("d", shape=(n, 5))
このdはさきほどdim=2と指定した時と同じように2次元配列ですが、大きさが決まっています。
dim=2はshapeが未定だが添字の数は決まっているということを意味するので、実は
d = jm.Placeholder("d", dim=2)
d = jm.Placeholder("d", shape=(None, None))
はどちらも同じ意味を持ちます。
shape と dimの使い分け
ではshapeとdimはどのように使い分けるのが良いでしょうか。
二つの例を見てみましょう。
import jijmodeling as jm
n = jm.Placeholder("n")
d = jm.Placeholder("d", shape=(n, ))
import jijmodeling as jm
d = jm.Placeholder("d", dim=1)
n = d.shape[0]
この例は同じ実装に見えますが、前者は数式を評価する際にデータとしてnとdの両方が必要となります。
しかし後者はdのみをデータとして与えればよく、nはdの大きさから推定されます。
!!! note
先程 dim はshapeをNoneにした時と同じ意味を持つと説明しましたが、.shapeインターフェースでshapeの値を取り出す際にNoneの場合は自動的にdの大きさに対応するPlaceholderが出力されます。
つまりn = d.shape[0]のnは実際のdに代入されるデータの大きさと紐づいています。
ここで紹介した例の前者だとnとdの両方のデータを入れる必要があり、この関係に矛盾が合った場合、数式の評価時(コンパイルのときなど)にしか間違いに気づけず、思わぬところでエラーが発生します。
そのため後者のようにdimを使った実装の方がより安全です。
次にshapeを使った方が良い例を見てみましょう。
2つのPlaceholderを作ることを考えます。
import jijmodeling as jm
d = jm.Placeholder("d", dim=1)
C = jm.Placeholder("C", dim=1)
import jijmodeling as jm
d = jm.Placeholder("d", dim=1)
n = d.shape[0]
C = jm.Placeholder("C", shape=(n, ))
これら二つも同じように見えますが、前者は変数dとCの長さに関係はありません。
しかし後者はdはdimで1次元配列であることを表していますが、nとしてdの長さを取得し、Cはnつまりdと同じ長さであることを表しています。
このように各変数間の大きさに依存関係がある場合はshapeを使って陽に依存関係がわかるようにすることをおすすめします。