JijModeling 1.9.0 リリースノート#

インスタンスデータのランダム生成#

  • jijmodeling はプレースホルダーのランダムデータ生成をサポートするようになりました!

    • ダミーデータを使用してモデルを配布したり、小さなトイ入力に対するモデルの動作をテストするのに役立ちます。

  • 詳細は、Problem.generate_random_dataset および Problem.generate_random_instance のAPIドキュメントを参照してください。

Problem.generate_random_dataset および Problem.generate_random_instance#

  • Problem.generate_random_dataset 関数は、jm.Interpreter に入力される値の辞書を生成します。

  • Problem.generate_random_instance を使用して、Interpreter を手動で初期化することなく直接OMMXインスタンスを生成します。

概要#

ランダム生成機能を使用するには、Placeholder 宣言でいくつかの情報を指定する必要があります。 このバージョンでは、次のランダム生成関連の属性が追加されました:

  • dtype: 配列(またはスカラー)の要素の型。jm.DataType.INTEGER または jm.DataType.FLOAT のいずれかでなければなりません。

  • jagged: ジャギー配列を生成する場合は True に設定します。デフォルトは False です。

  • shape: \(n\) 次元配列またはジャギー配列を生成するには、形状を指定する必要があります。これは、次元式または None を含むタプルでなければなりません。

    • None は軸のサイズが不定であることを意味します。\(n\) 次元配列の場合、各軸は親軸に関係なくランダムで固定サイズです。ジャギー配列の場合、同じ軸が親軸ごとに異なるサイズを持つことができます。

dtype のみが指定されている場合、プレースホルダーは他の場合と同様にスカラー値と見なされます。

Problem.generate_random_* は次のキーワード引数を取ります:

  • seed (オプション): ランダムデータ生成のためのシード。省略された場合、環境エントロピーからサンプルを取得します。

  • options (オプション): 各プレースホルダーの値と軸サイズの範囲。

  • default (オプション): options 引数に存在しないプレースホルダーのデフォルト範囲オプション。

options および default には範囲オブジェクトを指定します。具体的な構文は APIリファレンスの「範囲パラメータと範囲構文」セクション に記載されています。 要するに、範囲オブジェクトは次のフィールドで構成されます:

  • value: プレースホルダーの値の範囲。(デフォルト: 閉区間 \([-1, 1]\) から一様にサンプル)

  • size: プレースホルダーの各軸のサイズの範囲 - スカラープレースホルダーの場合は無視されます。(デフォルト: 閉区間 \([1, 5] \cap \mathbb{N}\) から一様にサンプル)

jijmodeling.rangejijmodeling.range.valuejijmodeling.range.size モジュールおよび組み込みの range(N, M) 関数を size 範囲に使用できます。

#

import jijmodeling as jm

v = jm.Placeholder("v", dtype=jm.DataType.INTEGER, shape=[None])
N = v.len_at(0, latex="n")
w = jm.Placeholder("w", dtype=jm.DataType.FLOAT, shape=[N])
C = jm.Placeholder("C", dtype=jm.DataType.FLOAT)
x = jm.BinaryVar("x", shape=[N])
i = jm.Element("i", belong_to=N)

problem = jm.Problem("MyProblem", sense=jm.ProblemSense.MAXIMIZE)
problem += jm.sum(i, v[i] * x[i])
problem += jm.Constraint("capacity", jm.sum(i, w[i] * x[i]) <= C)

problem
\[\begin{split}\begin{array}{cccc}\text{Problem:} & \text{MyProblem} & & \\& & \max \quad \displaystyle \sum_{i = 0}^{n - 1} v_{i} \cdot x_{i} & \\\text{{s.t.}} & & & \\ & \text{capacity} & \displaystyle \sum_{i = 0}^{n - 1} w_{i} \cdot x_{i} \leq C & \\\text{{where}} & & & \\& x & 1\text{-dim binary variable}\\\end{array}\end{split}\]
# 生成されたデータの辞書を取得
data_set = problem.generate_random_dataset(
    seed=42,
    # Default Options.
    default={
        "value": jm.range.open_closed(5, 15),  # 値を 5 < x <= 15 からサンプル
    },
    # プレースホルダー固有のオプション。
    options={
        "v": {
            "value": range(1000, 10000),
            "size": range(2, 10),  # 各軸の長さは 2 <= n < 10
        }
    },
)
data_set
{'C': 12.697394604342424,
 'v': array([4410., 7120.]),
 'w': array([14.24692945, 14.91803914])}
config = {
    "seed": 42,
    # デフォルトオプション。
    "default": {
        "value": jm.range.open_closed(5, 15),  # Samples values 5 < x <= 15
    },
    # プレースホルダー固有のオプション。
    "options": {
        "v": {
            "value": range(1000, 10000),
            "size": range(2, 10),  # 各軸の長さは 2 <= n < 10
        }
    },
}

# `generate_random_instance` は generate_random_dataset と `Interpreter.eval_problem` のラッパーです。
instance = problem.generate_random_instance(**config)
assert instance == jm.Interpreter(data_set).eval_problem(problem)
# $n$ 次元配列 vs ジャギー配列。

N = jm.Placeholder("N", dtype=jm.DataType.INTEGER)

# `jagged` が指定されていない(または `False` に設定されている)場合、生成されたデータは $n$ 次元配列になります。
ND = jm.Placeholder("ND", dtype=jm.DataType.FLOAT, shape=[N, None])

# `jagged` が `True` に設定されている場合、生成されたデータはジャギー配列になります。
JD = jm.Placeholder("JD", dtype=jm.DataType.FLOAT, shape=[N, None], jagged=True)

W = jm.BinaryVar("W", shape=[N])

# ND と JD はどちらも ndim 3 ですが、`None` の意味が異なります。

# ダミー問題を作成

problem = jm.Problem("MyProblem2")
problem += jm.sum(i, ND[i, 0] * JD[i, 0] * W[i])
data_set = problem.generate_random_dataset(
    seed=42, default={"size": range(2, 5)}, options={"N": {"value": range(2, 7)}}
)
data_set["ND"]
array([[ 0.53947892,  0.43851716,  0.70001689,  0.52274876],
       [ 0.16669862,  0.36490574, -0.41864448,  0.6020486 ],
       [-0.35717673,  0.42229989,  0.75553446,  0.23352309],
       [ 0.70278017,  0.41508094,  0.41565856, -0.81427987],
       [-0.64195438, -0.12760731,  0.20402936, -0.37202221],
       [-0.02161649, -0.20201642,  0.57824385,  0.27011351]])
jd = data_set["JD"]
assert type(jd) is jm.JaggedArray
jd.dim
2
[[jd.get([i, j]) for j in range(jd.size_at([i]))] for i in range(jd.size_at([]))]
[[-0.1714581841203171, 0.24546263509057642],
 [0.8895181708443225,
  0.6284068548505282,
  0.4939994897028317,
  0.5691758844274046],
 [-0.06250375011588982, 0.9441797579257241],
 [0.4013438463266694, 0.6071495573420029, 0.6363935389166482],
 [-0.748701159594753,
  0.12996558406728909,
  0.10849819327046317,
  0.7144708283472143],
 [0.03940420021641833,
  -0.3650379384649609,
  -0.6156945696387757,
  0.2877456030741059]]