{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# ommx.v1.Solution\n",
"\n",
"OMMX has several structures that represent the solution of mathematical models.\n",
"\n",
"| Data Structure | Description |\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) | Holds the solution value for the decision variable ID. The simplest representation of a solution. |\n",
"| [`ommx.v1.Solution`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Solution) | A representation of the solution intended to be human-readable. In addition to the values of the decision variables and the evaluation values of the constraints, it also holds metadata for the decision variables and constraints added to the [`ommx.v1.Instance`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Instance). |\n",
"\n",
"Most solvers are software designed to solve mathematical models, so they return minimal information equivalent to `ommx.v1.State`, but OMMX mainly handles `ommx.v1.Solution`, which allows users to easily check the optimization results.\n",
"\n",
"`ommx.v1.Solution` is generated by passing `ommx.v1.State` or equivalent `dict[int, float]` to the `ommx.v1.Instance.evaluate` method. Let's consider the simple optimization problem we saw in the previous section again:\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",
"It is clear that this has a feasible solution $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": [
"The generated `ommx.v1.Solution` inherits most of the information from the `ommx.v1.Instance`. Let's first look at the decision variables."
]
},
{
"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": [
"In addition to the required attributes—ID, `kind`, `lower`, and `upper`-it also inherits metadata such as `name`. Additionally, the `value` stores which was assigned in `evaluate`. Similarly, the evaluation value is added to the constraints as `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": [
"The `objective` property contains the value of the objective function, and the `feasible` property contains whether the constraints are satisfied."
]
},
{
"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": [
"Since $xy = 0$ when $x = 1, y = 0$, all constraints are satisfied, so `feasible` is `True`. The value of the objective function is $x + y = 1$.\n",
"\n",
"What happens in the case of an infeasible solution, $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` indicates that it is an infeasible solution."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.10.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}