{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# ommx.v1.Instance\n",
"\n",
"[`ommx.v1.Instance`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Instance) is a data structure for describing the optimization problem itself (mathematical model). It consists of the following components:\n",
"\n",
"- Decision variables ([`decision_variables`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Instance.decision_variables))\n",
"- Objective function ([`objective`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Instance.objective))\n",
"- Constraints ([`constraints`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Instance.constraints))\n",
"- Maximization/Minimization ([`sense`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Instance.sense))\n",
"\n",
"For example, let's consider a simple optimization problem:\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",
"The corresponding `ommx.v1.Instance` is as follows."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from ommx.v1 import Instance, DecisionVariable\n",
"\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",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Each of these components has a corresponding property. The objective function is converted into the form of [`ommx.v1.Function`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Function), as explained in the previous section."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Function(x1 + x2)"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"instance.objective"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`sense` is set to `Instance.MAXIMIZE` for maximization problems or `Instance.MINIMIZE` for minimization problems."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"instance.sense == Instance.MAXIMIZE"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Decision Variables\n",
"\n",
"Decision variables and constraints can be obtained in the form of [`pandas.DataFrame`](https://pandas.pydata.org/pandas-docs/stable/reference/frame.html)."
]
},
{
"cell_type": "code",
"execution_count": 4,
"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",
"
\n",
" \n",
" id | \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",
"
\n",
" \n",
" 2 | \n",
" binary | \n",
" 0.0 | \n",
" 1.0 | \n",
" y | \n",
" [] | \n",
" <NA> | \n",
" <NA> | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" kind lower upper name subscripts description substituted_value\n",
"id \n",
"1 binary 0.0 1.0 x [] \n",
"2 binary 0.0 1.0 y [] "
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"instance.decision_variables"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, `kind`, `lower`, and `upper` are essential information for the mathematical model.\n",
"\n",
"- `kind` specifies the type of decision variable, which can be Binary, Integer, Continuous, SemiInteger, or SemiContinuous.\n",
"- `lower` and `upper` are the lower and upper bounds of the decision variable. For Binary variables, this range is $[0, 1]$.\n",
"\n",
"Additionally, OMMX is designed to handle metadata that may be needed when integrating mathematical optimization into practical data analysis. While this metadata does not affect the mathematical model itself, it is useful for data analysis and visualization.\n",
"\n",
"- `name` is a human-readable name for the decision variable. In OMMX, decision variables are always identified by ID, so this `name` may be duplicated. It is intended to be used in combination with `subscripts`, which is described later.\n",
"- `description` is a more detailed explanation of the decision variable.\n",
"- When dealing with many mathematical optimization problems, decision variables are often handled as multidimensional arrays. For example, it is common to consider constraints with subscripts like $x_i + y_i \\leq 1, \\forall i \\in [1, N]$. In this case, `x` and `y` are the names of the decision variables, so they are stored in `name`, and the part corresponding to $i$ is stored in `subscripts`. `subscripts` is a list of integers, but if the subscript cannot be represented as an integer, there is a `parameters` property that allows storage in the form of `dict[str, str]`.\n",
"\n",
"If you need a list of [`ommx.v1.DecisionVariable`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.DecisionVariable) directly, you can use the [`get_decision_variables`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Instance.get_constraints) method."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"v.id=1, v.name='x'\n",
"v.id=2, v.name='y'\n"
]
}
],
"source": [
"for v in instance.get_decision_variables():\n",
" print(f\"{v.id=}, {v.name=}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To obtain `ommx.v1.DecisionVariable` from the ID of the decision variable, you can use the [`get_decision_variable`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Instance.get_decision_variable) method."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x1.id=1, x1.name='x'\n"
]
}
],
"source": [
"x1 = instance.get_decision_variable(1)\n",
"print(f\"{x1.id=}, {x1.name=}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Constraints\n",
"Next, let's look at the constraints."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" equality | \n",
" type | \n",
" used_ids | \n",
" name | \n",
" subscripts | \n",
" description | \n",
"
\n",
" \n",
" id | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" =0 | \n",
" quadratic | \n",
" {1, 2} | \n",
" <NA> | \n",
" [] | \n",
" <NA> | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" equality type used_ids name subscripts description\n",
"id \n",
"0 =0 quadratic {1, 2} [] "
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"instance.constraints"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In OMMX, constraints are also managed by ID. This ID is independent of the decision variable ID. When you create a constraint like `x * y == 0`, a sequential number is automatically assigned. To manually set the ID, you can use the [`set_id`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Constraint.set_id) method."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"c.id=100\n"
]
}
],
"source": [
"c = (x * y == 0).set_id(100)\n",
"print(f\"{c.id=}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The essential information for constraints is `id` and `equality`. `equality` indicates whether the constraint is an equality constraint ([`Constraint.EQUAL_TO_ZERO`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Constraint.EQUAL_TO_ZERO)) or an inequality constraint ([`Constraint.LESS_THAN_OR_EQUAL_TO_ZERO`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Constraint.LESS_THAN_OR_EQUAL_TO_ZERO)). Note that constraints of the type $f(x) \\geq 0$ are treated as $-f(x) \\leq 0$.\n",
"\n",
"Constraints can also store metadata similar to decision variables. You can use `name`, `description`, `subscripts`, and `parameters`. These can be set using the [`add_name`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Constraint.add_name), [`add_description`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Constraint.add_description), [`add_subscripts`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Constraint.add_subscripts), and [`add_parameters`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Constraint.add_parameters) methods."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"c.id=100, c.name='prod-zero'\n"
]
}
],
"source": [
"c = (x * y == 0).set_id(100).add_name(\"prod-zero\")\n",
"print(f\"{c.id=}, {c.name=}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can also use the [`get_constraints`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Instance.get_constraints) method to directly obtain a list of [`ommx.v1.Constraint`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Constraint). To obtain `ommx.v1.Constraint` by its the constraint ID, use the [`get_constraint`](https://jij-inc.github.io/ommx/python/ommx/autoapi/ommx/v1/index.html#ommx.v1.Instance.get_constraint) method."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Constraint(Function(x1*x2) == 0)\n"
]
}
],
"source": [
"for c in instance.get_constraints():\n",
" print(c)"
]
}
],
"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
}