{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# ommx.v1.Solution\n",
"\n",
"OMMXには数理モデルの解を表す構造体がいくつか存在します\n",
"\n",
"| データ構造 | 説明 |\n",
"| --- | --- |\n",
"| [`ommx.v1.State`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/solution_pb2/index.html#ommx.v1.solution_pb2.State) | 決定変数のIDに対して解の値を保持したもの。最も単純な解の表現。 |\n",
"| [`ommx.v1.Solution`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Solution) | 人間が読む事を想定した解の表現。決定変数の値やそれによる制約条件の評価値に加えて、[`ommx.v1.Instance`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Instance)に追加された決定変数や制約条件のメタデータも保持している。 |\n",
"\n",
"多くのソルバーは数理モデルを解く事を目的としたソフトウェアなので `ommx.v1.State` に相当する最小限の情報を返しますが、OMMXではユーザーが最適化の結果を容易に確認できる形である `ommx.v1.Solution` を中心として扱います。\n",
"\n",
"`ommx.v1.Solution` は `ommx.v1.Instance.evaluate` メソッドに `ommx.v1.State` あるいは相当する `dict[int, float]` を渡す事で生成されます。前節で見た簡単な最適化問題\n",
"\n",
"$$\n",
"\\begin{align}\n",
"\\max \\quad & x + y \\\\\n",
"\\text{subject to} \\quad & x y = 0 \\\\\n",
"& x, y \\in \\{0, 1\\}\n",
"\\end{align}\n",
"$$\n",
"\n",
"をここでも考えましょう。これは明らかに実行可能解 $x = 1, y = 0$ を持ちます。"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from ommx.v1 import Instance, DecisionVariable\n",
"\n",
"# Create a simple instance\n",
"x = DecisionVariable.binary(1, name='x')\n",
"y = DecisionVariable.binary(2, name='y')\n",
"\n",
"instance = Instance.from_components(\n",
" decision_variables=[x, y],\n",
" objective=x + y,\n",
" constraints=[x * y == 0],\n",
" sense=Instance.MAXIMIZE\n",
")\n",
"\n",
"# Create a solution\n",
"solution = instance.evaluate({1: 1, 2: 0}) # x=1, y=0"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"生成された `ommx.v1.Soluiton` は `ommx.v1.Instance` からほとんどの情報を引き継ぎます。まず決定変数を見てみましょう。"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" kind | \n",
" lower | \n",
" upper | \n",
" name | \n",
" subscripts | \n",
" description | \n",
" substituted_value | \n",
" value | \n",
"
\n",
" \n",
" id | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" 1 | \n",
" binary | \n",
" 0.0 | \n",
" 1.0 | \n",
" x | \n",
" [] | \n",
" <NA> | \n",
" <NA> | \n",
" 1.0 | \n",
"
\n",
" \n",
" 2 | \n",
" binary | \n",
" 0.0 | \n",
" 1.0 | \n",
" y | \n",
" [] | \n",
" <NA> | \n",
" <NA> | \n",
" 0.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" kind lower upper name subscripts description substituted_value value\n",
"id \n",
"1 binary 0.0 1.0 x [] 1.0\n",
"2 binary 0.0 1.0 y [] 0.0"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"solution.decision_variables"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"必須であるIDと `kind`, `lower`, `upper` に加えて `name` などのメタデータも引き継ぎます。加えて `value` には `evaluate` で代入された値が追加されます。同様に制約条件にも `value` として評価値が追加されます。"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" equality | \n",
" value | \n",
" used_ids | \n",
" name | \n",
" subscripts | \n",
" description | \n",
" dual_variable | \n",
" removed_reason | \n",
"
\n",
" \n",
" id | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" =0 | \n",
" 0.0 | \n",
" {1, 2} | \n",
" <NA> | \n",
" [] | \n",
" <NA> | \n",
" <NA> | \n",
" <NA> | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" equality value used_ids name subscripts description dual_variable \\\n",
"id \n",
"0 =0 0.0 {1, 2} [] \n",
"\n",
" removed_reason \n",
"id \n",
"0 "
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"solution.constraints"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`objective` プロパティには目的関数の値が、`feasible` プロパティには制約条件を満たしているかどうかが格納されます。"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"solution.objective=1.0, solution.feasible=True\n"
]
}
],
"source": [
"print(f\"{solution.objective=}, {solution.feasible=}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$x = 1, y = 0$ の時 $xy = 0$ なので制約条件は全て守られているので `feasible` は `True` になります。また目的関数の値は $x + y = 1$ になります。\n",
"\n",
"では実行可能解でないケース、$x = 1, y = 1$ の時はどうなるでしょうか?"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"solution11.objective=2.0, solution11.feasible=False\n"
]
}
],
"source": [
"solution11 = instance.evaluate({1: 1, 2: 1}) # x=1, y=1\n",
"print(f\"{solution11.objective=}, {solution11.feasible=}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`feasible = False` となっており、実行可能解でない事が確認できます。"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}