JijModeling 2.10.0 リリースノート#
機能強化#
ランダムインスタンス生成でカテゴリーラベルの要素を直接リストで指定できるように#
これまではランダムインスタンス生成でカテゴリーラベルの値を固定する場合、 {"C": {"keys": ["A", "B", "C"]}} のように keys として指定する必要がありましたが、リストで直接指定できるようになりました。
import jijmodeling as jm
@jm.Problem.define("problem")
def problem(problem: jm.DecoratedProblem):
C = problem.CategoryLabel()
a = problem.Float(dict_keys=C)
x = problem.BinaryVar(dict_keys=C)
problem += (a * x).sum()
problem.generate_random_dataset(
seed=42,
options={"C": ["A", "B", "C"]} # {"C": {"keys": [...]}} と同値
)
{'a': {'A': -4.161370289401178,
'B': -1.210197493373315,
'C': 1.800434110281392},
'C': ['A', 'B', 'C']}
リストが利用できるのはカテゴリーラベルのみであり、他のプレースホルダーなどについてはこれまで通りの形式で指定する必要があります。
\(\LaTeX\) 表示のカスタマイズ#
latex パラメータに加えて、 element_latex と subscript_styles という、\(\LaTeX\) の表示をカスタマイズできる引数を Placeholder、DecisionVar、NamedExpr、CategoryLabel のコンストラクタに追加しました。
element_latex は、そのオブジェクトを範囲とする添字に共通の名前を設定します。
自動的に割り当てられる名前(i、j など)のかわりにこの名前が使われます。
なお、lambda 式や for 句でユーザーが書いた名前が、この名前で上書きされることになるのでご注意ください。
problem = jm.Problem("problem")
N = problem.Natural("N", element_latex="n")
c = problem.Float("c", shape=N)
x = problem.BinaryVar("x", shape=N)
problem += jm.sum(c * x)
problem += c.map(lambda v: v * 2).sum()
problem
タプル集合などの場合は、element_latexに名前のリストも指定できます。
名前が割り当てられなかった要素については、通常の命名挙動になります。
subscript_styles は、添字の実際の表示方法を変更します。たとえば、上付き添字、括弧、角括弧による表示に切り替えることができます。
多次元配列型は、スタイルを一つだけ指定した場合、全添字に適応されますが、スタイルのリストを渡すことで、添字の位置ごとに異なるスタイルを設定できます。
problem = jm.Problem("problem")
N = problem.Natural("N")
x = problem.BinaryVar("x", shape=(N, N), subscript_styles=jm.SubscriptStyle.BRACKET)
y = problem.BinaryVar(
"y", shape=(N, N), subscript_styles=[jm.SubscriptStyle.SUP, jm.SubscriptStyle.SUB]
)
problem += x[0, 1] + y[0, 1]
problem
バグ修正#
バグ修正 1:ランダムインスタンス生成にカテゴリーラベルの情報が含まれるように#
ランダムインスタンス生成で得られたデータセットにカテゴリーラベルそのものの定義が含まれていなかった問題を修正しました。
これまでは以下の dataset には C が含まれておらず eval に失敗していましたが、本リリースからは問題なく実行されるようになりました。
import jijmodeling as jm
@jm.Problem.define("problem")
def problem(problem: jm.DecoratedProblem):
C = problem.CategoryLabel()
a = problem.Float(dict_keys=C)
x = problem.BinaryVar(dict_keys=C)
problem += (a * x).sum()
dataset = problem.generate_random_dataset(
seed=42,
options={"C": {"keys": ["A", "B", "C"]}}
)
dataset
{'C': ['A', 'B', 'C'],
'a': {'A': -4.161370289401178,
'B': -1.210197493373315,
'C': 1.800434110281392}}
problem.eval(dataset)
Instance(raw=<builtins.Instance object at 0x7c6bad0c00>, annotations={})
空リスト・空配列をプレースホルダーとして入力できるように#
これまで、1 次元配列に対して空の配列やリストをインスタンスデータとして入力することはできましたが、2 次元以上の配列に対してはコンパイル時にエラーになっていました。
今回のリリースから、配列のシェイプが空データを許容する場合、いずれかの不定な軸の次元が 0 であるような多次元配列として解釈されるようになりました。
@jm.Problem.define("p")
def problem(problem: jm.DecoratedProblem):
cuts = problem.Float(ndim=2)
problem.eval({"cuts": []}) # これまではエラーだったが、$0 \times 0$ 配列として解釈される
Instance(raw=<builtins.Instance object at 0x7c6bad2700>, annotations={})
fixed_variables を指定すると制約検出でエラーになる問題の修正#
One-hot 制約や SOS1 制約に含まれる決定変数の値を fixed_variables で固定すると、制約検出が有効な場合に内部エラー E-CE0007 が発生することがあった問題を修正しました。
以下のように、一部の決定変数の値を固定した問題も、制約検出を有効にしたままコンパイルできるようになりました。
import jijmodeling as jm
problem = jm.Problem("one-hot with fixed variables")
x = problem.BinaryVar("x", shape=(3,))
problem += problem.Constraint("onehot", x[0] + x[1] + x[2] == 1)
problem.eval({}, fixed_variables={"x": {0: 0}})
Instance(raw=<builtins.Instance object at 0x7c6bad1b00>, annotations={})
また、One-hot 制約のすべての変数を 0 に固定するなど、固定値によってこれらの制約を満たせなくなる場合には、制約名と理由を示すエラー E-CE0022 が発生するようになりました。