---
jupytext:
  text_representation:
    extension: .md
    format_name: myst
    format_version: 0.13
    jupytext_version: 1.19.1
kernelspec:
  display_name: Python 3 (ipykernel)
  language: python
  name: python3
---

# ommx.v1.Solution

OMMX has several structures that represent the solution of mathematical models.

| Data Structure | Description |
| --- | --- |
| [`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. |
| [`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). |

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.

`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:

$$
\begin{aligned}
\max \quad & x + y \\
\text{subject to} \quad & x y  = 0 \\
& x, y \in \{0, 1\}
\end{aligned}
$$

It is clear that this has a feasible solution $x = 1, y = 0$.

```{code-cell} ipython3
from ommx.v1 import Instance, DecisionVariable

# Create a simple instance
x = DecisionVariable.binary(1, name='x')
y = DecisionVariable.binary(2, name='y')

instance = Instance.from_components(
    decision_variables=[x, y],
    objective=x + y,
    constraints={0: x * y == 0},
    sense=Instance.MAXIMIZE
)

# Create a solution
solution = instance.evaluate({1: 1, 2: 0})  # x=1, y=0
```

The generated `ommx.v1.Solution` inherits most of the information from the `ommx.v1.Instance`. Let's first look at the decision variables.

```{code-cell} ipython3
solution.decision_variables_df
```

In addition to the required attributes—ID, `kind`, `lower`, and `upper`—it also inherits metadata such as `name`. Additionally, the `value` assigned in `evaluate` is stored. Similarly, the evaluation value is added to the constraints as `value`.

```{code-cell} ipython3
solution.constraints_df
```

The `objective` property contains the value of the objective function, and the `feasible` property contains whether the constraints are satisfied.

```{code-cell} ipython3
print(f"{solution.objective=}, {solution.feasible=}")
```

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$.

What happens in the case of an infeasible solution, $x = 1, y = 1$?

```{code-cell} ipython3
solution11 = instance.evaluate({1: 1, 2: 1})  # x=1, y=1
print(f"{solution11.objective=}, {solution11.feasible=}")
```

`feasible = False` indicates that it is an infeasible solution.
