diff --git a/docs/_static/custom.css b/docs/_static/custom.css
index 86efe0c..620daf3 100644
--- a/docs/_static/custom.css
+++ b/docs/_static/custom.css
@@ -37,19 +37,18 @@ code {
.warning { background-color: rgb(220 150 40 / 10%); }
.warning * { color: rgb(105 72 28); }
-.input_area, .output_area {
+.input_area, .output_area, .output_area img {
border-radius: 8px !important;
border-width: 0 !important;
margin: 8px 0 8px 0;
}
.output_area {
- padding: 12px;
+ padding: 4px;
background-color: hsl(227 60% 11% / 0.7) !important;
}
.output_area pre {
- //overflow: hidden;
color: #fff;
}
diff --git a/docs/benchmarks/gurobi.env b/docs/benchmarks/gurobi.env
new file mode 100644
index 0000000..f14b8b2
--- /dev/null
+++ b/docs/benchmarks/gurobi.env
@@ -0,0 +1,3 @@
+OutputFlag 0
+Threads 1
+TimeLimit 3600
diff --git a/docs/benchmarks/knapsack.ipynb b/docs/benchmarks/knapsack.ipynb
index 0836b6e..83145da 100644
--- a/docs/benchmarks/knapsack.ipynb
+++ b/docs/benchmarks/knapsack.ipynb
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
- "id": "d236e2a0",
+ "id": "ed5d6503",
"metadata": {},
"source": [
"# Multidimensional Knapsack\n",
@@ -61,21 +61,3893 @@
" \n",
"### Challenge A\n",
"\n",
- "* 250 variables, 10 constraints, fixed weights\n",
+ "* 100 variables, 10 constraints, fixed weights\n",
"* $w \\sim U(0, 1000), \\gamma \\sim U(0.95, 1.05)$\n",
"* $K = 500, u \\sim U(0, 1), \\alpha = 0.25$\n",
- "* 500 training instances, 50 test instances\n"
+ "* 512 training instances, 64 test instances\n"
]
},
{
"cell_type": "code",
- "execution_count": null,
- "id": "39be5cda",
+ "execution_count": 1,
+ "id": "8710002b",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CPU times: user 26 s, sys: 1min 6s, total: 1min 32s\n",
+ "Wall time: 16min 21s\n"
+ ]
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
"source": [
- "MultiKnapsackGenerator(\n",
- " n=randint(low=250, high=251),\n",
+ "%%time\n",
+ "%config InlineBackend.figure_formats = ['svg']\n",
+ "%matplotlib inline\n",
+ "\n",
+ "from miplearn.benchmark import run_benchmarks\n",
+ "from miplearn.problems.knapsack import MultiKnapsackGenerator\n",
+ "from scipy.stats import uniform, randint\n",
+ "\n",
+ "instances = MultiKnapsackGenerator(\n",
+ " n=randint(low=100, high=101),\n",
" m=randint(low=10, high=11),\n",
" w=uniform(loc=0.0, scale=1000.0),\n",
" K=uniform(loc=500.0, scale=0.0),\n",
@@ -83,7 +3955,13 @@
" alpha=uniform(loc=0.25, scale=0.0),\n",
" fix_w=True,\n",
" w_jitter=uniform(loc=0.95, scale=0.1),\n",
- ")"
+ ").generate(576)\n",
+ "\n",
+ "run_benchmarks(\n",
+ " train_instances = instances[:512],\n",
+ " test_instances = instances[512:],\n",
+ " n_jobs=16,\n",
+ ");"
]
}
],
diff --git a/docs/benchmarks/preliminaries.ipynb b/docs/benchmarks/preliminaries.ipynb
index 1ac7019..002c441 100644
--- a/docs/benchmarks/preliminaries.ipynb
+++ b/docs/benchmarks/preliminaries.ipynb
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
- "id": "423ee254",
+ "id": "cf77634b",
"metadata": {},
"source": [
"# Preliminaries\n",
@@ -18,11 +18,19 @@
"To illustrate the performance of `LearningSolver`, and to set a baseline for newly proposed techniques, we present in this page, for each benchmark challenge, a small set of computational results measuring the solution speed of the solver and the solution quality with default parameters. For more detailed computational studies, see [references](index.md#references). We compare three solvers:\n",
"\n",
"* **baseline:** Gurobi 9.1 with default settings (a conventional state-of-the-art MIP solver)\n",
- "* **ml-exact:** `LearningSolver` with default settings, using Gurobi 9.0 as internal MIP solver\n",
+ "* **ml-exact:** `LearningSolver` with default settings, using Gurobi as internal MIP solver\n",
"* **ml-heuristic:** Same as above, but with `mode=\"heuristic\"`\n",
"\n",
- "All experiments presented here were performed on a Linux server (Ubuntu Linux 18.04 LTS) with Intel Xeon Gold 6230s (2 processors, 40 cores, 80 threads) and 256 GB RAM (DDR4, 2933 MHz). All solvers were restricted to use 4 threads, with no time limits, and 10 instances were solved simultaneously at a time."
+ "All experiments presented here were performed on a Linux workstation (Ubuntu Linux 20.04 LTS) with AMD Ryzen 3950X (16 cores, 32 threads) and 64 GB RAM (DDR4, 3200 MHz). All solvers were restricted to use a single thread, 3600 second time limit, and 16 instances were solved simultaneously at a time."
]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4f4597c3",
+ "metadata": {},
+ "outputs": [],
+ "source": []
}
],
"metadata": {
diff --git a/docs/benchmarks/stab.ipynb b/docs/benchmarks/stab.ipynb
index ed7f4a2..4937b32 100644
--- a/docs/benchmarks/stab.ipynb
+++ b/docs/benchmarks/stab.ipynb
@@ -2,14 +2,14 @@
"cells": [
{
"cell_type": "markdown",
- "id": "23083bd9",
+ "id": "e4a9abff",
"metadata": {},
"source": [
"# Maximum Weight Stable Set\n",
"\n",
"## Problem definition\n",
"\n",
- "Given a simple undirected graph $G=(V,E)$ and weights $w \\in \\mathbb{R}^V$, the problem is to find a stable set $S \\subseteq V$ that maximizes $ \\sum_{v \\in V} w_v$. We recall that a subset $S \\subseteq V$ is a *stable set* if no two vertices of $S$ are adjacent. This is one of Karp's 21 NP-complete problems.\n",
+ "Given a simple undirected graph $G=(V,E)$ and weights $w \\in \\mathbb{R}^V$, the problem is to find a stable set $S \\subseteq V$ that maximizes $\\sum_{v \\in V} w_v$. We recall that a subset $S \\subseteq V$ is a *stable set* if no two vertices of $S$ are adjacent. This is one of Karp's 21 NP-complete problems.\n",
"\n",
"## Random instance generator\n",
"\n",
@@ -18,24 +18,3940 @@
"## Challenge A\n",
"\n",
"* Fixed random Erdős-Rényi graph $G_{n,p}$ with $n=200$ and $p=5\\%$\n",
- "* Random vertex weights $w_v \\sim U(100, 150)$\n",
- "* 500 training instances, 50 test instances"
+ "* Random vertex weights $w_v \\sim U(100, 125)$\n",
+ "* 512 training instances, 64 test instances"
]
},
{
"cell_type": "code",
- "execution_count": null,
- "id": "207c7846",
+ "execution_count": 1,
+ "id": "f99c2c79",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CPU times: user 43.6 s, sys: 1min 42s, total: 2min 25s\n",
+ "Wall time: 1min 56s\n"
+ ]
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
"source": [
- "MaxWeightStableSetGenerator(\n",
- " w=uniform(loc=100., scale=50.),\n",
- " n=randint(low=200, high=201),\n",
+ "%%time\n",
+ "%config InlineBackend.figure_formats = ['svg']\n",
+ "%matplotlib inline\n",
+ "\n",
+ "from miplearn.benchmark import run_benchmarks\n",
+ "from miplearn.problems.stab import MaxWeightStableSetGenerator\n",
+ "from scipy.stats import uniform, randint\n",
+ "\n",
+ "instances = MaxWeightStableSetGenerator(\n",
+ " w=uniform(loc=100.0, scale=25.0),\n",
+ " n=randint(low=150, high=151),\n",
" p=uniform(loc=0.05, scale=0.0),\n",
" fix_graph=True,\n",
- ")"
+ ").generate(576)\n",
+ "\n",
+ "run_benchmarks(\n",
+ " train_instances = instances[:512],\n",
+ " test_instances = instances[512:],\n",
+ " n_jobs=16,\n",
+ ");"
]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6973a585",
+ "metadata": {},
+ "outputs": [],
+ "source": []
}
],
"metadata": {
diff --git a/docs/benchmarks/tsp.ipynb b/docs/benchmarks/tsp.ipynb
index f6455d3..7ab7271 100644
--- a/docs/benchmarks/tsp.ipynb
+++ b/docs/benchmarks/tsp.ipynb
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
- "id": "2f39414b",
+ "id": "bf2bdd0f",
"metadata": {},
"source": [
"# Traveling Salesman\n",
@@ -16,7 +16,7 @@
"\n",
"### Random problem generator\n",
"\n",
- "The class `TravelingSalesmanGenerator` can be used to generate random instances of this\n",
+ "The class `miplearn.problems.tsp.TravelingSalesmanGenerator` can be used to generate random instances of this\n",
"problem. Initially, the generator creates $n$ cities $(x_1,y_1),\\ldots,(x_n,y_n) \\in \\mathbb{R}^2$,\n",
"where $n, x_i$ and $y_i$ are sampled independently from the provided probability distributions `n`,\n",
"`x` and `y`. For each pair of cities $(i,j)$, the distance $d_{i,j}$ between them is set to:\n",
@@ -26,42 +26,3849 @@
"where $\\gamma_{i,j}$ is sampled from the distribution `gamma`.\n",
"\n",
"If `fix_cities=True` is provided, the list of cities is kept the same for all generated instances.\n",
- "The $gamma$ values, and therefore also the distances, are still different.\n",
+ "The $\\gamma$ values, and therefore also the distances, are still different.\n",
"\n",
"By default, all distances $d_{i,j}$ are rounded to the nearest integer. If `round=False`\n",
"is provided, this rounding will be disabled.\n",
"\n",
"### Challenge A\n",
"\n",
- "* Fixed list of 350 cities in the $[0, 1000]^2$ square\n",
+ "* Fixed list of 100 cities in the $[0, 1000]^2$ square\n",
"* $\\gamma_{i,j} \\sim U(0.95, 1.05)$\n",
- "* 500 training instances, 50 test instances"
+ "* 512 training instances, 64 test instances"
]
},
{
"cell_type": "code",
- "execution_count": null,
- "id": "6b2c4ff9",
+ "execution_count": 1,
+ "id": "f7f4490f",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CPU times: user 5min 13s, sys: 4min 46s, total: 10min\n",
+ "Wall time: 32min 2s\n"
+ ]
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
"source": [
- "TravelingSalesmanGenerator(\n",
+ "%%time\n",
+ "%config InlineBackend.figure_formats = ['svg']\n",
+ "%matplotlib inline\n",
+ "\n",
+ "from miplearn.benchmark import run_benchmarks\n",
+ "from miplearn.problems.tsp import TravelingSalesmanGenerator\n",
+ "from scipy.stats import uniform, randint\n",
+ "\n",
+ "instances = TravelingSalesmanGenerator(\n",
" x=uniform(loc=0.0, scale=1000.0),\n",
" y=uniform(loc=0.0, scale=1000.0),\n",
- " n=randint(low=350, high=351),\n",
+ " n=randint(low=100, high=101),\n",
" gamma=uniform(loc=0.95, scale=0.1),\n",
" fix_cities=True,\n",
" round=True,\n",
- ")"
+ ").generate(576)\n",
+ "\n",
+ "run_benchmarks(\n",
+ " train_instances = instances[:512],\n",
+ " test_instances = instances[512:],\n",
+ " n_jobs=16,\n",
+ ");"
]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "cc125860",
- "metadata": {},
- "outputs": [],
- "source": []
}
],
"metadata": {
diff --git a/docs/benchmarks/uc.ipynb b/docs/benchmarks/uc.ipynb
index 23bc2f2..ec7ae89 100644
--- a/docs/benchmarks/uc.ipynb
+++ b/docs/benchmarks/uc.ipynb
@@ -2,13 +2,64 @@
"cells": [
{
"cell_type": "markdown",
- "id": "ed7d4bdc",
+ "id": "ed679fe1",
"metadata": {},
"source": [
"# Unit Commitment\n",
"\n",
"TODO"
]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "21cf82e4",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ ".\n",
+ "├── .ipynb_checkpoints\n",
+ "│ ├── facility-checkpoint.ipynb\n",
+ "│ ├── gurobi-checkpoint.env\n",
+ "│ ├── knapsack-checkpoint.ipynb\n",
+ "│ ├── preliminaries-checkpoint.ipynb\n",
+ "│ ├── stab-checkpoint.ipynb\n",
+ "│ ├── tsp-checkpoint.ipynb\n",
+ "│ └── uc-checkpoint.ipynb\n",
+ "├── facility.ipynb\n",
+ "├── gurobi.env\n",
+ "├── knapsack.ipynb\n",
+ "├── preliminaries.ipynb\n",
+ "├── stab.ipynb\n",
+ "├── tsp.ipynb\n",
+ "└── uc.ipynb\n",
+ "\n",
+ "1 directory, 14 files\n"
+ ]
+ }
+ ],
+ "source": [
+ ";tree -a"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "dd98c833",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "886adaec",
+ "metadata": {},
+ "outputs": [],
+ "source": []
}
],
"metadata": {
diff --git a/docs/index.md b/docs/index.md
index bb8ccc9..6876509 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -59,7 +59,8 @@ numbered: true
## Acknowledgments
-* Based upon work supported by **Laboratory Directed Research and Development** (LDRD) funding from Argonne National Laboratory, provided by the Director, Office of Science, of the U.S. Department of Energy under Contract No. DE-AC02-06CH11357, and the **U.S. Department of Energy Advanced Grid Modeling Program** under Grant DE-OE0000875.
+* Based upon work supported by U.S. Department of Energy **Advanced Grid Modeling Program** under Grant DE-OE0000875.
+* Based upon work supported by **Laboratory Directed Research and Development** (LDRD) funding from Argonne National Laboratory, provided by the Director, Office of Science, of the U.S. Department of Energy under Contract No. DE-AC02-06CH11357
## References
diff --git a/docs/jump-tutorials/getting-started.ipynb b/docs/jump-tutorials/getting-started.ipynb
index a023994..b3aa483 100644
--- a/docs/jump-tutorials/getting-started.ipynb
+++ b/docs/jump-tutorials/getting-started.ipynb
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
- "id": "546635ee",
+ "id": "b54271ba",
"metadata": {},
"source": [
"# Getting started with MIPLearn\n",
@@ -32,7 +32,7 @@
},
{
"cell_type": "markdown",
- "id": "8b97258c",
+ "id": "6135092d",
"metadata": {},
"source": [
"## Installation\n",
@@ -48,7 +48,7 @@
{
"cell_type": "code",
"execution_count": 1,
- "id": "2dbeacbc",
+ "id": "c549d632",
"metadata": {},
"outputs": [
{
@@ -71,7 +71,7 @@
},
{
"cell_type": "markdown",
- "id": "b2f449e7",
+ "id": "bc99f8c1",
"metadata": {},
"source": [
"In addition to MIPLearn itself, we will also install a few other packages that are required for this tutorial:\n",
@@ -85,7 +85,7 @@
{
"cell_type": "code",
"execution_count": 2,
- "id": "68f99568",
+ "id": "d068ed52",
"metadata": {},
"outputs": [
{
@@ -110,7 +110,7 @@
},
{
"cell_type": "markdown",
- "id": "51e09fc9",
+ "id": "9689bce5",
"metadata": {},
"source": [
"
\n",
@@ -124,7 +124,7 @@
},
{
"cell_type": "markdown",
- "id": "18c300c4",
+ "id": "9801f40d",
"metadata": {},
"source": [
"## Modeling a simple optimization problem\n",
@@ -160,7 +160,7 @@
{
"cell_type": "code",
"execution_count": 3,
- "id": "b12d6483",
+ "id": "8ae84f9d",
"metadata": {},
"outputs": [],
"source": [
@@ -175,7 +175,7 @@
},
{
"cell_type": "markdown",
- "id": "55cdb64b",
+ "id": "3d59466c",
"metadata": {},
"source": [
"Next, we create a function that converts this data structure into a concrete JuMP model. For more details on the JuMP syntax, see [the official JuMP documentation](https://jump.dev/JuMP.jl/stable/)."
@@ -184,7 +184,7 @@
{
"cell_type": "code",
"execution_count": 4,
- "id": "1e38a266",
+ "id": "e07e3633",
"metadata": {},
"outputs": [],
"source": [
@@ -213,7 +213,7 @@
},
{
"cell_type": "markdown",
- "id": "d28c4d5a",
+ "id": "6e92b1d8",
"metadata": {},
"source": [
"At this point, we can already use JuMP and any mixed-integer linear programming solver to find optimal solutions to any instance of this problem. To illustrate this, let us solve a small instance with three generators, using SCIP:"
@@ -222,7 +222,7 @@
{
"cell_type": "code",
"execution_count": 5,
- "id": "9ff9f05c",
+ "id": "e2b828da",
"metadata": {},
"outputs": [
{
@@ -260,7 +260,7 @@
},
{
"cell_type": "markdown",
- "id": "345de591",
+ "id": "92e27701",
"metadata": {},
"source": [
"Running the code above, we found that the optimal solution for our small problem instance costs \\$1320. It is achieve by keeping generators 2 and 3 online and producing, respectively, 60 MW and 40 MW of power."
@@ -268,7 +268,7 @@
},
{
"cell_type": "markdown",
- "id": "eb8904ef",
+ "id": "06e538e5",
"metadata": {},
"source": [
"## Generating training data\n",
@@ -283,7 +283,7 @@
{
"cell_type": "code",
"execution_count": 6,
- "id": "7298bb0d",
+ "id": "859e0e29",
"metadata": {},
"outputs": [],
"source": [
@@ -311,7 +311,7 @@
},
{
"cell_type": "markdown",
- "id": "c1feed43",
+ "id": "92cb1931",
"metadata": {},
"source": [
"In this example, for simplicity, only the demands change from one instance to the next. We could also have made the prices and the production limits random. The more randomization we have in the training data, however, the more challenging it is for the machine learning models to learn solution patterns.\n",
@@ -322,7 +322,7 @@
{
"cell_type": "code",
"execution_count": 7,
- "id": "61d43994",
+ "id": "cf7d09ba",
"metadata": {},
"outputs": [],
"source": [
@@ -333,7 +333,7 @@
},
{
"cell_type": "markdown",
- "id": "3fdeb8cd",
+ "id": "8a03a93d",
"metadata": {},
"source": [
"Next, we write these data structures to individual files. MIPLearn uses files during the training process because, for large-scale optimization problems, it is often impractical to hold the entire training data, as well as the concrete JuMP models, in memory. Files also make it much easier to solve multiple instances simultaneously, potentially even on multiple machines. We will cover parallel and distributed computing in a future tutorial.\n",
@@ -344,7 +344,7 @@
{
"cell_type": "code",
"execution_count": 8,
- "id": "31b48701",
+ "id": "2433ed6f",
"metadata": {},
"outputs": [],
"source": [
@@ -359,7 +359,7 @@
},
{
"cell_type": "markdown",
- "id": "5cecea59",
+ "id": "de0861c2",
"metadata": {},
"source": [
"Finally, we use `MIPLearn.LearningSolver` and `MIPLearn.solve!` to solve all the training instances. `LearningSolver` is the main component provided by MIPLearn, which integrates MIP solvers and ML. The `solve!` function can be used to solve either one or multiple instances, and requires: (i) the list of files containing the training data; and (ii) the function that converts the data structure into a concrete JuMP model:"
@@ -368,7 +368,7 @@
{
"cell_type": "code",
"execution_count": 9,
- "id": "60732af0",
+ "id": "bd7432e7",
"metadata": {},
"outputs": [
{
@@ -394,7 +394,7 @@
},
{
"cell_type": "markdown",
- "id": "bbc7ad82",
+ "id": "ee2a0bac",
"metadata": {},
"source": [
"The macro `@time` shows us how long did the code take to run. We can see that SCIP was able to solve all training instances in about 2 minutes. The solutions, and other useful training data, are stored by MIPLearn in `.h5` files, stored side-by-side with the original `.jld2` files."
@@ -402,7 +402,7 @@
},
{
"cell_type": "markdown",
- "id": "73379180",
+ "id": "f14f08f3",
"metadata": {},
"source": [
"## Solving new instances\n",
@@ -413,7 +413,7 @@
{
"cell_type": "code",
"execution_count": 10,
- "id": "e045d644",
+ "id": "fd8161d0",
"metadata": {},
"outputs": [
{
@@ -432,7 +432,7 @@
},
{
"cell_type": "markdown",
- "id": "d8de7b26",
+ "id": "cf0ed97d",
"metadata": {},
"source": [
"The trained MIP solver was able to solve all test instances in about 6 seconds. To see that ML is being helpful here, let us repeat the code above, but remove the `fit!` line:"
@@ -441,7 +441,7 @@
{
"cell_type": "code",
"execution_count": 11,
- "id": "cf2a989e",
+ "id": "d0812fbf",
"metadata": {},
"outputs": [
{
@@ -459,7 +459,7 @@
},
{
"cell_type": "markdown",
- "id": "e100b25d",
+ "id": "ca64c7ca",
"metadata": {},
"source": [
"Without the help of the ML models, SCIP took around 10 seconds to solve the same test instances.\n",
@@ -473,7 +473,7 @@
},
{
"cell_type": "markdown",
- "id": "af451e87",
+ "id": "a80dc6a5",
"metadata": {},
"source": [
"## Understanding the acceleration\n",
@@ -484,7 +484,7 @@
{
"cell_type": "code",
"execution_count": 12,
- "id": "0c675452",
+ "id": "e5ec48e6",
"metadata": {},
"outputs": [
{
@@ -553,7 +553,7 @@
},
{
"cell_type": "markdown",
- "id": "ff0b6858",
+ "id": "714805e0",
"metadata": {},
"source": [
"The log above is quite complicated if you have never seen it before, but the important line is the one starting with `feasible solution found [...] objective value 1.705169e+07`. This line indicates that MIPLearn was able to construct a warm start with value `1.705169e+07`. Using this warm start, SCIP then used the branch-and-cut method to either prove its optimality or to find an even better solution. Very quickly, however, SCIP proved that the solution produced by MIPLearn was indeed optimal. It was able to do this without generating a single cutting plane or running any other heuristics; it could tell the optimality by the root LP relaxation alone, which was very fast. \n",
@@ -564,7 +564,7 @@
{
"cell_type": "code",
"execution_count": 13,
- "id": "1aa9230e",
+ "id": "7f1da1e6",
"metadata": {},
"outputs": [
{
@@ -650,7 +650,7 @@
},
{
"cell_type": "markdown",
- "id": "9417bb85",
+ "id": "033da453",
"metadata": {},
"source": [
"In this log file, notice how the previous line about warm starts is missing. Since no warm starts were provided, SCIP had to find an initial solution using its own internal heuristics, which are not specifically tailored for this problem. The initial solution found by SCIP's heuristics has value `2.335200e+07`, which is significantly worse than the one constructed by MIPLearn. SCIP then proceeded to improve this solution, by generating cutting planes and repeatedly running additional primal heuristics. In the end, it was able to find the optimal solution, as expected, but it took longer.\n",
@@ -660,7 +660,7 @@
},
{
"cell_type": "markdown",
- "id": "ab9c1ff4",
+ "id": "76510d4a",
"metadata": {},
"source": [
"## Accessing the solution\n",
@@ -673,7 +673,7 @@
{
"cell_type": "code",
"execution_count": 14,
- "id": "79759e87",
+ "id": "49fe62d5",
"metadata": {},
"outputs": [
{
@@ -705,7 +705,7 @@
},
{
"cell_type": "markdown",
- "id": "b096dcf9",
+ "id": "9414f027",
"metadata": {},
"source": [
"We can then solve this model as before, with `MIPLearn.solve!`:"
@@ -714,7 +714,7 @@
{
"cell_type": "code",
"execution_count": 15,
- "id": "1b668c12",
+ "id": "4b15a28d",
"metadata": {},
"outputs": [
{