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

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

| Data Structure | Description |
| --- | --- |
| {class}`~ommx.State` | Holds the solution value for the decision variable ID. The simplest representation of a solution. |
| {class}`~ommx.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 {class}`~ommx.Instance`. |

Most solvers are software designed to solve mathematical models, so they return minimal information equivalent to `ommx.State`, but OMMX mainly handles `ommx.Solution`, which allows users to easily check the optimization results.

`ommx.Solution` is generated by passing `ommx.State` or equivalent `dict[int, float]` to the `ommx.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 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.Solution` inherits most of the information from the `ommx.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.
