JijModeling における変数#

本章では、JijModeling において現れる二種類の変数、決定変数プレースホルダーについて、それぞれの概念的な説明を行います。

JijModelingにおける「変数」とは#

JijModeling では、大きく分けて二種類の変数が存在します。 一つは数理モデルの重要な構成要素の一つである決定変数であり、ソルバーにより値が決定される意思決定のための変数です。 これに加え、JijModeling ではインスタンスへのコンパイル時にインスタンスデータの値が代入されるプレースホルダーと呼ばれる種類の変数が存在します。 後者のプレースホルダーの概念は、入力データと数理モデルの定義を分離している JijModeling 特有の概念であり、これによって型検査による誤りの検出や制約検出、簡潔な\(\LaTeX\)出力などの機能が実現されています。

コンパイル時にインスタンスデータが代入されるのが Placeholder、コンパイル後も残りソルバーによって決定されるのが決定変数

図 4 プレースホルダーと決定変数#

図4に両者の簡単な例を示しました。 \(N\)\(d\)はコンパイル時にインスタンスデータが代入されるパラメータ、つまりプレースホルダーであり、インスタンスでは具体的な値に置き換えられています。 一方、各\(x_i\)たちはソルバーによって値が決定される決定変数であり、インスタンスにおいても残りつづけています。 この例では、\(x_n\)たちはプレースホルダー\(N\)の要素\(n\)によって添え字づけられており、数理モデルの段階では長さは不定になっています。 しかし、コンパイル時に具体的な\(N\)の値は確定し、この例では\(3\)個の独立した決定変数へと展開されています。

また、プレースホルダーの変種として、JijModeling にはカテゴリーラベルという種類の変数も存在します。 カテゴリーラベルは、「辞書のキーとして使うことができ、具体的な値の候補はコンパイル時に与えられるラベルの集合」に相当します。 個別のカテゴリーラベルは、互いの等値性の比較(== / !=)以外に何の構造ももたないものとして扱われ、コンパイル時に文字列または整数値の集合をインスタンスデータの一部として与えることで初めて実体化されます。

カテゴリーラベルとプレースホルダーの違い

インスタンスデータの一部で与えるという点で、カテゴリーラベルはプレースホルダーに似ていますが、厳密にはプレースホルダーとは異なる概念です。 各カテゴリーラベルはプレースホルダーとして使える値の種類を新たに追加するための機能であり、ある意味で Python などの言語でユーザーが新たに定義したクラスや型に相当するものだからです。

カテゴリーラベルの使いどころ

以下のような場合、添え字にカテゴリーラベルを使うとよいでしょう:

  1. 添え字の間の順序関係が本質的でない場合

  2. 添え字上の数値演算が必要でない場合

  3. 文字列の名前など、人間にとってわかりやすい名前を割り当てたい場合

ヒント

続く章では構成の都合上プレースホルダー→決定変数の順に説明を行いますが、変数間の依存関係さえ守られていれば定義する順番に特に制限はありません。

変数の配列と辞書#

JijModeling の変数は、単独の(一個だけの)変数として定義することも、配列や辞書の形で複数の変数をまとめて定義することもできます。 複数の変数をまとめて定義する方法は、総和記号などを含む一般の数理モデルの定式化の際に必要になります。 たとえば、クイックスタートの各章(SCIP版OpenJij版)でも採り上げた典型的なナップサック問題を考えてみましょう。

\[ \begin{alignedat}{2} \max &&\quad& \sum_{i = 0}^{N - 1} v_i x_i\\ \text{s.t.} &&& \sum_{i = 0}^{N - 1} w_i x_i \leq W,\\ &&& x_i \in \{0, 1\} \end{alignedat} \]

それぞれ価値\(v_i \in \mathbb{R}\)、重さ\(w_i \in \mathbb{R}\)\(N\)個のアイテムを、ナップサックの容量\(W\)を越えない範囲で価値を最大化するように詰める問題です。 ここで、アイテムの個数\(N\)は入力されるインスタンスデータによって変更できることが望ましく、したがって \(v_0 x_0 + v_1 x_1 + v_2 x_2\) のような固定された項数の和ではなく、範囲がプレースホルダー\(N\)に依存した総和\(\sum\)の形で表現できると嬉しいです。 こういった「入力するインスタンスデータによって項数の変わりうる変数一式」を表現するのに使われるのが添え字つき変数です。

JijModeling では、決定変数やプレースホルダーについて、以下の二種類のコレクションを定義することができます:

  1. 変数の配列\(0\) から連続的にインデックスがついた配列。Numpy の ndarray のような多次元配列にも対応。

  2. 変数の辞書。整数や文字列、あるいはカテゴリーラベルのタプルをキーとする離散的な辞書(連想配列)。

これらには専用の構築子も用意されていますが、多くはこの後扱う単独変数の構築子にキーワード引数を追加することで宣言することができます。

配列と辞書の使い分け

配列と辞書はそれぞれかわりに使うこともできますが、以下のような基準で使い分けると良いでしょう。

  • 配列を使うとよい場面

    1. 添え字が\(0\)から始まり、密に連続して並んでいる場合

    2. 巡回順など添え字の順番に時間的・空間的な意味がある場合

  • 辞書を使うとよい場面

    1. 添え字が\(0\)から開始するとは限らなかったり、部分的にしか定義されていない場合

    2. 添え字に自然数ではなく、文字列などで特別な意味を持たせたい場合

    3. 添え字の並び順に特に意味がない場合

以下、配列と辞書のそれぞれについて、変数の宣言に関わる部分についてのみ簡単に概要を述べます。 より一般の事項や演算については 式の構築 を参照してください。

配列の概要#

JijModeling では、変数から成るものに限らず一次元やより多次元の配列を扱うことができます。また、実は単なるスカラーも内部的にはゼロ次元の配列として扱われています。 JijModeling では、配列の各軸の長さについては入力されたプレースホルダーの値に依存することができますが、次元(成分数)自体はゼロを含む自然数の定数リテラルである必要があります。

配列型の表記

JijModeling の配列型は、次元とその要素の型をセミコロン ; で区切って表現されます:

テキスト表記

LaTeX表記

意味

1次元整数配列

Array[N; int]

\(\mathrm{Array}[N; \mathbb{Z}]\)

長さ \(N\) の整数配列

2次元実数配列

Array[N, M; float]

\(\mathrm{Array}[N \times M; \mathbb{R}]\)

\(N \times M\) の実数行列

辞書の概要#

JijModeling では、配列に加えて変数の辞書(または連想配列)を宣言することができます。 配列がゼロから始まる連続的な添え字を持つ構造の記述に有効であったのに対し、辞書は疎であったり部分的にしか定義されていない添え字や、あるいは自然数以外の値を添え字を表現するのに使われます。

JijModeling の辞書には、辞書の「定義域」に関する制約により PartialDictTotalDict という二種類が存在します:

辞書の種類

数式

説明

PartialDict[K; V]

\(\mathrm{PartialDict}[K; V]\)

K の値をキーとし、各キーに型 V の値が割り当てられた辞書。キーの集合は K の部分集合でよい。

TotalDict[K; V]

\(\mathrm{TotalDict}[K; V]\)

K全てのあり得る値に対して、それに対応する V 型の値が全域で割り当てられた辞書。PartialDictと違い、辞書は型 K 全域で定義されている必要がある

これを踏まえて、辞書のキーとして使うことができる型を見ていきましょう。基本的には、以下の四種類のみです:

  1. 整数(決定変数を含まない)

  2. 文字列

  3. カテゴリーラベル

  4. 各成分が(1)から(3)のいずれかから成るタプル

加えて、TotalDict は全ての値が列挙されているような型 K に対してのみ使える必要があるため、ある意味で「有界」な範囲が定まっているもののみとなります。 具体的には、各辞書では以下の表に示すようなキーを使うことができます。

整数

文字列

カテゴリーラベル

タプル

PartialDict

左から成るものなら何でも

TotalDict

決定変数を含まない自然数 \(n\) 未満の自然数全体 \(\mathbb{N}_{<n}\)

予め指定された(一意な)文字列のリスト

左から成るものなら何でも

ここで、「○」は「この型として振る舞うものであれば何でもキー型として指定できる」という意味です。 以上は変数の辞書以外の一般の辞書にも適用される一般的な条件です。

決定変数を定義する際の注意

決定変数もプレースホルダーもほぼ同じような方法で配列・辞書を定義することができますが、一点重要な違いがあります。

それは、決定変数はソルバーによって値が決定されるという性質上、コンパイル後のインスタンスにおいて決定変数の個数が完全に確定している必要があるという点です。 言い方を変えれば、プレースホルダーの値によってインスタンスに含まれる決定変数の個数が完全に決まる必要があるということです。 この要請は、たとえばプレースホルダーとして与えられる配列は次元のみの指定だけでよかったり、辞書も部分的にしか定義されていない場合も許容するのに対し、決定変数の配列・辞書はそれぞれシェイプとキーの集合が(他のプレースホルダーへの参照を含みつつ)完全に指定されている必要がある、という違いに現れています。

式としての変数#

JijModeling では、宣言された変数はそのメタデータを保存するオブジェクトとして宣言されますが、同時にとしても振る舞います。 特に、他の式の構成要素の一部として現れた場合、変数オブジェクトは自動的にその名前の変数を参照する式に自動的に変換されます。 変数が式中に現れた場合、単独の変数の場合は対応する型の式に、添え字つきの変数の場合は表現に応じて変数から成る配列や辞書の式として振る舞います。

それでは、次章から、プレースホルダーと決定変数のそれぞれについて、単独や添え字つきでの宣言方法について見ていきましょう。