ommx.v1.Function#
数理最適化では目的関数や制約条件を表現するために(数学的な意味での)関数を扱う必要があります。OMMXでは特に多項式を中心に扱い、OMMX Messageには多項式を表すためのデータ構造として以下のものが存在します。
データ構造 |
説明 |
---|---|
線形の関数。決定変数のIDとその係数のペアを持つ |
|
二次の関数。決定変数のIDのペアとその係数のペアを持つ |
|
多項式。決定変数のIDの組とその係数のペアを持つ |
|
上記のいずれかあるいは定数 |
ommx.v1.Function の作成#
Python SDKでこれらのデータ構造を作る場合、大きく分けて二つの方法があります。まずひとつ目は、各データ構造のコンストラクタを直接呼び出す方法です。たとえば、次のようにしてommx.v1.Linear
を作ることができます。
from ommx.v1 import Linear
linear = Linear(terms={1: 1.0, 2: 2.0}, constant=3.0)
print(linear)
Linear(x1 + 2*x2 + 3)
このように決定変数はIDで識別され、係数は実数で表されます。係数や定数値にアクセスするには terms
constant
プロパティを使います。
print(f"{linear.terms=}, {linear.constant=}")
linear.terms={(1,): 1.0, (2,): 2.0, (): 3.0}, linear.constant=3.0
もう一つの方法は ommx.v1.DecisionVariable
から作る方法です。ommx.v1.DecisionVariable
は決定変数のIDを持つだけのデータ構造です。ommx.v1.Linear
などの多項式を作る際には、ommx.v1.DecisionVariable
を使って決定変数を作り、それを使って多項式を作ることができます。
from ommx.v1 import DecisionVariable
x = DecisionVariable.binary(1, name="x")
y = DecisionVariable.binary(2, name="y")
linear = x + 2.0 * y + 3.0
print(linear)
Linear(x1 + 2*x2 + 3)
このとき多項式のデータ型は決定変数に関するID以外の情報を保持しないことに注意してください。上の例で言えば x
や y
といった DecisionVariable.binary
に渡した情報は Linear
には伝わりません。この二つ目の方法はどの次数の多項式も作ることができます。
q = x * x + x * y + y * y
print(q)
Quadratic(x1*x1 + x1*x2 + x2*x2)
p = x * x * x + y * y
print(p)
Polynomial(x1*x1*x1 + x2*x2)
Linear
, Quadratic
, Polynomial
はそれぞれ固有のデータの保持方法を持っているため別のMessageになっていますが、目的関数や制約条件としてはどれを使ってもいいので、それらのいずれかあるいは定数である Function
というMessageが用意されています。
from ommx.v1 import Function
# Constant
print(Function(1.0))
# Linear
print(Function(linear))
# Quadratic
print(Function(q))
# Polynomial
print(Function(p))
Function(1)
Function(x1 + 2*x2 + 3)
Function(x1*x1 + x1*x2 + x2*x2)
Function(x1*x1*x1 + x2*x2)
決定変数の代入・部分評価#
Function
及び他の多項式は決定変数の値を代入する evaluate
メソッドを持ちます。例えば上で作った線形関数 \(x_1 + 2x_2 + 3\) に \(x_1 = 1, x_2 = 0\) を代入すると \(1 + 2 \times 0 + 3 = 4\) となります。
value, used_id = linear.evaluate({1: 1, 2: 0})
print(f"{value=}, {used_id=}")
value=4.0, used_id={1, 2}
引数は dict[int, float]
の形式と ommx.v1.State
をサポートしています。evaluate
は評価した値に加えて使用した決定変数のIDを返します。これは最適化問題を解いて得られた解である ommx.v1.State
に対して評価を行った時にどの部分を使ったのかを知りたい場合に便利です。evaluate
は評価に必要な決定変数のIDが足りない場合はエラーを返します。
try:
linear.evaluate({1: 1})
except RuntimeError as e:
print(f"Error: {e}")
Error: Variable id (2) is not found in the solution
一部の決定変数にだけ値を代入したい場合は partial_evaluate
メソッドを使います。これは evaluate
と同じ引数を受け取りますが、値が代入されていない決定変数については評価せずにそのまま返します。
linear2, used_id = linear.partial_evaluate({1: 1})
print(f"{linear2=}, {used_id=}")
linear2=Linear(2*x2 + 4), used_id={1}
部分評価された結果は多項式になるため、元の多項式と同じ型で返されます。
係数の比較#
Function
や他の多項式型には almost_equal
関数が用意されています。これは多項式の各係数が指定された誤差で一致するかどうかを判定するための関数です。例えば \( (x + 1)^2 = x^2 + 2x + 1 \) であることを確認するには次のように書きます
xx = (x + 1) * (x + 1)
xx.almost_equal(x * x + 2 * x + 1)
True